Skip to content

FE-875: App runtime probe — boot, probe, classify#219

Open
kostandinang wants to merge 4 commits into
ka/fe-872-dep-install-classificationfrom
ka/fe-875-app-runtime-probe
Open

FE-875: App runtime probe — boot, probe, classify#219
kostandinang wants to merge 4 commits into
ka/fe-872-dep-install-classificationfrom
ka/fe-875-app-runtime-probe

Conversation

@kostandinang

@kostandinang kostandinang commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Stack Context

Stacks on FE-872 (#218). Fifth Arc-1 frontier -- the concrete reachability mechanism behind integration-oracle (without it, "reachable" collapses to "a test imports the module"). Slices 1 + 2 both land here.

What?

Boot the host app from the cook worktree and exercise it over the wire -- the app-execution analogue of test-runner.ts.

  • Slice 1 -- probe (runProbe, app-probe.ts): boot -> poll readiness -> hit one HTTP feature endpoint -> classify, always tearing the process down. reachable (< 400), not-reachable (booted but endpoint absent/erroring -- the FE-800 orphan), infra (never booted). A spawn error bails fast instead of polling to timeout.
  • Slice 2 -- spec resolution (buildProbeSpec, app-probe.ts): resolve a ProbeTarget (boot argv + paths) into a runnable ProbeSpec by allocating a free port and assembling the ready/feature URLs. The boot test's hand-rolled port dance becomes the production primitive it now dogfoods.

Why?

Verification today only runs the test runner in the worktree, so "reachable" degrades to "a test imports the module" and the FE-800 orphan survives. The harness owns the deterministic, unshortcuttable check; the boot argv + paths are inputs (cook-time grounding supplies them later) -- no per-stack boot engine. The port can't be hardcoded: under parallel cook each slice boots its own app and a fixed port collides, so port->URL binding is the one harness-owned piece (best-effort ephemeral, loopback-only, acknowledged TOCTOU window -- no retry framework).

Tests

Real seeded node:http apps in tmp worktrees, no mocks: reachable; booted-but-404 -> orphan; immediate-exit / missing-binary -> infra; teardown leaves no process. Plus buildProbeSpec: port allocated + URLs assembled, caller env layered under PORT, distinct ports across 8 concurrent allocations. (Also hardens the FE-743 wall-clock timing test, which flaked under the CPU contention real-process tests add -- tolerance now scales with serialMs.)

Deferred

Mode-awareness + where the ProbeTarget argv/paths come from (architect intent + cook grounding) = integration-oracle (#6).

Co-authored-by: Amp amp@ampcode.com

@kostandinang kostandinang changed the title FE-875: app runtime probe — boot + HTTP probe + reachability classification (slice 1) FE-875: App runtime probe — boot, HTTP probe, reachability classification Jun 16, 2026
@kostandinang kostandinang force-pushed the ka/fe-875-app-runtime-probe branch from cb90e92 to f7a632b Compare June 16, 2026 10:40
@kostandinang kostandinang changed the title FE-875: App runtime probe — boot, HTTP probe, reachability classification FE-875: app runtime probe — boot/probe/classify + ProbeSpec resolution Jun 16, 2026
@kostandinang kostandinang changed the title FE-875: app runtime probe — boot/probe/classify + ProbeSpec resolution FE-875: App runtime probe — boot, probe, classify Jun 16, 2026
@kostandinang kostandinang force-pushed the ka/fe-872-dep-install-classification branch from ff041c6 to 7e923c6 Compare June 16, 2026 12:53
@kostandinang kostandinang force-pushed the ka/fe-875-app-runtime-probe branch 2 times, most recently from 6139723 to abb2725 Compare June 16, 2026 13:24
@kostandinang kostandinang force-pushed the ka/fe-872-dep-install-classification branch 2 times, most recently from 2cec280 to fecc5c6 Compare June 16, 2026 13:38
@kostandinang kostandinang force-pushed the ka/fe-875-app-runtime-probe branch from abb2725 to 56fa05d Compare June 16, 2026 13:38
@kostandinang kostandinang marked this pull request as ready for review June 16, 2026 14:18
@cursor

cursor Bot commented Jun 16, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
New orchestrator module and types only; not yet wired into the cook net. Real-process integration tests may add CI load; timing assertion change is test-only.

Overview
Adds the app runtime probe (FE-875): harness code that boots a real app in the cook worktree and checks one HTTP feature endpoint, so reachability is not reducible to “a unit test imports the module.”

runProbe spawns the boot argv, polls a readiness URL, hits the feature URL, and returns reachable (HTTP <400), not-reachable (app up but endpoint missing — the FE-800 orphan), or infra (boot/probe failure), mirroring FE-872’s infra vs test split. Boot processes are always torn down (SIGTERM → SIGKILL). Readiness and feature fetch calls use AbortSignal.timeout so a server that accepts connections but never responds cannot hang the cook.

buildProbeSpec turns a ProbeTarget (boot argv + path strings) into a ProbeSpec: it picks a free loopback port, sets PORT in env (overriding caller PORT), and builds ready/feature URLs — the piece the harness owns so parallel cooks do not collide on a hardcoded port.

New types live in types.ts (ProbeSpec, ProbeTarget, ProbeResult, ProbeOutcomeKind). Integration with integration-oracle and cook-time ProbeTarget sourcing is still deferred; PLAN.md records slices 1–2 as landed.

Also relaxes the engine contract parallel-vs-serial timing assertion to scale with serialMs so real-process probe tests do not flake under CPU contention.

Reviewed by Cursor Bugbot for commit f32bdf1. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56fa05d. Configure here.

Comment thread src/orchestrator/src/app-probe.ts
Comment thread src/orchestrator/src/app-probe.ts
@kostandinang kostandinang force-pushed the ka/fe-875-app-runtime-probe branch from 56fa05d to a188d00 Compare June 16, 2026 18:05
@kostandinang kostandinang force-pushed the ka/fe-872-dep-install-classification branch from 4ef65e5 to c902500 Compare June 16, 2026 23:45
@kostandinang kostandinang force-pushed the ka/fe-875-app-runtime-probe branch 2 times, most recently from cc32bd0 to 57fd42c Compare June 16, 2026 23:55
@kostandinang kostandinang force-pushed the ka/fe-872-dep-install-classification branch from c902500 to ba9c819 Compare June 16, 2026 23:55
…cation (slice 1)

The app-execution analogue of test-runner.ts: runProbe(spec, sandboxDir)
boots an app from the worktree, polls readiness, exercises one HTTP feature
endpoint, and returns a structured ProbeResult classifying the outcome as
reachable (<400) / not-reachable (booted but endpoint absent — the FE-800
orphan) / infra (never booted), always tearing the boot process down.

- types.ts: ProbeOutcomeKind / ProbeSpec / ProbeResult
- app-probe.ts: runProbe + readiness poll + SIGTERM->SIGKILL teardown;
  spawn-error bails fast instead of polling to timeout
- the boot argv + URLs are ProbeSpec INPUTS (cook-time grounding supplies
  them later), not a per-stack boot engine — harness owns the deterministic,
  read-only check; boot mechanics may lean on agent bash (honors the boundary)
- tests boot real seeded node:http apps: reachable / orphan-404 /
  boot-fail / missing-binary / teardown

Also hardens the FE-743 'comparable wall-clock' timing test: its absolute
25ms slack flaked under CPU contention from real-process test files (this
slice's probe tests exposed it). Tolerance now scales with serialMs; a true
serialized-parallel regression is many x serialMs, still caught.

Remaining slices: mode-awareness, integration-oracle gating, ProbeSpec sourcing.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a
Co-authored-by: Amp <amp@ampcode.com>
kostandinang and others added 3 commits June 17, 2026 09:36
… probe

runProbe's readiness poll and feature fetch used bare global fetch with
no timeout. A server that accepts a connection but never responds would
block await fetch forever — the wall-clock READY_TIMEOUT_MS is only
checked between poll attempts, so it never fired, hanging the probe and
the whole cook. Each fetch now carries a per-call AbortSignal.timeout;
timeouts are overridable so the no-hang behavior is unit-tested fast.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant