Route snapshot capture sources through one platform-neutral router

未关闭
#4,205 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
5/100
Issue 类型
重构
描述清晰度
基本清楚
活跃度
活跃
技术栈
android, ios, macos, typescript
领域
mobile, tooling

调研方向

Start with the iOS route core in packages/platform-apple/src/snapshot-route.ts and its failure policy in snapshot-route-failure-policy.ts, then the constant ports in packages/platform-apple/src/runner-runtime.ts. The ADR decision on Android's system-UI annotation and SurfaceProof must land before any code moves, and the work is blocked by #4182 on unmerged runner layers. Done means one router in packages/capture-kit serves all channels, with no constant-filled ports and the existing route tests passing unchanged.

由索引模型根据 Issue 内容生成。

描述

needs-triage

Purpose

Snapshot capture source selection must be one product rule for every platform and provider. Today the rule exists only for iOS, in packages/platform-apple/src/snapshot-route.ts, and each channel fills the route's ports with placeholders. Android, macOS, web, WebDriver and Revyl each have one hard-wired source with no shared fallback, refusal or proof vocabulary. Producer facts live in about six owners.

Current state (evidence)

  • The iOS route core: packages/platform-apple/src/snapshot-route.ts (probes, target resolution, acquisition, one fallback, identity stamping, warnings) and snapshot-route-failure-policy.ts (refusal scope).
  • The runner channel (#4182) fills the route's ports with constants: isDiscoveryPending: () => false, targetFreshness: 'cached', systemSurfacePresent: async () => 'unknown' (packages/platform-apple/src/runner-runtime.ts). The route reads them at snapshot-route.ts (discovery wait, cached-target refresh, presence probe).
  • Eligibility is split: isEligible in the route, the observe-only bypass in runner-runtime.ts bindBridgeSnapshot, and the preferredBackend verdict pin in packages/capture-kit/src/snapshot-quality-verdict.ts → stable-capture.ts.
  • Producer facts: packages/contracts/src/ios-snapshot.ts, three producer-keyed tables in packages/capture-kit/src/ios-snapshot-acquisition.ts, packages/kernel/src/snapshot.ts (SnapshotProvenance), packages/command-runtime/.../stable-capture.ts, producer switches in packages/command-runtime/src/commands/capture/runtime/snapshot.ts. Revyl's Android tree is labeled appium-source, the same name WebDriver uses for iOS.
  • Single-source platforms: Android packages/platform-android/src/snapshot-capture.ts, macOS packages/platform-apple/src/os/macos/surface-snapshot.ts, Revyl packages/provider-revyl/src/snapshot.ts, WebDriver packages/provider-webdriver/src/webdriver-ios-snapshot.ts.
  • validateTarget is duplicated in snapshot-source/adapter.ts and runner-snapshot-bridge.ts. Three fallback settlers exist: runFallback, runSurfaceFallback, captureOffRoute.
  • ADR 0004 is about 60 KB. docs/adr/FORMAT.md asks for about 8 KB.

Required behavior

  1. A new ADR, "Snapshot capture source routing", states the rule for all platforms. ADR 0004 keeps only the iOS facts (bridge, runner plan, system-surface hosts) and drops its amendment history.

  2. One platform-neutral router in packages/capture-kit owns: the source plan (plan(input) returns the source and the reason), one fallback per capture, the per-target generation circuit, the refusal table (capture scope vs generation scope), occlusion proof, identity stamping, and warnings. It imports no platform package.

  3. Each platform or provider declares its channels. A channel declares only what it has. A channel never fills a port with a constant.

    type SurfaceProof = (device, signal) =>
      Promise<'clear' | Readonly<{ occluded: string }> | 'unproven'>;
    type SourceChannel<T> = Readonly<{
      producer: SnapshotProducer;
      acquire(req: { target: T; hint; signal }): Promise<SourceOutcome>;
      resolveTarget(device, app, signal): Promise<T>;
      refreshTarget?(device, app, signal): Promise<T>;   // replaces targetFreshness
      awaitDiscovery?(device, signal): Promise<void>;    // replaces isDiscoveryPending
      proof: 'none' | SurfaceProof;                      // replaces the presence/foreground pair
      supports: { customActions: boolean; observeOnly: boolean; pinnedBackend: boolean };
    }>;
    
  4. iOS local, iOS provider (Limrun runner channel), Android, macOS and web route through the router. A single-source platform is the one-channel case.

  5. One producer registry in packages/contracts, declared with satisfies Record<SnapshotProducer, ProducerFacts> (channel, truncation, residue, quiet time, ref-namespace owner). The producer union is platform-neutral. Every other producer table derives from the registry.

  6. The refusal fixture contracts/fixtures/ios-snapshot-bridge-refusals.json (#4182) becomes the router's refusal table input for every channel that emits typed refusals.

Completion conditions

  • git grep finds no route port filled by a constant (() => false, async () => 'unknown') and no targetFreshness.
  • A layering rule fails when the router module imports a platform or provider package.
  • A repo guard fails when a producer in the registry has no production emitter.
  • A repo guard fails when an ADR cites a file path or test name that does not exist.
  • Existing route behavior tests pass unchanged against the router, for the guest and runner channels.
  • Live check: local iOS Simulator, Limrun iOS, local Android emulator. Each capture names the same producer and fallback warnings as before the change.
  • The new ADR is accepted, and ADR 0004 is under about 15 KB.

Dependencies

Blocked by: #4182 (runner-served bridge and refusal fixture), which is stacked on the unmerged Limrun runner layers (stack/limrun-native-runner).
Open question: whether Android's system-UI annotation fits the SurfaceProof port. Decide this in the ADR before code moves.

主要语言
TypeScript
星标
5.3k
派生
377
平均合并
13 小时 18 分钟
30 天内合并 PR
653

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

callstack/agent-device 的其他 Issue

查看 callstack/agent-device 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。