Skip to content

refactor(capture-kit): share the bounded provider app-log poller #2616

Description

@thymikee

refactor(capture-kit): share the bounded provider app-log poller

Purpose and evidence

PR #2112 (8dad6500a31178e4f11ec32fe981ce069aa75041) adds an approximately 200-line app-log poller with the same acquisition rollback, polling state, tail overlap, finish memoization and disposal mechanics as Limrun. Fixes to these mechanics would require coordinated provider edits.

Evidence: Doublespeed poller and packages/provider-limrun/src/app-log-poller.ts (compare the exact merged base before implementation). The PR acknowledges a shared-capture follow-up but no issue currently owns it.

Required behavior and boundary

Extract the shared polling mechanics into existing packages/capture-kit, consistent with ADR 0019. A narrow input should contain a disposable reader, backend identity, app bundle ID, output path and the existing clock/output ports. Conceptually the reader provides readLogs(appBundleId, lineLimit, signal): Promise<string> plus async disposal.

Providers keep lease/session identity, authentication, descriptor codecs, connection verification, reconnect and exact-owner admission. Adapt provider-specific cancellation at their boundary: Limrun currently settles an uncancelable read through awaitLimrunOperation. Doublespeed's poller supplies a signal; its reconnect reader forwards it, while currentAppLogReader currently drops it. Characterize both reader paths and do not silently change cancellation semantics during extraction. Do not imply abort proves the underlying request ended. Preserve current behavior for late results and rejections.

Keep the current polling interval, read timeout, line limit, recovery states, output append/marker behavior, backend selection and user-visible errors. Provider-specific cleanup messages remain explicit input or adapter-owned formatting; shared policy must not name Limrun or Doublespeed. Correcting the reader cancellation difference is separate behavior-changing work. Do not turn this into a generic provider framework or broaden it to recording/perf.

Completion and validation

  • First compare both implementations and list intentional differences. Stop if one common lifecycle would erase a provider-specific ownership or cancellation guarantee.
  • Move unchanged common tests with their code, adding characterization only for uncovered boundary differences. Cover tail overlap/rotation, mark filtering, initial output acquisition failure, read failure/recovery, timeout with a signal-ignoring reader, late rejection, finish during an in-flight read, repeated finish and disposal failure.
  • Retain provider-specific reconnect, descriptor and admission tests. Assert backend identity and existing error semantics independently of the new helper.
  • Both providers use one implementation of the shared polling lifecycle and tail algorithm; source shrinks overall after adapters, and no obsolete copy remains. No new package or provider-specific identifier in shared polling policy.
  • pnpm check:affected --run passes. Provider integration and coverage remain GitHub-authoritative; record unavailable live provider evidence rather than claiming it. Report before/after production LOC and exact provider-specific differences retained.

Dependencies and readiness

Blocked by: #2112 landing. Re-audit both pollers at that merged head before implementation. This is a follow-up, not a reason to enlarge or block #2112. #2544 is daemon capture-admission extraction and #2541 provider-device admission; neither owns this polling mechanism.

Effort: M. Risk: medium (adoption, cancellation and disposal order).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions