Skip to content

probe 2: two contributor commits - #7

Merged
quad341 merged 2 commits into
mpr-probe-base2from
mpr-probe-h2
Jul 28, 2026
Merged

quad341 merged 2 commits into
mpr-probe-base2from
mpr-probe-h2

Conversation

@quad341

@quad341 quad341 commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Throwaway attribution probe for mpr cherry-pick design (gm-ubcxn). No workflows in base; nothing to review.

@quad341
quad341 merged this pull request into mpr-probe-base2 Jul 28, 2026
@quad341
quad341 deleted the mpr-probe-h2 branch July 28, 2026 05:07
quad341 pushed a commit that referenced this pull request Oct 3, 2026
…unwired) (gastownhall#6970)

## Summary

Reconciler v2, slice P3-3: the allocator's per-pass inputs, read in
memory. Built for P3-5a (decide), P3-4 (ledger clearing) and P3-7
(wiring), and **not wired into the runtime**. Nothing outside tests
constructs the new code. Legacy behavior is unchanged: the legacy edits
are pure extractions (listed below), and their callers pass the same
values they did before.

## Census (`allocator_census.go`, I2)

**Legs.** The census covers every open session row on every leg of
`sessionCensusStoreCandidates`, with the sessions leg first. It reads
only indexes (AM6):
- **Exact leg** (the SQLite binding): read from its `CachingStore`
through the session front door, which overlays dirty rows.
- **Recording leg** (bd, native Dolt, Postgres): served from the P3-2
backstop lane's recording of legacy's own live `ListAll`
(`[]session.Info` with `At` and `Err`). A pass never touches a non-exact
store.
- P3-2 is being built in parallel, so the census takes a two-function
seam (`censusLegFeed`): one function classifies the leg, the other
returns the recording, keyed by store.

**Last-good bounds and incomplete or stale legs.**
- A failed read serves the leg's last good rows whole, within a bound:
60s for an exact leg, 2 × patrol for a recording. Past the bound the leg
is **stale**: its rows Keep, and the census is incomplete.
- A stale leg, or one with nothing to serve, leaves the census
**incomplete**. That blocks every fresh create, as legacy does
(POOL-047; owner decision 2026-10-03).
- A partial read keeps its rows, on the sessions leg too. The pass fails
only on a hard sessions-leg error with nothing to serve, or when there
are no legs at all.

**Fold and duplicates.**
- Rows are keyed `(leg, bead ID)`, never by name, so rows that share an
enterprise slot-scoped name are one row each (F8).
- The fold keeps legacy's first-leg-wins rule by bead ID. A later copy
is a duplicate (C2.11): it stays in `Rows`, the unfolded census the
ledger reads, but it is not a canonical row and not a sharer of its
name.
- Each row carries the facts `ledgerRow` reads, under the same names:
`Incarnation`, `InstanceToken`, `StartLease` (START-043, including the
claim-or-creating condition via `pendingCreateStartInFlightInfo`) and
`PendingCreate`. These are set on the canonical copy only.
- `Ledger(cfg)` is the `ledgerCensus` adapter. It returns every row on
every leg with its `endpointKeyForAgent` endpoint, resolved from the
normalized template, and `Legs: CompleteLegs()`.
- Rows in states main does not know are flagged and counted per template
(F9), and keep their slots.

**Indexes.**
- Canonical rows by runtime session name.
- Pool identity leases over every copy on every leg. These are deduped
by `(ID, session_name, alias, agent_name)`, the same key as the create
effect's locked check (`freshPoolAvailabilityInfos`), so plan time and
effect time agree.
- `IdentityLeaseHolder` answers the snapshot leg of
`ensurePoolIdentityNotHeldByOpenRow` in O(1).

## Observation adapter (`allocator_observe.go`, I3, AM3)

Liveness states:
- **alive**: listed and fresh, its pane and process are not known dead,
and the runtime is attributed to this row or its name is unique.
- **occupied**: another bead owns the name, whether that runtime is
alive or dead.
- **dead**: listed and fresh, but `Running` or `ProcessAlive` is a fresh
No (tmux remain-on-exit keeps exited panes listed), attributed to this
row or its name is unique. A dead row is not uncertain. Like absent, it
is a start candidate, and the start path recycles the pane. It is not
alive for dependencies (BEHAVIORS #7).
- **absent**: listed No by a complete, attested pass.
- **absent-unconfirmed**: not listed by a fresh pass on which every
backend was complete or unattested.
- **unknown**: anything else, including a shared name whose runtime has
no known owner or carries no owner. An unknown row is uncertain.

"Present" means a fresh Listed Yes, or listed by the latest fresh pass
on a backend that did not fail, even if that backend never primes (exec,
ssh, herdr, t3bridge, or a partial listing).

Attach and pending:
- Unsupported attach reads as not attached. A stale or unprimed attach
on a backend that reports attach makes an alive row uncertain.
- Pending is an input only as a fresh Yes on an alive row, because
legacy probes pending only on live targets.
- A dead row reports neither attach nor pending.

## Readers (`allocator_health.go`)

- **Provider health (I7) and suspension (I9)** are memoized on `(mtime,
size)`: one stat per pass. A reader reloads while its last load is
within the filesystem's mtime granularity, so a same-size rewrite within
one tick is still seen.
- **Provider health** is parsed once per change and aged at the pass
clock.
- **Startup-health episodes** come from the sessions leg's cache:
through the dirty-row overlay on an exact leg, strictly from memory on
any other leg, and from the last good read for up to 60s. They are
resolved as `LoadStartupHealthEpisode` resolves them: newest created
wins, ties go to the largest ID.

## scale_check lane (`allocator_scalecheck_lane.go`, I5)

- **Cadence.** A paced lane on the patrol cadence. The first pass runs
at start, and each pass runs under the host's `safeTick`
(`v2-scale-check`).
- **Work.** Each pass runs every enabled custom scale_check pool through
`evaluatePendingPools`. The allocator is woken only when the counts or
the partial set change.
- **Partial results.** A pool whose probe env cannot be built is marked
partial, not skipped (BEHAVIORS gastownhall#38). A missing or stale result also
reads as partial.
- **City suspended** (`Workspace.Suspended`, the suspension file, or
`GC_SUSPENDED=1`): a pass runs nothing and publishes nothing. Legacy's
demand pass returns before any scale_check in this case
(`TestBuildDesiredState_ProductionDemandSkipsAllScaleChecksWhenCitySuspended`).
- The lane reads suspension through its own memoized I9 reader, and
derives suspended rigs from that same state.
- A skipped pass does not count toward the duty cycle
(`startGatedPacedLane`), so a wake after resume runs at once.
- A pass that panics does count, so wakes cannot rerun it back to back.
- **Parity with legacy.**
`TestScaleCheckLaneWorkMatchesBuildDemandTargets` compares the lane's
work element by element against legacy's `pendingPools`: agent index,
scale params including the expanded check, pool dir, probe env, and the
new-demand flag. The env failures must be exactly the pools legacy
silently skips. Fixtures:
  - P3-1's randomized cities;
  - `build_desired_state_test.go`'s scale_check fixtures;
  - a suspended rig, and a rig outside the city dir;
  - same-named agents in two rigs, where only one backs a named session.

## Legacy refactors (byte-identical behavior)

- `evaluatePendingPools` takes the runner, and
`evaluatePendingPoolsMapWith` exposes it; `evaluatePendingPoolsMap`
passes `shellScaleCheck` as before.
- `buildDemandTargets` takes the probe-env builder (`probeEnvFunc`);
legacy passes `controllerQueryRuntimeEnv`.
`TestBuildDemandTargetsGoldenAgainstInlineLoop` still pins it to the
pre-refactor loop.
- `loadProviderHealthSnapshot` is split into `parseProviderHealthFile`
and `snapshotAt(now)`.
- `ensurePoolIdentityNotHeldByOpenRow`'s predicate is extracted into
`poolIdentityLeaseOf` and `poolIdentityLeaseTemplateMatches`. Legacy and
the census call the same functions.
- `buildSuspendedRigPathsForCity` delegates to
`suspendedRigPathsWithState(cfg, st)`.
- `TestV2RuntimeDoesNotReferenceCityRuntime` now also covers the four
new files.

## Tests and mutations

New tests cover every row of the spec's P3-3 table, plus these added at
re-review:
- the lane skipping passes while the city is suspended (all three
sources, then a pass after resume);
- suspended rigs read from the pass's suspension state;
- a skipped pass not pacing the next wake;
- a wake after a panicking pass being paced;
- a duplicate copy not counting as a sharer;
- the lease dedupe key fields;
- endpoint resolution through the normalized template.

I re-ran the reviewer's mutants against the final tree, together with
five new ones for the suspension gate. R-C5 is gone because its code was
deleted (`ListAll` never returns closed rows). Of the 30 mutants, 25 are
killed and 5 survive, all from the original review and none targeted:
- R-O9, R-C3, R-H1 and R-S3 move a boundary or change last-good serving;
- P-4 (empty query topology) is equivalent for custom-check pools.

Local gates:
- `gofmt`, `go vet ./cmd/gc`, and `go build -o /dev/null ./...`;
- the slice tests with `-race -count=20`;
- the cmd/gc fast suite (`GC_FAST_UNIT=1`);
- `./internal/testpolicy/...` and `./scripts/...`;
- golangci-lint 2.12.0 `--new-from-rev=<merge base> --whole-files
./cmd/gc`: 0 issues;
- gazelle diff: none;
- the pre-commit and pre-push hooks.

## Obligations deferred (recorded in the P3 spec, "Obligations from
P3-3", §4.4 and §4.11)

**P3-5a**
- Ask `IdentityLeaseHolder` with the template-defaulted identity, and
only for bead-scoped identities.
- Read liveness through `alive` and `startCandidate`.
- Read POOL-052's singleton occupancy from the observation cache by the
planned runtime name, including unowned runtimes, with unknown counting
as occupied. A corpse frees the name, but a zombie holds it, because
legacy's `IsRunning` reads a zombie as running.
- Ask `scaleCheckResult.partial` only for custom-check templates.
- Either grant dead non-named rows a start (the interim divergence
below) or classify them `None(dead-runtime)`.

**P3-7**
- Make the host's sessions leg `legs[0]`.
- Re-pace the lane's patrol and the census `recordingMaxAge` on reload.
- Pass the leg classification to `episodeReader.read`, and give the lane
the host's `safeTick`.
- Wake the scale_check lane on resume.

**P4.1**
- Keep the dead-pane recycle in the start path.

**P4.4 and P4.1**
- Legacy closes non-named dead rows as `dead-runtime` before demand
(MAINT-031) and releases their work. MAINT-031 is off under v2 until
P4.4, so in the interim a dead row is granted a start in place. Once
MAINT-031 runs under v2, its close must win over a granted start.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
quad341 pushed a commit that referenced this pull request Oct 11, 2026
…stale apt index) (gastownhall#7554)

## Summary

**This fixes the fork pool outage.** Since about 20:05Z on 2026-10-10,
every fork pool VM has failed setup with `apt-get install` exit 100. The
image's apt index names `libxml2 2.9.14+dfsg-1.3ubuntu3.9`, which the
Blacksmith mirror now 404s, so fork lanes have had no workers (114
actions queued).

This bumps `gastownhall/rbe-worker` from `421eb59c` to `3bfd8aea`:
- #6 refreshes the apt index once and retries the toolset install,
before the worker-env measurement (which measures upstream major.minor
only).
- #5 (S4b) and its revert #7 cancel out, so S4b doesn't ship in this
bump.

## Test plan
- [x] rbe-worker `product-check` at `3bfd8aea` against this tree: ok
- [x] `go test ./scripts/ -run 'RBE|Worker|Pool'`
- [ ] After merge: fork pool runs succeed, and fork queued drains on
core

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant