Skip to content

feat(core): attribute location boot phases and bound wellknown fetches - #354

Merged
shuv1337 merged 2 commits into
integration-v2from
location-boot-phases
Aug 10, 2026
Merged

feat(core): attribute location boot phases and bound wellknown fetches#354
shuv1337 merged 2 commits into
integration-v2from
location-boot-phases

Conversation

@shuv1337

Copy link
Copy Markdown
Collaborator

Fixes #352.

Diagnosis

The reported "serialization" of concurrent cold location builds is not a lock. A controlled benchmark at the LocationServiceMap level (6 fresh directories, warm globals) reproduces the issue's completion-clustering signature and shows the concurrency is work-conserving:

Measurement Result
Sequential per-build 14, 16, 14, 15, 15, 9 ms (total 85 ms)
Concurrent per-build 28, 24, 21, 32, 27, 28 ms — clustered
Concurrent total wall-clock 35 msless than the sequential total

RcMap.get forks each key's lookup into its own fiber and Layer.MemoMap only shares same-layer builds through a deferred, so N concurrent CPU-bound builds time-slice fairly on the single JS thread: each observes ~N× latency and all complete together. That fully explains the issue's 10× repro (6 × ~30 ms of work ⇒ everyone finishes at ~330 ms) and the p99 clustering. It does not explain the 16.2 s incident, which must be an off-CPU await inside a specific phase — exactly what the missing instrumentation hides.

Changes

  1. BootPhase (new, packages/core/src/boot-phase.ts) — a per-boot phase recorder provided to the location layer build via fiber context. location services booted now carries a phaseMs breakdown: config (discovery), wellknown (nested inside config), project (resolve incl. git), and watch (initial config-root reconcile — the incident's watcher-subscribe evidence). Plugin activation and repository watches are forked off the boot critical path and stay uninstrumented. The unattributed remainder is node construction plus time-slicing against concurrent boots.
  2. Bound wellknown HTTP fetches with a 10 s timeout (inspect + remote config GET). Previously unbounded and on the response path.
  3. Adopt upstream anomalyco/opencode@c22942c1f3 (fix(core): tolerate unavailable wellknown config): a failing wellknown.resolve logs a warning and contributes no documents instead of dying the config load. Resolved against our entry ordering (wellknown stays highest priority). With (2), an unresponsive origin now degrades into a warning instead of stalling every cold build for that location indefinitely.

Upstream v2 was checked for a fix to the serialization itself: none exists (only the adopted tolerance commit touches this path).

Not changed, deliberately

  • No cap on concurrent builds: serializing would keep the same makespan while adding head-of-line blocking — one pathological build would stall unrelated directories.
  • The build stays on the HTTP response path; making it cheaper or pre-warmed is follow-up work once phaseMs data names the dominant phase.

Validation

  • bun typecheck clean in packages/core, packages/server, packages/cli
  • 1595 core tests pass, including a new regression test (attributes boot phases in the booted log) asserting the booted log carries all four phase keys bounded by durationMs
  • Config tests cover the adopted upstream behavior (tolerates unavailable authenticated wellknown config and reloads it later)

Adopted from upstream anomalyco/opencode v2 commit c22942c (Dax Raad).
A failing wellknown resolve no longer dies the config load; it logs a
warning and contributes no documents until the integration reconnects.
Resolved against our tree's config entry ordering, which keeps wellknown
at highest priority.

Relates to #352: loadWellknown() sits on the location build path, so a
failing origin previously killed cold location builds outright.
Cold location builds logged one opaque durationMs, which made tail
incidents unattributable (#352 observed 16.2s with no way to tell config
discovery from project resolve from network waits). Controlled
measurement shows the reported concurrent-build "serialization" is fair
time-slicing of CPU-bound builds on the single JS thread: concurrent
cold builds are work-conserving (6 concurrent builds complete in less
total wall-clock than 6 sequential ones) but each observes ~N x latency
and all finish clustered. The tail therefore hides in an off-CPU await
inside a specific phase.

Add BootPhase: a per-boot recorder provided to the location layer build
via fiber context. The critical-path phases -- config discovery,
wellknown (nested inside config), project resolve, and the initial
config-root watch reconcile -- record wall-clock durations, and the
"location services booted" line now carries the phaseMs breakdown so the
next tail incident names its phase. Plugin activation and repository
watches are forked off the boot path and stay uninstrumented.

Bound both wellknown HTTP fetches (manifest inspect and remote config)
with a 10s timeout. Combined with the tolerated-failure handling, an
unresponsive origin now degrades into a logged warning instead of
stalling every cold build for that location indefinitely.
@shuv1337
shuv1337 merged commit 00e7c54 into integration-v2 Aug 10, 2026
2 of 3 checks passed
@shuv1337
shuv1337 deleted the location-boot-phases branch August 10, 2026 21:52

@github-actions github-actions 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.

shuvbot found no summary-only findings.

shuv1337 added a commit that referenced this pull request Aug 13, 2026
Merge anomalyco/opencode upstream/v2 (283258e, 187 commits) into
integration-v2 (00e7c54), aligning with upstream everywhere except
fork-critical features, per PLAN-upstream-v2-merge.md.

Preserved fork features: identity/publish/updater/launcher, managed
service lifecycle (ServiceLifecycle.ensure everywhere), Anthropic Claude
Pro/Max subscription provider, structured output, session tool policy,
strict prompt retry identity (durable admitted-event reconciliation),
mobile pairing removal, and prior fork fixes (#350/#353/#354).

Adopted from upstream: session_v2 rename, skills prompt attachments,
plugin hook rename request -> http.request/http.response, new CLI
commands (models/export/import/debug config), workspace_domain,
legacy-credential import, docs/app/desktop changes.

Database bridge (M2): DatabaseMigration.apply now detects a fork-tip
session table (fork_boundary column, tool-policy migration present, no
session_v2) and renames it to session_v2 in one transaction before
upstream migrations run, rebuilding session_v2_* indexes and marking
the upstream squash migration as already applied so its destructive SQL
never executes. Validated against a real dev DB copy (12 sessions/16
messages/86 events preserved) and via a fork-tip fixture test.

Data-safety corrections (M3): V1Migration no longer globally wipes
events when V2 sessions already exist (gated on empty session_v2);
imported legacy Anthropic OAuth credentials now map to methodID
claude-pro-max.

CLI/service wiring (M4): new upstream handlers registered without pair;
every server-start path (auth login, debug config, server-connection)
routes through ServiceLifecycle.ensure.

Regeneration & docs (M5): protocol/client/www regenerated; publish.yml
gains a github.ref_name == integration-v2 guard; merged docs rebranded
to Shuvcode while preserving SDK/API symbols; migrate-v1.mdx documents
the DB bridge, scoped event deletion, and the hook rename; AGENTS.md
records the session_v2/bridge and hook-name invariants.

Upstream-bug follow-ups (M6): symlinked mutation targets now resolve
through the nearest existing ancestor's real path before authorization,
closing an external-directory approval bypass; desktop background-cli
prefers the canonical managed state root over the first running
candidate; failed server replacement no longer removes existing tabs.

Validated: full per-package typecheck+test pass (schema, protocol,
core, server, client, cli, tui, app) plus a live smoke test against an
isolated standalone server pointed at a scratch copy of a real dev
database, confirming existing sessions/transcripts render and that a
live prompt round-trips both structured output and a skill attachment.
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.

Server: concurrent cold location builds serialize (p99 3.5s, 16.2s observed)

1 participant