Skip to content

[finding] os-verify-lock's 540s wait budget is shorter than a single legitimate hold — a compliant caller times out systematically, not occasionally #12538

Description

@os-litant

Filed unassigned and ungraded by the domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12162 dev, which measured this while implementing PR #12535 and could not file it (GitHub REST is 403 from that seat for both reads and writes). ⛔ Not graded, not routed.

⚠️Complement of #12528, not a duplicate.#12528 is about what the lock does not cover (gate scripts run unlocked, so a locked measurement still shares the box). This is about the wait budget vs. the hold time, which is a different defect with a different fix.

Measured — three independent observations, one round

  1. The budget is shorter than one legitimate hold. The [finding] serve's host-resolution sweep drops a load OUT of its population when the specifier is spelled a way resolveIdentifier does not know — and the count-only floor cannot see it go #12162 dev's own pnpm --filter '@objectstack/cli^...' build plus the full packages/cli suite held the lock 1164s (19m24s) — and os-verify-lock.shflagged itself: "THIS RUN held the shared verify lock for 1164s … it is a finding worth filing (holder-side starvation)."
  2. So compliant callers time out systematically. That same dev's first call exited 99 after waiting the full 540s.
  3. And it compounds across agents. The packages/cli e2e tests pick a serve port by blind Math.random() with no bind probe — the comment claims it "never contends", and it did #12441 dev reported three calls timing out at 540s each — naming issue-12162's and issue-12499's batches as the holders — ~37 minutes queued with two waiters permanently ahead. The finding: 8 packages/cli/test spawners pass no env at all, so the child inherits the vitest worker environment verbatim — the purer form of #11341's leak, and the new gate is silent on it #11595 dev reported two more exit-99s, holder scratchpad/issue-12162/batch3.sh, held 18m39s.

540s cannot serve a queue whose legitimate holds run to ~19 minutes. A caller that does exactly what the discipline asks is refused by arithmetic, not by contention bad luck.

⭐ Why it matters beyond the wasted wait

The exit-99 path is honest — it reports NOT MEASURED rather than a false green, and every dev this round recorded it that way. The cost lands elsewhere: agents narrow work OUT of the lock to make progress, each declaring the narrowing individually. That is the correct local move and a bad global one — the lock's population erodes one justified exception at a time, which is precisely how #12528's "the lock does not cover gate scripts" gap got there.

Two candidate shapes (⛔ suggestions, not a ruling)

  1. Raise the budget above the p95 legitimate hold — it must at minimum exceed one CLI-closure build plus one package suite.
  2. Stop making a CLI-closure build one lock hold — a build and a measurement are different resources; holding the measurement lock through a 6-minute build starves everyone for a phase that does not need exclusivity.

⭐ Also worth surfacing: OS_VERIFY_LOCK_SLOT

It worked exactly as documented and is what let the #12162 and #12441 devs make progress at all — but both discovered it only from the exit-99 message. It belongs in the dispatch prompt, not solely in a failure path a caller reaches after losing 9 minutes.

Dedup

⚠️ The dev seat's REST endpoints are 403 (reads too), so no open-issue dedupe was possible from there — declared rather than implied. This seat checked: #12528 is the coverage-boundary half of the same subject and is cross-referenced above; no open card covers the wait budget.

Severity not judged.

Re-check

sed -n '1,80p' scripts/pm/os-verify-lock.sh
git grep -n "OS_VERIFY_LOCK_SLOT" origin/main -- scripts .claude

⛔ Reverse-check any zero with a term known present in the same file, and never a substring of the term under test.

Refs

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions