Skip to content

refactor: extract platform log runtime - #1701

Merged
thymikee merged 12 commits into
mainfrom
agent/platform-runtime-logs
Aug 10, 2026
Merged

refactor: extract platform log runtime#1701
thymikee merged 12 commits into
mainfrom
agent/platform-runtime-logs

Conversation

@thymikee

@thymikee thymikee commented Aug 9, 2026

Copy link
Copy Markdown
Member

Summary

Move the complete logs descriptor onto typed platform runtimes for all six families and Limrun while preserving the seven CLI plans.
Add exact-owner durable handles, fencing, recovery, fail-closed provider transport composition, and remove daemon platform/tag/provider branches.

Stacked on #1699. Part of #1696.

Validation

  • pnpm check:affected --run
  • committed-state pnpm check:layering
  • Android narrow-provider and macOS provider scenarios
  • Claude and independent adversarial lifecycle review

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-08-10 15:59 UTC

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.05 MB 2.12 MB +74.4 kB
JS gzip 665.2 kB 691.3 kB +26.1 kB
npm tarball 802.2 kB 824.9 kB +22.7 kB
npm unpacked 2.80 MB 2.87 MB +74.6 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.6 ms 29.6 ms +0.1 ms
CLI --help 69.4 ms 69.4 ms -0.1 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/src3.js +44.4 kB +13.3 kB
dist/src/session.js +14.4 kB +4.8 kB
dist/src/sdk-batch-runner.js +4.9 kB +1.5 kB
dist/src/context.js +4.8 kB +1.2 kB
dist/src/internal/daemon.js +2.3 kB -25 B

@thymikee

Copy link
Copy Markdown
Member Author

Review verdict: not ready at a108975f (mergeable/CLEAN; all reported checks green).

P1 — durable recovery leaves a stale marker that wedges logs start. reattachCleanupOnlyAppLogProcess returns missing when a valid marker’s process is already absent, but does not clear that marker. Daemon recovery terminalizes the resource, while the next start rejects the still-present marker before launch. After daemon recovery of an already-exited owned process, logs start therefore remains blocked until manual marker deletion. Safely clear that exact marker on the verified missing-process recovery path, and add a red-before production/lifecycle regression: dead owned PID → recovery terminal → next logs start launches.

Acceptance blocker — #1696 locks every bundle/package metric to ≤+3%. The exact same-runner size report is raw JS +69.8 kB over 2.05 MB (+3.40%) and gzip +23.4 kB over 664.2 kB (~+3.52%). Green Size is report-only; reduce/reconcile the increase or explicitly revise the threshold with reviewed evidence.

Evidence blocker — no exact-head live changed-route proof. The iOS/Android/macOS smoke jobs do not invoke logs; the PR body has mocked/provider scenarios only. After the fix, provide live iOS-simulator and Android-emulator evidence for open → logs start → produce/relaunch output → logs stop, plus daemon restart/dead-process recovery → second logs start succeeds.

No other source defect was confirmed in this review.

@thymikee

Copy link
Copy Markdown
Member Author

Correctness and live-evidence follow-up at exact head 2d8ca8a: the stale owned-marker wedge is fixed by clearing the verified marker when cleanup-only reattachment proves the process missing. The planted test failed before the fix with stale marker still blocks replacement and is green after it. The mandatory affected gate passed 3,930 tests with 87.78% changed-line coverage, and every GitHub check is now green. Exact-head live proof also passed on Android emulator-5554 and iOS simulator 6044A251-23C2-4584-B7DB-87A16B787757: open, logs start, marker, app relaunch, second marker, logs stop, and close; both app.log files contained both markers plus relaunch output with the expected android and ios-simulator backends. The guarded Android takeover case verified daemon and log-child PID/start-time/command identities, killed only those two exact processes, observed startup recovery remove app-log.pid and terminalize app-log.resource.json, then successfully started, marked, stopped, and closed a replacement stream. The locked size threshold remains exceeded and is intentionally unresolved here; ADR 0019 remains revise and the packaging/budget decision is tracked by #1704.

@thymikee

Copy link
Copy Markdown
Member Author

Re-review at exact head 2d8ca8a: the stale-marker P1 is fixed. Recovery now clears only the decoded owned marker after the process is confirmed missing; the new red/green regression is non-vacuous, and the production recovery route reaches this seam before terminalization. Exact-head Android emulator and iOS simulator logs evidence covers open/start/marker/relaunch/marker/stop/close, plus guarded Android daemon/process takeover and successful replacement start; all checks are green and the PR is CLEAN/mergeable.

It remains not ready solely because #1696’s locked ≤+3% package-size condition is unresolved: raw is ~+3.40% and gzip ~+3.52%; #1704 is open and has not revised or satisfied that bound. No ready label applied.

Comment thread packages/provider-limrun/src/runtime-instance.ts Fixed
@thymikee
thymikee force-pushed the agent/platform-runtime-logs branch from 2d8ca8a to 14ce1ef Compare August 10, 2026 08:14
@thymikee

Copy link
Copy Markdown
Member Author

Follow-up adversarial review found two inherited tooling P1s and one gate defect, all fixed at 14ce1ef. Apple logs doctor/CoreDevice/start foreground probes now use the closed request-scoped AppleToolHost (background durable xcrun remains on the managed-process seam); Harmony logs now prepares the Harmony toolchain, resolves configured HDC, preserves the legacy TOOL_MISSING/hint, and fails before side effects. Cancellation tests are non-vacuous: prior Apple and Harmony implementations each failed 2 cases when abort and transport errors differed; exact signal.reason is now preserved. R13 observed 4 raw-xcrun violations before the migration and 0 after. A real provider-inventory Apple logs-doctor scenario is included. The stacked diff also exceeded Node spawnSync’s 1 MiB buffer (1,063,027 bytes), so the changed-coverage wrapper now uses a bounded 16 MiB buffer with a 1.5 MiB regression fixture. Full pnpm check:affected --run is green: 3,947 tests, 87.94% changed-line coverage, package/declarations, layering, fallow, and provider integration. The separate <=+3% package-budget decision remains tracked in #1704; no CLI/docs/skills behavior changed.

@thymikee

Copy link
Copy Markdown
Member Author

Re-review at exact head 14ce1efb: no source or regression-test defects were confirmed in the scoped Apple tooling/cancellation, Harmony preflight/cancellation, or changed-coverage buffer fix. The actual CodeQL workflow and all four language-analysis jobs succeeded; the aggregate CodeQL status is stale/derived.

This remains not ready for two reasons:

  • refactor(daemon): implement ADR 0019 through the adoption checkpoint #1696 locks every package-size metric to ≤+3%; raw JS is still about +3.43% and gzip about +3.60%. ADR 0019: resolve the platform-runtime package-size checkpoint #1704 remains open and has neither satisfied nor revised that acceptance bound.
  • Exact-head live evidence is stale for the newly moved Apple logs route. The prior live run at 2d8ca8a predates moving logs doctor and simulator logs start foreground simctl work onto the scoped Apple provider. Please provide a clean 14ce1efb iOS simulator run covering open -> logs doctor -> logs start -> produce/relaunch marker -> logs stop -> close, with app.log evidence. Real Harmony HDC-path evidence is also unavailable/unrecorded; record that explicitly as a device-evidence blocker/residual risk if no target is available.

No ready label applied.

@thymikee

Copy link
Copy Markdown
Member Author

Concrete shapes for the blocking findings — reuse-focused

Follow-up to the earlier review, after a focused audit of every app-log site at stack head d73bdb4. These are the specific abstractions that resolve findings 1–3 and set up reuse for the next durable resource. Verified numbers, not estimates, unless marked.

1. Canonical device identity → packages/kernel/src/device.ts

Five of the six flagged comparators are the same 6-field identity (id, platform/family, appleOs, kind, target, iosPhysicalDeviceBackend); runtimeDeviceKey even serializes the fields in a different order than the preflight pair. Add:

export type DeviceIdentity = Readonly<{ id: string; platform: Platform; appleOs?: AppleOS;
  kind: DeviceKind; target?: DeviceTarget; iosPhysicalDeviceBackend?: 'coredevice' | 'xctest' }>;
export function deviceIdentity(device: DeviceInfo): DeviceIdentity;       // owns the `x === undefined ? {} : { x }` projection, once
export function deviceIdentityKey(identity: DeviceIdentity): string;
export function sameDeviceIdentity(left: DeviceIdentity, right: DeviceIdentity): boolean;

Collapses: durableDeviceKeyFromSelected + durableDeviceKey (app-log-start-preflight.ts), sameDurableDeviceIdentity (app-log-session-resource.ts), runtimeDeviceKey (request-runtime-binding.ts), gateway sameDeviceIdentity, plus the hand-rolled projections in createExpectedRecoveryEnvelope and deviceFromEnvelope — 9 spread-projection blocks total. Exclusion: factsMatchBindingIdentity compares RuntimeDeviceShape (no id, has providerMode) — it is a facts validator, not an identity comparator; leave it out.

2. createPidScopedAppLogRuntimeOwner(config) → contracts, beside the existing shared helpers

The codec/envelope/owner triad is already shared (createAppLogRecoveryOperations is called identically by apple, android, harmonyos, and provider-limrun). The factory completes the duplicated half. Config surface that the diff supports: family, displayName, backend, streamNoun, transports + selectTransport, pidPath: 'required' | 'optional', assertBundleIdSafe?, buildPidRequest, buildStreamCommand, doctorChecks. Android lands at ~38 lines, HarmonyOS ~28 (−250 net); the next adb/hdc-shaped family costs ~35 lines instead of ~250.

Scope limits, so this doesn't get overbuilt:

  • Apple cannot fit and must not be forced. It has no PID-scoped process model (attaches once via log stream/devicectl console, never polls a PID), backend is a function of the device (backendForAppleDevice), and simulator command construction is async (simctl get_app_container + plutil). Its 688 lines stay custom; at most lift the recovery-wiring skeleton (~10–15 lines).
  • No network-runtime factory. ~75–80% of each network file is genuinely platform-specific recovery parsing; only ~70–80 lines are shareable. Skip.
  • Don't generalize the limrun poller. The suffix/prefix-overlap diffing exists because Limrun's API re-returns the whole tail; webdriver stubs app-log entirely. It is provider-API-specific, correctly encapsulated.
  • Keep the config module behind the existing lazy boundary (logs/config.ts imported by runtime.ts, reached only via loadRuntime's dynamic import) — laziness gates stay green.
  • Preserve the current per-family behavioral deltas as explicit config, don't silently unify them: Android pidPath: 'required' vs HarmonyOS 'optional' (note: the Harmony-optional path can yield permanent cleanup-pending; unify to 'required' in a separate, stated decision), and Android's assertAndroidLogPackageSafe vs Harmony's missing bundle-id validation.

3. Delete isManagedAppLogCommand (finding 3) — no replacement needed

Write-time it self-checks a command this codebase constructed and can only false-negative (SIGKILL of our own just-spawned child + opaque marker error for any new family's command shape). Read-time it is tautological after the exact startTime + command equality check that already runs. The recorded-vs-live equality is the ownership test; keep only that.

4. Plan-declared requirements → logs-runtime-plan.ts

Add requiresAppSession: boolean per plan kind (true only for start/clear-restart) and guard once in the dispatcher. This deletes six duplicated appBundleId checks (a start request currently runs the same check three times; clear-restart also three, via startSessionAppLog). Fold the requireRuntimeBinding throw into bindDevice itself so each plan case does exactly one await bindDevice(...) — removes all 8 wrapper call sites including the 3 that discard the result (stop/mark/clear).

5. Public type surface

  • The limrun.d.ts bloat (~50 inlined AppLog* types, +15.5 kB) is not a contracts or provider-package problem: LimrunRuntime carries the daemon-internal loadRuntime(): Promise<PlatformRuntimeOwner> and the whole class is re-exported through public src/sdk/limrun.ts, so dts bundling inlines the transitive operations closure. Only platform-runtime-gateway.ts calls loadRuntime. Split the provider-module handle off the public class (constructed beside it in provider-device-runtimes.ts); src/sdk/limrun.ts keeps its export list unchanged.
  • Trim facades/platform.ts 36→26 app-log exports. Delete outright: DurableResourceFacet (zero implementers; the network facet uses none of its ecosystem — resolves finding 7 in the delete direction) and AppLogDescriptorCodec (every real codec types against generic DurableDescriptorCodec). Fold the six other zero-consumer types (AppLogInspection, AppLogDoctorInput/Result, AppLogRecoveryContext, AppLogReattachInput, AppLogCleanupInput) into unexported locals.

6. Daemon-side reuse core (sets up recordings)

  • AppLogCleanupLedger, instantiated in daemon-runtime.ts beside sessionStore/leaseRegistry, replacing the two module-global Map/Sets. Includes a new P1: assertNoRetainedLegacyMarker() checks retainedLegacyAppLogMarkers.size === 0 globally — one stuck legacy marker on any device blocks logs start on every device until daemon restart. Scope it by deviceIdentityKey. Give undurableCleanupBlocks a bounded TTL with a diagnostic on expiry.
  • Lifecycle 5→2 (open | completed, phase as forensic metadata): 'completing' is written 3x, read 0x; the only persisted-lifecycle branches in the codebase are === 'completed' (recovery skip, preflight conflict) plus a same-call starting|active authority check. Recovery's real state machine is the live ReattachOutcome, not the persisted string. This also removes the two-phase adoption write and the starting-as-tombstone in persistIncoherentRuntimeEnvelope, and makes the fail-closed decode stricter. Requires a one-paragraph ADR 0019 §5 amendment; fencing, fail-closed decode, and cleanup-only recovery are untouched.
  • With those two in place, extract the fence/envelope/transition/ledger core as an internal DurableCaptureResource so handler bodies drop to ~15 lines — this is the seam the recordings migration reuses.

7. Teardown caveat — do not simply delete skipAppLog

sessionStore.set replaces the session object; teardownDaemonSessionForShutdown then passes the stale reference where session.appLog is still truthy, so removing the flag double-invokes forceCleanupSessionAppLog on a disposed resource. Convert to an options object with explicit appLog: 'run' | 'already-settled' and declarative step construction instead of steps.splice(1, 0, ...).

Minor

freezeJsonValue re-runs the full bounded validator per nested node (quadratic under the 4,096-node cap) — branch on cheap type checks instead. Merge app-log-live-handle-core.ts into app-log-live-handle.ts (single caller).


Net: ~800–900 source lines deleted, ~10–15 kB raw JS + ~20 kB declarations, and the next PID-shaped family or durable resource type starts from a declaration, not a clone. Budget/threshold direction is recorded on #1704.

Base automatically changed from agent/platform-runtime-devices to main August 10, 2026 10:52
@thymikee
thymikee force-pushed the agent/platform-runtime-logs branch from 14ce1ef to e99da36 Compare August 10, 2026 12:10
@thymikee

Copy link
Copy Markdown
Member Author

Revision package implemented at e99da3680

This head is rebased onto merged #1699 and implements the review package from the prior comment, with the placement correction from #1704: implementation mechanics live in a new private @agent-device/capture-kit, while @agent-device/contracts keeps the pure types and plan models.

What changed

  • Added canonical kernel device identity and reused it across preflight, adoption, binding, and recovery. factsMatchBindingIdentity remains separate because it validates RuntimeDeviceShape, not device identity.
  • Added the bounded Android/Harmony PID-scoped owner factory in capture-kit. Apple and Limrun stay custom; there is no network factory and no generalized Limrun poller. Lazy family loading is preserved.
  • Deleted the managed-command allowlist; exact PID/start-time/command marker identity remains the ownership proof.
  • Added plan-declared requiresAppSession; the dispatcher proves the app session once and passes a required bundle ID through start/restart.
  • Split the daemon-internal Limrun provider-module handle from the public LimrunRuntime, removing the declaration closure leak without changing the SDK export list.
  • Trimmed unused platform façade types/values.
  • Replaced ambient app-log sets/maps with a daemon-owned AppLogAdmissionLedger: retained legacy markers are device-scoped, invalid evidence remains globally fail-closed, and undurable blocks expire after 5 minutes with diagnostics.
  • Fixed the stale-marker P1 on the exact recovery seam: a decoded owned marker whose process is confirmed missing is cleared before terminal recovery, and a second start succeeds.
  • Collapsed persisted lifecycle to open | completed; transient phase stays metadata. ADR 0019 §5 now records that model explicitly.
  • Replaced the teardown skip boolean/positional shape with a discriminated API. Shutdown settles app-log under its fence, re-reads the store, then performs generic teardown, avoiding the stale-reference double-cleanup trap.
  • Fixed the bounded JSON freeze quadratic walk, merged the live-handle core, and factored the verified lifecycle/reconnect clones.

Package placement and sequencing

@agent-device/capture-kit now owns the durable-capture implementation: PID process/recovery/live-handle/probe/session-artifact mechanics, runtime envelope/descriptor codecs, and durable JSON helpers. Contracts retains the envelope and operation/outcome types plus plan models. The ratchet rejects filesystem/process/timer mechanics drifting back into contracts. Compliance wiring covers affected checks, layering enumeration, package boundaries, and workspace typecheck.

The temporary #1699 Android implementation in contracts is also gone at this head: android-adb-failure.ts and android-device.ts are removed from contracts and their end-state implementations stay with Android inventory/daemon consumers. The older android-input-ownership, android-system-chrome, and apple-multitouch-support cargo is intentionally untouched until those command cutovers.

Validation

  • pnpm check:affected --run && git push --force-with-lease: passed; push occurred only after the gate.
  • 778 test files / 6,363 tests passed.
  • Changed-line coverage: 993/1,104 = 89.95%.
  • Package/declaration smoke, full typecheck, lint/format, layering, fallow, provider integration, replay compatibility: green.
  • Seen-red evidence covered the plan requirement, lifecycle decoder, cross-device marker wedge, ledger TTL, Limrun declaration leak, quadratic freeze, and contracts-implementation ratchet.

Budget denominator

The size decision remains #1704, measured cumulatively from the original 44c298d7f checkpoint baseline rather than the now-merged devices base:

Metric 44c298d7f e99da3680 Cumulative delta
JS raw 2,036,067 2,120,117 +84,050 (+4.128%)
JS gzip 659,646 689,797 +30,151 (+4.571%)
npm tarball 797,027 823,385 +26,358 (+3.307%)
npm unpacked 2,781,186 2,866,441 +85,255 (+3.065%)

That is the honest cumulative checkpoint cost; the rebased per-PR report must not replace it. The accepted rationale is capture-pipeline reliability, durable cloud log streaming, and reusable durable-capture substrate—not a new observability layer.

@thymikee

Copy link
Copy Markdown
Member Author

Independent verification at e99da368 — revision package confirmed; two findings remain

Verified in code and via an independent build with module-level source-map attribution, not from the summary.

Confirmed implemented: capture-kit owns the mechanics; canonical deviceIdentity in packages/kernel/src/device-identity.ts with all five old encoders at zero occurrences; isManagedAppLogCommand deleted; guard dedup real (one requires an app session occurrence, was six; zero requireRuntimeBinding sites); lifecycle 'open' | 'completed' with the ADR 0019 §5 amendment in this diff; DurableResourceFacet deleted; contracts ratchet gate present; #1699's android files out of contracts; the limrun.d.ts leak properly dead — 14,654 B vs baseline 14,369 B, zero AppLog references, the shared logs.d.ts declaration chunk gone.

Size, independently measured: packaging metrics improved as designed (tarball cumulative +3.31%, unpacked +3.07%), while raw JS is ~4 kB heavier than the pre-revision logs head — the dedup savings were consumed by review-mandated correctness code (Harmony toolchain preflight, scoped Apple tool host, ledger TTL/diagnostics, teardown rework). The cumulative table in the summary is honest; the unrelated main fixes in its denominator contribute negligible bytes. #1704 remains the deciding gate for raw/gzip, as expected.

Findings

1 (P2) — the retained-marker hint promises a remedy the ledger doesn't honor. Retained legacy markers are loaded once at daemon startup (daemon-runtime.tsretainLegacyMarkers) and assertStartAllowed in app-log-admission-ledger.ts never rechecks the filesystem. A user who follows the hint — inspects and removes the app-log.pid after confirming the process is gone — stays blocked until they also restart the daemon. Either recheck marker-file existence in assertStartAllowed and drop the entry when the file is gone (self-healing, still fail-closed for markers that remain on disk), or change the hint to state a daemon restart is required. Prefer the recheck.

2 (polish, optional) — packages/platform-android/src/logs/runtime.ts is 109 lines against the ~40-line config target (doctor probes inlined rather than declared), and contracts still carries ~6.5 kB more bundled runtime than baseline (plan models, binding-narrowing helpers — legitimate under the gate; noting the aspiration, not blocking).

Positive note: the ledger's residual global block now applies only to markers whose device identity is undecodable — the honest fail-closed scope, not the old cross-device wedge.

With finding 1 addressed and smoke green, this PR is done pending #1704. A rebase expectation for #1702 is recorded on that PR.

@thymikee

Copy link
Copy Markdown
Member Author

Exact-head re-review at e99da368: not ready.

Confirmed P2: daemon startup retains legacy app-log markers in AppLogAdmissionLedger once; assertStartAllowed never rechecks/removes an entry after its marker file is manually removed, while the error hint says removal is the remedy. Following the hint therefore remains blocked until daemon restart. Recheck injected marker existence at admission and delete only the absent matching entry—or explicitly require daemon restart—with red-before coverage.

Exact-head live logs evidence is also stale after the admission-ledger/identity/PID-runtime/lifecycle/teardown rewrite. Rerun Android recovery/replacement-start and iOS logs doctor -> start -> marker -> relaunch -> stop -> close, recording Harmony unavailability as residual risk if needed.

Finally, the cumulative checkpoint remains above the locked +3% bound in all four metrics: +4.128% raw, +4.571% gzip, +3.307% tarball, and +3.065% unpacked. #1704 remains open.

Other targeted revision paths and all current checks are clean. No ready label applied.

@thymikee

Copy link
Copy Markdown
Member Author

Exact-head re-review at 5f63821d: prior retained-marker P2 is fixed cleanly. Admission now rechecks matching marker existence, prunes only absent entries, and remains fail-closed if any matching/global marker survives; the createNextAppLogFence regression is non-vacuous against the prior implementation.

Two readiness blockers remain: no exact-head Android recovery/replacement-start and iOS logs doctor -> start -> marker -> relaunch -> stop -> close evidence exists after the admission-ledger/identity/PID-runtime/lifecycle/teardown rewrite, and #1704's cumulative package checkpoint remains revise with all four locked +3% metrics exceeded (+4.128% raw, +4.571% gzip, +3.307% tarball, +3.065% unpacked).

All checks are green; no ready label applied.

@thymikee

Copy link
Copy Markdown
Member Author

Implemented and pushed the remaining exact-head logs correction at 6394ef4.

What changed:

  • PID-scoped app-log capture now monitors the resolved app PID and rotates the managed log stream when the app relaunches. The reusable lifecycle mechanics live in @agent-device/capture-kit; platform packages still own PID resolution and command construction.
  • Seen-red regression: the new rollover test failed before the implementation because no monitor sleep/start boundary existed. The focused capture/runtime set is now 6 files / 36 tests green.
  • The mandatory pnpm check:affected --run && git push chain passed: 779 files / 6,365 tests, changed-line coverage 90.11%, all runnable selected checks green.

Exact-head Android live proof on emulator-5554 / com.callstack.agentdevicelab:

  • capture started against app PID 8956; after open --relaunch the app PID became 9294;
  • app-log.pid changed to adb -s emulator-5554 logcat -v time --pid 9294;
  • app.log contains both pr1701-android-rollover-before and pr1701-android-rollover-after plus fresh PID-9294 startup output;
  • logs stop and session close both succeeded.

Crash-recovery / second-start proof:

  • Before signaling, daemon PID 14941 and logcat PID 50573 were matched against their recorded start times and exact commands; the resource manifest was open and session-confined.
  • After SIGKILL of only those verified processes, the replacement daemon removed app-log.pid and rewrote app-log.resource.json to lifecycle completed with recoveryStatus already-missing.
  • Reopening the same session then completed logs start -> mark pr1701-android-after-recovery -> logs stop -> close successfully.

Addendum bookkeeping: the temporary #1699 contracts implementations packages/contracts/src/android-adb-failure.ts and android-device.ts are absent at this #1701 head. Their resolved ownership is carried by this rebase; they are not intended to remain in contracts.

The package-budget decision remains tracked separately in #1704 and must use the cumulative 44c298d baseline, not the post-#1699 moving base.

@thymikee
thymikee force-pushed the agent/platform-runtime-logs branch from 6394ef4 to 1887953 Compare August 10, 2026 14:21
@thymikee

Copy link
Copy Markdown
Member Author

Exact-head re-review at 188795386: the PID-rollover route and regression are clean. Android/Harmony PID-scoped logs now monitor the resolved app PID, terminate and dispose the old exact managed stream when it changes, wait through absence, and start the platform-owned command against the replacement PID. The regression observes that lifecycle and is load-bearing. All substantive checks are green; the PR is CLEAN/MERGEABLE.

This remains not ready for two reasons. First, practical evidence is not exact-head complete: the Android rollover/recovery proof was captured at pre-rebase 6394ef49. Its logs patch is range-diff-equivalent, but current main also changes Android lifecycle, so rerun the full open -> logs start -> marker -> open --relaunch -> marker -> logs stop -> close and guarded recovery/replacement-start sequence at exact head. Exact-head iOS logs doctor -> start -> marker -> relaunch -> stop -> close evidence is still absent after the Apple tool-host move; Harmony HDC evidence remains unavailable and should be recorded as residual risk if no target exists.

Second, #1704 now has reviewed same-host cumulative measurements and revised measured bounds, so the old “unreviewed +3% decision” wording is obsolete. But the checkpoint is not complete: #1704 remains open, ADR 0019 has not recorded the accepted bound, and checkpoint Status remains revise rather than continue or stop. Complete the ADR/#1703 checkpoint rerun before readiness. No ready label applied.

@thymikee

Copy link
Copy Markdown
Member Author

Final rebased-head live follow-up:

  • Verified source checkout HEAD: 188795386466cfdba5d5748db5c9d3477e70eb4e.
  • Android emulator session pr1701-final-head opened the controlled com.callstack.agentdevicelab fixture and started logs.
  • Before relaunch, app-log.pid targeted app PID 10952 (adb -s emulator-5554 logcat -v time --pid 10952).
  • open --relaunch moved the app to PID 11455; within the monitor interval the durable marker rotated to adb -s emulator-5554 logcat -v time --pid 11455.
  • The same app.log contained both pr1701-final-before and pr1701-final-after, plus 117 lines from PID 11455, including process startup output.
  • logs stop and close both succeeded. The named session, worktree daemon state, Metro server, and temporary tcp:8093 adb reverse mapping were cleaned up; the emulator was left running.

This refreshes the relaunch/stream-rollover evidence on the final rebased PR head. The earlier comment retains the detailed verified daemon-crash/dead-child recovery → completed manifest → successful second start proof.

@thymikee

Copy link
Copy Markdown
Member Author

The architecture/budget portion of the remaining review is now resolved by the pushed checkpoint stack:

  • ADR 0019: resolve the platform-runtime package-size checkpoint #1704 records the explicit revised-budget decision and rationale.
  • docs: record platform runtime adoption checkpoint #1703 at ffc077e25cd2ab7cd9ddfe3b1100efb59ba18619 now uses the original 44c298d7 cumulative denominator, records the final logs/network heads, marks the defective old checkpoint superseded, includes the capture-kit placement/ratchet and ADR §5 ledger amendment, and names recordings on DurableCaptureResource as the next unit.
  • Exact-head Android rollover and stale-marker recovery proof is already linked above; the current logs head remains 188795386466cfdba5d5748db5c9d3477e70eb4e with all checks green.

This follow-up closes the ADR/budget bookkeeping portion only. I am not relabeling the previously requested exact-head iOS live route as satisfied by unit or smoke coverage.

@thymikee

Copy link
Copy Markdown
Member Author

Exact-head iOS simulator evidence is now complete on 188795386466cfdba5d5748db5c9d3477e70eb4e.

Target and controlled fixture:

  • iPhone 17 Pro simulator 6044A251-23C2-4584-B7DB-87A16B787757
  • com.callstack.agentdevicelab; interactive snapshot showed the real Agent Device Tester surface before the log flow
  • isolated session pr1701-ios-final

Observed production route:

  1. logs doctor reported backend ios-simulator, simctlAvailable: true, inactive state, and the canonical session app.log.
  2. logs clear, logs start, and marker pr1701-ios-final-before succeeded.
  3. The app process before relaunch was PID 2168; the managed log marker owned a simctl ... log stream child with PID 3699.
  4. open --relaunch --metro-port 8093 succeeded on the same session; the app moved to PID 5041 while the same log resource stayed active.
  5. Marker pr1701-ios-final-after succeeded. The same app.log contained both canaries, lines from AgentDeviceTester[2168], and the new launch/runtime output from AgentDeviceTester[5041] (including successful HTTP 200 traffic).
  6. logs path reported active: true, backend ios-simulator, and the unchanged canonical path; logs stop returned stopped: true; session close succeeded.

The Metro process was stopped afterward and the simulator was left running. This closes the requested exact-head iOS start → relaunch/PID rollover → output → stop evidence rather than relying on the generic native smoke job.

@thymikee thymikee added ready-for-human Valid work that needs human implementation, judgment, or maintainer merge and removed ready-for-human Valid work that needs human implementation, judgment, or maintainer merge labels Aug 10, 2026
@thymikee

Copy link
Copy Markdown
Member Author

Exact-head readiness update at 188795386: the prior Android, iOS, and package-budget blockers are closed. Android live proof covers PID rollover 10952 -> 11455, marker rotation, continuous app.log output, stop/close, and the previously recorded guarded recovery/replacement start. iOS live proof now covers logs doctor, clear/start, marker, app relaunch 2168 -> 5041, old/new process output in the same canonical app.log, path, stop, close, and cleanup. All checks are green and the branch is CLEAN/MERGEABLE. #1704 and #1703 now record the revised cumulative budget and ADR bookkeeping.

The remaining blocker is HarmonyOS/HDC practical evidence. This head changes the shared Android/Harmony PID-scoped owner plus Harmony toolchain/cancellation/start behavior, but no live Harmony target has exercised it. On an available configured HDC target, provide open -> logs doctor -> logs start -> marker -> relaunch/PID rollover -> marker/output -> logs stop -> close, and preferably recovery -> replacement start; if the target remains unavailable, this stays an explicit residual device risk under the project readiness rule. No ready label applied.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Aug 10, 2026
@thymikee
thymikee merged commit b1ed535 into main Aug 10, 2026
32 checks passed
@thymikee
thymikee deleted the agent/platform-runtime-logs branch August 10, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants