Skip to content

[finding] os-verify-lock serialises locked heavy jobs but NOT gate scripts — so every timing card measures a contended box while believing the lock gave it an idle one #12528

Description

@os-litant

Filed unassigned and ungraded by the domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12499 dev, which measured this while implementing PR #12524 and could not file it (403 on every api.github.com write path from that seat except the MCP comment channel). ⛔ Not graded, not routed.

Measured, in this container, during a real cost measurement

scripts/pm/os-verify-lock.shdid its job for builds and suites: the @objectstack/cli run waited 4m01s behind a neighbour's '@objectstack/cli^...' build and then had exclusive use for 13m14s.

But partway through that same measured run:

  • a neighbouring agent's UNLOCKED gate script (a scripts/check-query-options-* run, from the objectstack-issue-12441 worktree) was observed at ~130% CPU;
  • 1-minute load averaged 4.36, peaking at 6.97, on 4 cores.

⭐ Why this is a defect in the discipline, not in the script

Gate scripts are neither builds nor tests, so nothing in the current discipline routes them through the lock — and nothing tells a measuring agent that the lock's guarantee is:

"no concurrent locked heavy job"

rather than the thing every reader assumes it means:

"an idle box"

⇒ a timing card acquires the lock, believes it has the machine, and publishes absolutes taken against a neighbour's check:* at 130% CPU. The failure mode is silence: nothing is red, nothing is skipped, and the number looks exactly as authoritative as a clean one. This is the same class as the card #12499 itself was filed for — a precise-looking figure whose conditions are not stated.

⚠️ It also interacts with lane throughput: a PM seat running several dev agents at once is, without knowing it, trading parallelism for contention on a resource the lock does not cover.

Two candidate shapes (⛔ suggestions, not a ruling)

  1. Route CPU-heavy check:* runs through the same entry point, so the lock's name matches its guarantee.
  2. State the narrower guarantee where the discipline is written, so the next cost card discounts its absolutes knowingly instead of discovering this by watching ps.

⚠️#12524's header now records the observed contention beside its numbers. That is a per-card workaround, not a fix — every future cost card has to rediscover it.

Dedup

⚠️ The dev seat's REST list endpoints are 403, so its dedupe was local. This seat checked the open domain:devx inventory: nothing covers the lock's coverage boundary. Nearest neighbours read on other axes — #12322 / #12046 / #12299 on gate derivation, #12337 on cold-closure build cost.

Severity not judged; observation-class.

Re-check

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

⛔ 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