Merge upstream/main into fork — v1.4.0 resync (352 commits) - #109
Merged
Conversation
…rics-single-tagged-build test: share one tagged binary across metrics process contracts
…empotence-double test: use stateful double for idempotent Dolt start
…load-event-driven test: signal supervisor death in reload failure test
…t-recovery-crisp test: remove duplicate raw bd recovery check
…y-crisp test: cut mail testscript from 54s to 9s
…nsistency-direct-dolt test: cut worktree store consistency from 59s to 7s
…starter-fast-clock test: simulate slow concurrent Dolt startup
…fast-composition test: replace managed mail city with direct Dolt fixture
## Summary - Strengthens the shared `mail.Provider` conformance suite so Archive and Delete remove a message from every public view. - Makes terminal operations return typed `mail.ErrNotFound` without resurrecting archived messages. - Gives `mail.Fake` deterministic clock and thread-ID suppliers, then aligns beadmail, the exec adapter/fixture, and the MCP bridge with the same contract. ## Why The interface already promised that Archive removes a message from all views, but shared conformance only checked Inbox. That allowed providers and test doubles to disagree on Get, Read, Reply, MarkRead, MarkUnread, Thread, All, and Count behavior. One reusable contract now owns those semantics instead of duplicating slow end-to-end scenarios. ## Test-pyramid impact - The same provider contract runs against Fake, beadmail, the stateful exec fixture, and the mocked MCP bridge. - No new real-service or end-to-end test was added. - `go test -count=1 ./internal/mail/...`: **62.80s**, versus **58.63s** baseline (**+4.17s / +7.1%**). - Peak RSS: **1,370,480 KB**, versus **1,367,368 KB** baseline (**+0.2%**). - An over-tested draft measured **80.83s**; its unrelated read-survivor setup was removed before review. ## Verification - `go test -count=1 ./internal/mail/...` - `go test -race -count=20 ./internal/mail -run '^TestFakeConformance$'` - `go test -race -count=20 ./internal/mail/beadmail -run '^TestBeadmailConformance$'` - `go test -race -count=20 ./internal/mail/exec -run '^TestExecConformance$'` - `go test -count=3 ./internal/mail/exec -run '^TestMCPMailConformance$'` - `bash -n contrib/mail-scripts/gc-mail-mcp-agent-mail` - `shellcheck contrib/mail-scripts/gc-mail-mcp-agent-mail` - `make test-fast-parallel` - `go vet ./...` - Active pre-commit and pre-push hooks - Three-prong exact-diff council: correctness, maintainability, and test policy all approved ## Tracking - `ga-80po0c.25` --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Test User <test@test.com>
…s start under herdr (gastownhall#4349) ## Problem Any agent with MCP servers configured cannot run under the herdr session provider, and on-demand pool sessions hang in `start-pending` / `agent_not_found` forever. gastownhall#3837 shipped the herdr provider without wiring it into skill/MCP materialization, and three distinct gaps stack up: **1. herdr never executed `cfg.PreStart`.** Stage-2 skill/MCP materialization is delivered *as* a PreStart entry, so `isStage2EligibleSession` (cmd/gc/skill_integration.go) correctly holds out any runtime that doesn't run PreStart — the same reason subprocess is excluded. With `"herdr"` in neither eligibility allowlist, `resolveProjectedMCPForTarget` hard-fails every MCP-configured agent: ``` effective MCP cannot be delivered to workdir %q with session provider "herdr" ``` For pool sessions this error surfaces inside `buildDesiredState`, so the session is dropped from desired state and `provider.Start` is never called: the reconciler polls (`herdr agent get`) an agent that was never created (`herdr agent start` never issued), and the polecat sits in `start-pending` forever. **2. Ownership metadata was never readable.** The reconciler's pending-create ownership check (`runningSessionMatchesPendingCreateInfo`) reads `GC_SESSION_ID` / `GC_INSTANCE_TOKEN` via `Provider.GetMeta` on ticks that fire while `Start` is still delivering the startup nudge. tmux satisfies those reads for free — its `GetMeta` is tmux `GetEnvironment`, and `new-session` seeds the session environment from `cfg.Env`. herdr's meta store is a sidecar populated only by `SetMeta`, so the reads came back empty and the reconciler reaped every freshly started pool session seconds after a *successful* start: ``` session reconciler: rolling back pending create <wisp>: live runtime belongs to another session ``` **3. pre_start `chdir`'d into a workdir that may not exist yet.** A pool session's worktree is often created concurrently with (or by) pre_start itself, so resume-path starts failed instantly with `chdir ... no such file`. ## Fix (one commit per concern) - **`fix(runtime/herdr): execute pre_start`** — implements PreStart in the herdr provider mirroring tmux (`runPreStart`/`runSetupCommand`): `sh -c` per entry, cwd from `GC_DIR`, process env + `cfg.Env`, bounded by `[session] setup_timeout` (wired through `New()` from the runtime registry, matching tmux), `ErrWaitDelay` treated as success for daemonizing commands, output tail attached to failures, failures fatal. With PreStart executing, herdr joins both eligibility allowlists (`canStage1Materialize`, `isStage2EligibleSession`) with doc-comment justification. - **`fix(runtime/herdr): seed GetMeta sidecar from cfg.Env + tolerate not-yet-created workDir`** — `Start` seeds the metadata sidecar from `cfg.Env` immediately after agent creation (before the long idle-wait window), honoring tmux's env-as-meta contract; later `SetMeta` calls still override per key. pre_start's cwd falls back to the city root when `GC_DIR` doesn't exist yet — the same fallback `effectiveWorkDir` already applies to the agent's own cwd (the injected materialize/project commands carry their target as an explicit `--workdir` flag and don't depend on cwd). ## Tests `internal/runtime/herdr/prestart_test.go` (runs commands in order, GC_DIR cwd, env passthrough, fatal failure with output tail + failing index, setup-timeout bound, default timeout, missing-GC_DIR fallback) and `seedmeta_test.go` (identity keys readable via GetMeta after seeding, SetMeta override, empty-env no-op). Plus herdr cases in `TestIsStage2EligibleSession`. ## Verification Live-tested on a real city with an MCP server configured, iterating until green: - Before: `herdr agent start` never issued for a slung pool polecat (captured via a herdr CLI shim); stuck `start-pending`. Removing the MCP server made it start — isolating the eligibility gate. - After commit 1: `agent start` fires and `Start` returns success — then the reconciler reaped it ("live runtime belongs to another session"). - After commit 2: pool polecat goes **ACTIVE** under herdr with MCP configured and claims its bead. ## Related - Depends conceptually on gastownhall#4342 (stale herdr socket read as "server running" — without it, the provider swap aborts before any of this runs). Independent code paths; either merges cleanly alone. - Complementary to gastownhall#4225 (ProcessAlive tree-walk): gastownhall#4225 fixes a liveness false-negative in `provider.go`; this fixes materialization + ownership metadata. No overlapping hunks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l#4413) ## Summary - makes `TESTING.md` the normative source for test placement, design, timing, and review - defines the one-risk/one-smallest-owner loop, testability refactors, conformance obligations, event-driven waits, failure-edge selection, E2E admission, and flake policy - sets the protected PR feedback objective while clearly separating policy targets from enforcement that exists today - corrects stale inventories, examples, provider interfaces, CI cadence claims, and test-double descriptions ## Current enforcement The document now distinguishes checked resource/runtime ledgers from work still owned by `ga-80po0c.4` (workflow timing) and `ga-80po0c.6` (executable E2E manifest). It also calls out current Playwright retry, coarse integration routing, live-inference cadence, and production-store conformance gaps instead of presenting them as solved. ## Validation - `go test -count=1 ./test/docsync` - `go test -count=1 ./internal/testpolicy/resourcecensus -run ^TestRepositoryLedgerMatchesCensusAndDocumentation$` - `go test -count=1 ./internal/testutil/providerledger` - `git diff --check` - repository pre-push fast suite: 8/8 shards passed ## Review Three delegated reviewers covered semantic usability, speed/failure policy, and repository accuracy/enforceability. Their concrete findings were incorporated before commit. Tracking bead: `ga-yfgl4b`.
## Summary - carry the assigned work-bead title through concrete resume and wake-known-identity pool requests - preserve the launcher's title-qualified worktree path during the claim-before-current-marker reconcile window - cover the exact cold-pool trigger shuffle observed in the supported-pack nightly artifact ## RCA Supported Pack Nightly run 29385443130, artifact 8331737677, launched pool session gpig-8m6 in `fi-kar-implement-owned-work`. Concurrent cold-pool demand temporarily rebound its metadata to another trigger while the provider stayed in its original cwd. When fi-kar was assigned back, the resume reconcile ran before `currently_processing_bead_id` was stamped. The resume request carried fi-kar's ID but omitted its title, so `poolTriggerWorkDir` derived nonexistent suffixless `.../fi-kar`. Ralph then failed its check while trying to chdir there. The same omission existed in wake-known-identity requests. PR gastownhall#4230 correctly protects same-trigger and marker-backed live retries, but this claim-before-marker seam needs the complete work-bead identity to reconstruct the launcher path. ## Verification - RED before fix: both regression tests reported an empty `WorkBeadTitle`; the resume case derived `.../fi-kar` instead of `.../fi-kar-implement-owned-work` - focused pool desired-state/trigger tests pass - focused tests pass under repeated and race-enabled runs - `go vet ./cmd/gc` - repository pre-commit hooks pass - `LOCAL_TEST_JOBS=8 make test-fast-parallel` passes - mandatory pre-push fast suite passes - independent five-axis review approved with no required findings No Ralph executor or workdir-preservation heuristic changes are included; the fix uses the existing `SessionRequest.WorkBeadTitle` seam and path-safe slugging.
## What this changes `gc dolt cleanup --force` now tracks Dolt data directories for data-dir-only SQL server processes and removes confirmed test-owned orphan directories after the process is reaped. Test startup also sweeps old, unheld `.dolt` store directories left by killed tests, which keeps stale temporary Dolt stores from accumulating across repeated local and CI runs. The sweep is deliberately conservative: it reuses the existing test-owned path allowlist, requires an old `.dolt` marker, and treats `lsof` scan errors as a reason to skip removal instead of guessing. ## Review notes - Deletion remains limited to test-owned config/data paths accepted by the existing guard logic. - The symptom-based sweep requires the age gate, `.dolt` marker, and no live `lsof` holder. - The main surfaces are `cmd/gc` cleanup/reaper code, `internal/doltorphan`, `test/dolttest`, the gastown integration test, and the resource-census ledger. - `docs/PROJECT_MANIFEST.md` is not present in this checkout; the release gate uses the deployer criteria and local `TESTING.md` gates. ## Test plan - [x] `go build ./...` - [x] `go vet ./...` - [x] `go test ./internal/testpolicy/resourcecensus/... ./internal/doltorphan/... ./test/dolttest/...` - [x] `go test -tags integration ./examples/gastown/... -run TestSweep_ReapsRealDoltDataDirAfterSIGKILL -count=1` - [x] `make test-fast-parallel` - [x] Release gate: [`release-gates/ga-trvdd9-1-dolt-reaper-datadir-gate.md`](release-gates/ga-trvdd9-1-dolt-reaper-datadir-gate.md) --------- Co-authored-by: quad341 <james@wordelman.name> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…ed work re-enters dispatch (ga-n2d.2) (gastownhall#3377) ## What When a worker session is reaped (dead-runtime or stale-session close) with work still assigned, `releaseWorkFromClosedSessionBead` already clears the assignee and reopens in_progress work. This adds: it now also **restores the work bead's pool route** (`gc.routed_to`, or `gc.run_target` for workflow-kind beads) when that route is empty, recovering the value from the closing session bead's own `template` / `agent_name` metadata. ## Why A polecat that finishes its bead and pushes its branch but **dies before completing the done-handoff** leaves the bead `open` with an **empty `gc.routed_to`** (a "handoff-orphan"). With no route, the pool demand probe (`bd ready --metadata-field gc.routed_to=<pool>`) never matches it, so no worker is dispatched — the completed work sits invisible and open indefinitely, and can block downstream beads. (Confirmed on a rig: two done-and-pushed beads stranded ~20h.) Existing `releaseOrphanedPoolAssignments` explicitly skips empty-routed beads — this closes exactly that gap. ## Behavior / safety - Routes the orphan back to the **dead worker's own pool template** (e.g. `<rig>/<pack>.polecat`), so it re-enters pool demand and a **fresh worker** re-attempts the (idempotent) done/handoff. It does **not** route to a merge/refinery role and cannot merge incomplete work. - Only fires on a **confirmed-dead / reaped** session (gated on `IsDeadRuntimeSession` + stop, or `!IsRunning` + startup-grace) — never touches a live worker's assigned work. - Restores only when the route is empty (`gc.routed_to == "" && gc.run_target == ""`); beads still carrying a route are untouched. Per-key metadata merge preserves `branch`/`gc.kind`/etc. Idempotent. ## Scope This is the Go **safety-net** half. The complementary **atomic done-handoff** (set the route on a clean done so the crash window shrinks) lives in the pack layer and is tracked separately. ## Tests 4 new table tests: restore-pool-route, restore-run-target-for-workflow, leave-existing-route-untouched, no-template-still-releases. Touched-scope tests green. ## Stacking Cut from `main`; self-contained and independent. Touches only `cmd/gc/session_beads.go` (+ its new test). No dependency on gastownhall#3373 or gastownhall#3366. Co-authored-by: Brandon Martin <b+git@heyomayeah.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d stream (adopts gastownhall#3718) (gastownhall#3931) ## Summary Adopts and supersedes gastownhall#3718 by @csells, carrying its provider-neutral structured transcript work forward and porting the UI from the retired dashboard to the current React/Vite SPA. This PR adds: - The typed `session.structured.v1` REST and SSE contract across supported transcript providers. - Provider-neutral message, tool, usage, thinking, interaction, and error projections. - React transcript rendering with snapshot, upsert, reset, pending, and degraded-state convergence. - Stable REST-to-SSE resume tokens, including empty, suffix, and interior paginated windows. - Go wire-level and Playwright Chromium end-to-end coverage. ## Maintainer hardening The adoption review additionally fixed: - Append-stable synthetic IDs for repeated id-less OpenCode and Gemini messages. - A required, closed provider-neutral tool-error category enum. - Sticky degraded dashboard state across heartbeat frames. - Shared `Last-Event-ID` precedence and generated-client header serialization. - Empty-page handoff using a bounded inclusive anchor upsert. - Interior paginated handoff using stable ID-anchored windows. - Cursor invalidation when a retained pagination anchor disappears after history rewrite. ## Rebase and review - Head: `774515714` - Base: `main` at `e025d64bc` - The five-commit `git range-diff` preserves the complete series: commits 1 and 3 remain patch-equivalent; commits 2, 4, and 5 differ only where regenerated API/dashboard artifacts incorporate current-main cockpit contracts. - Formal segmented Claude, Codex, and Gemini review completed; all merge-blocking findings were resolved. - Final merge simulation against current `main` is clean. ## Verification Green: - All affected Go packages and focused race tests. - 1,031 shared/frontend tests (152 shared + 879 React). - Spec CI and dashboard CI/check/smoke. - `go vet ./...` - `make check-docs` - Dashport Go end-to-end tests. - Playwright Chromium structured-transcript end-to-end test. - Pre-commit hook. - Fast test shards: 8/8. - Pre-push shards: 8/8. ## Follow-ups `ga-ju1u4d.6` and `ga-ju1u4d.8` track scoped watcher-readiness and generated-SSE runtime follow-up work. The deterministic reconnect path and production-browser transcript flow are covered and green here. ## Credit PR integration and dashboard port by @julianknutsen. Original structured-stream work from gastownhall#3718 by @csells; the adoption commit and this PR retain that provenance explicitly. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Chris Sells <csells@sellsbrothers.com> Co-authored-by: Eddie the Engineer <adopt-pr@gascity.com>
…ill-collision during deacon patrol [● P1 · IN_PROGRESS] (gastownhall#4396) Implements saitoc-fx5kqf
## What this changes Schema generation for Gas City config docs no longer recursively scans every non-hidden top-level directory in the worktree. Before this change, leaked scratch checkouts or abandoned worktree directories at the repository root could make the docgen comment walk parse thousands of unrelated Go files and push docgen tests toward timeouts under parallel test load. The docgen path now asks git for the tracked top-level directories at HEAD and only feeds those directories to jsonschema's comment extractor. Non-git roots, or roots where the git lookup fails, keep the previous walk-all-visible-directories behavior. ## Review notes - The main behavior is in `internal/docgen/schema.go`: `gitTrackedTopLevelDirs` plus the filter in `addGoCommentsFiltered`. - The regression test builds a disposable git repo with one tracked top-level package and one untracked `ga-leaked-worktree` directory, then verifies only the tracked package contributes comments. - The resource census changes are expected because the new test fixture invokes real git. The ledger mirror is updated in `internal/testpolicy/resourcecensus/census.go`, `test/test-resources.toml`, and `TESTING.md`. - This does not add a new runtime config knob or change schema output for committed source trees. ## Test plan - [x] `go test ./internal/docgen/... ./internal/testpolicy/resourcecensus/...` - [x] `make test-fast-parallel` - [x] `go vet ./...` - [x] Release gate: [`release-gates/ga-9ajrc0-docgen-tracked-dir-scan-gate.md`](release-gates/ga-9ajrc0-docgen-tracked-dir-scan-gate.md) --------- Co-authored-by: quad341 <james@wordelman.name>
## Summary Fixes monochrome Claude/Codex TUIs caused by `CI=1` leaking from the controller into a newly-created per-city tmux server and then into every pane. - Wraps only commands whose parsed executable basename is `claude` or `codex` with `env -u CI -u NO_COLOR`. - Classifies from `runtime.Config.Command` before prompt assembly, then wraps the final command, so provider aliases, empty legacy ProviderName, and long-prompt `sh -c` commands behave correctly. - Excludes Kiro/custom commands even when the launch family is `claude`; leaves OMP and other custom providers unchanged. - Applies at the shared `buildLaunchCommand` seam, so fresh starts and warm `respawn-pane` relaunches both get the same environment. - Does not manage a Claude `theme`; Claude documents `dark` as the default and supports `auto`, light, and custom user themes, so color support comes solely from removing leaked environment variables. ## Root cause evidence Claude Code's Ink/chalk `supports-color` returns color level 0 when `CI` is set without a recognized CI vendor variable. Isolated A/B on the same account/settings: - `CI=1`: 0 colored SGR escapes - `env -u CI`: 14 colored SGR escapes - `FORCE_COLOR=3`: 14 colored SGR escapes The live controller and tmux server both carried `CI=1`; a fresh pane after removing the server-global CI rendered color. `NO_COLOR` was a secondary leak, not the primary cause. ## Verification - `TestBuildLaunchCommandUnsetsColorKillersForInteractiveExecutables` pins Claude/Codex executable classification, provider aliases, empty legacy provider names, Kiro/custom exclusions, `/tmux-cli` behavior, and final long-prompt `sh -c` wrapping. - Real tmux integration test uses a unique fresh socket, an executable fixture named `claude`, explicit runtime `Env` values (`CI=1`, `NO_COLOR=1`, `CIRCLECI=true`), an atomic environment file, and a tmux `wait-for` lifecycle signal. The pane process has CI/NO_COLOR absent while preserving CIRCLECI. - With Homebrew ICU flags (`CGO_CPPFLAGS=-I/opt/homebrew/opt/icu4c@78/include`, `CGO_LDFLAGS=-L/opt/homebrew/opt/icu4c@78/lib`): full `internal/runtime/tmux` tests, real color integration test, `internal/hooks` tests, resource census test, affected vet, `make -s test-fsys-darwin-compile`, and `.githooks/pre-commit` all passed. Rebased onto current `upstream/main` (209ad3e). The four-file diff includes startup-path assertions because they close the create/respawn command regression. No live sessions or Qlandia configuration were touched. --------- Co-authored-by: a3ackerman <user.email=28374790+A3Ackerman@users.noreply.github.com>
) ## Problem `gc doctor` runs its checks sequentially with no per-check bound. One check that wedges — in production, `order-firing-current`, whose per-order `LastRunAcrossStores` store reads stall behind a saturated data plane — stalls the entire run indefinitely: no summary, no exit, and every check registered after the wedged one (import-state, jsonl-archive, MCP, rig coverage…) silently never runs. On a busy host this makes doctor unusable exactly when it's most needed, and the operator can't tell "doctor is slow" from "doctor is dead." Observed in production: doctor produced zero results past 150s while the first ~34 (config-layer) checks complete in under a minute; line-buffered capture + the check registration order pinned the wedge to `order-firing-current` under load. ## Fix - `Doctor.CheckTimeout` (zero = unbounded, preserving historical behavior for embedders): each check runs under a wall-clock bound. A check exceeding it is **abandoned** and reported as `StatusError` / `SeverityAdvisory` with `TimedOut: true` — advisory because the check's real outcome is unknown, so automation gates shouldn't fire on it; the run continues to the remaining checks. - Abandonment is race-safe: each bounded check runs against a context whose `Output` is a private buffer, flushed to the real writer on completion — an abandoned goroutine can never interleave writes with the rest of the run. `--fix` and `RenderExtras` are skipped for timed-out checks (unknown state / possibly still mutating). - `gc doctor --check-timeout` (default 60s, 0 disables). The `gc start` warm-up scan constructs its own Doctor and is unchanged. - `CheckResult.TimedOut` is exported for `--json` consumers. ## Tests - Wedged check (5s sleep, 25ms budget): abandoned in milliseconds, reported as timed-out advisory error, subsequent checks still run, report counts correct. - Zero timeout: unbounded inline behavior pinned. - Timed-out check: `--fix` not attempted. - Completed check's incidental `ctx.Output` writes still reach the real writer through the buffering. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Wldc4rd <charlie@thriva.app> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Eddie the Engineer <julianknutsen@users.noreply.github.com>
…townhall#4245) (gastownhall#4248) Fixes gastownhall#4245 (partially — see Scope note). ### Bug `beads.OpenStoreAtForCity` already computes a `BeadsDiagnostic` naming the preflight gate and reason whenever native-store eligibility fails and store selection falls back to the fork-per-op `BdStore` (which execs a `bd` CLI process — and opens 3 SQL connections — per store operation). But `cmd/gc`'s doctor wiring (`openStoreAtForCity` in `main.go`) only ever kept the opened `Store` from that result and discarded the `Diagnostic`. `BeadsStoreCheck` (`gc doctor`'s `beads-store` check) never saw it, so it can only ever report `✓ store accessible` — a city silently running the dramatically more expensive fallback looks identical to a healthy native-store city. The reporter measured ~27 `bd` forks/second (~80 SQL connections/sec) sustaining 1-4 Dolt cores for hours before the fallback was found via manual process-spawn sampling. ### Fix Added `openStoreResultForCity` alongside the existing `openStoreForCity` in `cmd/gc/cmd_doctor.go` — same underlying `openStoreResultAtForCity`, but preserving the `Diagnostic` instead of discarding it. Changed `BeadsStoreCheck`'s factory field from `func(string) (beads.Store, error)` to `func(string) (beads.StoreOpenResult, error)` and wired the new factory into `gc doctor`'s registration. After a successful open+ping, `Run` now checks `Diagnostic.Store == beads.BeadsStoreNameBdStore` (set only on the actual fallback path, confirmed by reading `internal/beads/factory.go`) and reports `StatusWarning` naming the gate and reason instead of `StatusOK`. `StatusWarning` never contributes to `gc doctor`'s blocking exit code (only `StatusError` with `SeverityBlocking` does — confirmed in `doctor.go`), so this is purely additive visibility, matching the issue's own "Expected" behavior. ### Validation - New tests `TestBeadsStoreCheck_WarnsOnBdStoreFallback` (asserts `StatusWarning`, message names the gate and reason, non-empty `FixHint`) and `TestBeadsStoreCheck_NativeStoreDiagnosticStaysOK` (inverse — a native-store diagnostic stays `StatusOK`). TDD RED confirmed against the pre-fix `Run` (both new tests written, the warning test failed with `status = 0 (OK), want Warning` before the diagnostic branch was added) → GREEN after. - All 8 pre-existing `BeadsStoreCheck` tests updated for the factory signature change (mechanical: wrap returned stores in `beads.StoreOpenResult{Store: ...}`) and still pass unchanged in behavior. - Full `internal/doctor` suite green. `cmd/gc` doctor/store/status-focused tests (`Doctor|BeadsStore|OpenStoreResult|CityStatus` filter) green. Full `cmd/gc` sharded suite (`GC_FAST_UNIT=1 test-go-test-shard ./cmd/gc 1 6`) green except one confirmed pre-existing, unrelated timing flake (`TestStopManagedCityForcesCleanupAfterTimeout`, `cmd_supervisor_test.go` — reproduces intermittently in isolated re-runs regardless of this diff; touches only managed-city stop/cleanup timing, disjoint from the beads-store diagnostic path this PR changes). - `go build ./...` and `go vet ./...` clean across the full workspace; `gofmt -l` clean on all touched files. ### Scope note This PR implements only the issue's suggested fix #1 (a `gc doctor` warning). Deliberately left out of scope: - Suggested fix #2 (`gc status` human-output line showing `store: BdStore (fallback: <gate>)`) — a separate command's output formatting, not required to close the "silent" problem since `gc doctor` is the primary operator health-check surface. - Suggested fix #3 (periodic re-preflight so long-lived processes can upgrade off the fallback once its gate clears) — a bigger lifecycle change to a supervisor/session-scoped process, not a same-day fix. - Surfacing `PreflightResult.RepairSteps` in the warning message — that data lives on `contract.PreflightResult`, not on the `BeadsDiagnostic` struct that reaches the doctor check; threading it through would touch `diagnosticFromPreflight` and widen `BeadsDiagnostic`'s shape beyond what's needed to make the fallback visible. Gate + reason (already on `BeadsDiagnostic`) covers the issue's core ask. Happy to follow up if useful. - gastownhall#4246 (the fallback's per-tick polling cost / caching) is a distinct, larger issue about reducing `BdStore`'s cost via cursors/caching — correctly filed separately by the reporter; not touched here.
## Summary - reuse the current Go test executable as the `gc` CLI instead of rebuilding the binary for this fixture - remove unused rig initialization from the city-only setup - preserve real managed Dolt startup, HQ schema verification, raw `bd create`, provider-store creation, runtime publication and cleanup, and both `gc-` prefix assertions ## Performance - focused local test body: 55.72s -> 22.54s - reduction: 33.18s, or about 59.5% (2.47x faster) - historical Blacksmith body: 15.17s The local environment has a v55 database with v53 code, so it falls back from the native store. These measurements demonstrate wall-time improvement only; they do not claim native-path validation. ## Validation - focused fresh-city and re-exec tests - test resource-census guard - `make test-fast-parallel` - `go vet ./...` - active pre-commit and pre-push hooks - two independent delegated reviews: approved with no blocking findings ## Scope Test infrastructure only. No production behavior or retry policy changes.
## Summary - extract the existing pool-death phase into `CityRuntime.reconcilePoolDeaths` - keep the `tick` call at the exact original position - let the two pool-death policy tests exercise that phase directly instead of traversing unrelated config reload, reconciliation, and store-opening work ## Performance - focused pair before: about 7.32s - focused pair after: about 0.01s - improvement: roughly 730x The extraction is mechanical and changes no production ordering, retry policy, error handling, hook behavior, or state transitions. ## Preserved edges - canonical rig environment reaches the death hook - partial session listings skip hook execution and preserve prior state - full `tick` coordination remains covered by the existing tick test inventory ## Validation - focused pair and five-run timing - test resource-census guard - `make test-fast-parallel` - `go vet ./...` - active pre-commit hook - two independent delegated reviews: approved with no required findings ## Scope One reconciliation phase and its two focused tests. No broader controller refactor.
… align, +TTL prune) (gastownhall#4281) ## What Publishes a per-session **run-map file at claim time** so external proxies can stamp `X-Gc-Run-Id` for run-scoped spend/cost attribution — restoring `manifold.spend` run_id fill (dead since the Jul-11 v55 skew day). Cherry-picks `c0ff9d217` from `feat/hook-runmap` (the minimal writer, 2 files) onto `main`, plus two adaptations. ## Why this shape `gc hook --claim` already resolves the run_id in hand (`beadmeta.ResolveRunID` of the just-claimed bead). `writeRunMap` publishes it to `${GC_RUNMAP_DIR:-/run/gc-manifold-runmap}/<session>.json = {run_id, bead_id, ts}` under each of the session's address keys (`GC_SESSION_NAME`, session-bead-id, `BEADS_ACTOR`). The proxy reads it by `x-manifold-affinity`. Because it writes the **in-hand run_id** and never reads the session bead back, it sidesteps two problems at once that blocked the old bead-pointer path: - the **v55 schema skew** on the work store (no `bd` read), and - the **wisp/graph-tier blindness** (no `bd`/`gc bd` reaches ephemeral graph-store session beads). Rewritten per claim keyed by session, so it tracks the *current* run even when one session completes multiple beads. ## Commits 1. `c0ff9d217` (cherry-pick) — the runmap writer + tests. 2. Default the writer dir to `/run/gc-manifold-runmap` to match what the deployed manifold proxy (`gc-manifold-proxy.go`, `GC_PROXY_RUNMAP_DIR` default) already reads — the two defaults previously disagreed so nothing was stamped. 3. **TTL prune** (`GC_RUNMAP_TTL`, default 48h): reap files not refreshed within the TTL so the dir stays bounded by the live session set instead of leaking one stale file per ended session (tmpfs clears `/run` only on reboot). 48h is generous enough to exceed the longest a live session goes between claims, so a working session is never pruned out from under the proxy. ## Tests `cmd_hook_claim_runmap_test.go`: per-key atomic write, empty-runID no-op, dir override, TTL parse/default/fallback, prune reaps-stale-keeps-fresh (and never touches non-`.json`), and prune-on-write. Build + vet + tests green. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Eddie the Engineer <adopt-pr@gascity.com>
## Summary
- inject the existing retry sleeper into root-store verification
- replace managed-Dolt and wall-clock traversal with a stateful
`beads.Store` double
- preserve the production path by passing `time.Sleep` at the sole
production call site
## Performance
| Scenario | Before | After |
| --- | ---: | ---: |
| root-store retry test body | 27.09s | effectively 0s |
The slice also removes three process-environment mutations from the
checked `cmd/gc` resource ledger.
## Coverage retained
The direct test proves the same contract at the policy boundary:
- the store fails twice and succeeds on the third `List`
- every attempt uses `ListQuery{AllowScan: true, Limit: 1}`
- the two retry delays are exactly 500ms
- production still supplies the real wall-clock sleeper
## Verification
- two independent delegated reviewers: APPROVE
- `GC_FAST_UNIT=1 go test -count=20 ./cmd/gc -run
^TestVerifyCanonicalBdScopeStoreReadyRetries$`
- `go test -count=1 ./internal/testpolicy/resourcecensus -run
^TestRepositoryLedgerMatchesCensusAndDocumentation$`
- `git diff --check origin/main...HEAD`
## Local hook note
The local pre-push fast sweep is currently blocked by 11 run-map tests
introduced on `main` by gastownhall#4281. All 11 reproduce on the exact parent
commit under inherited `umask 0002` and pass under `umask 022`; this
branch does not touch their source or tests. The branch was therefore
pushed with the local hook bypassed, while required GitHub CI remains
authoritative.
## Summary - extract only external issues-table scan-result classification into a pure helper - replace one real-Dolt negative test with a table-driven unit test for success, missing table, and generic scan failure - retain the real endpoint query and both existing real-Dolt project-identity composition tests ## Performance | Scenario | Before | After | | --- | ---: | ---: | | missing issues-table policy test body | 10.82s local / 7.00s CI | effectively 0s | The checked test-resource ledger also drops two subprocess sites, one subprocess-owning file, three environment mutations, and one slow-process gate. ## Coverage retained The unit edge pins: - nil scan result succeeds - exact `sql.ErrNoRows` produces the same trimmed-database missing-table message - any other scan error keeps the same contextual message and wrapped cause `TestVerifyExternalDoltEndpointRejectsProjectIdentityMismatch` and `TestVerifyExternalDoltEndpointRejectsMissingLocalProjectID` still start real Dolt and traverse `Ping`, `active_branch()`, `SHOW TABLES LIKE issues`, and project metadata reads. The production SQL query remains at the endpoint boundary. ## Verification - two independent delegated reviewers after rebase: APPROVE - focused mapping test at `-count=20` - both retained real-Dolt composition tests - checked resource-census/document synchronization - `go vet ./...` - changed-package lint and pre-commit hooks - `git diff --check` ## Local hook note The repository pre-push sweep remains blocked locally by the inherited gastownhall#4281 run-map tests under `umask 0002`; the exact failures reproduce on `main` and pass under `umask 022`. This slice does not touch that subsystem, so the branch was pushed with only the broken local pre-push hook bypassed. Required GitHub CI remains authoritative.
…im + trust it in run-detail (gastownhall#4435) The dashboard run-detail showed "session unresolved for this current node" for every step of every pool-routed run (0/524 execution instances resolved on maintainer-city). ## Root cause (two independent defects) 1. **Claim-time stamp never built.** The gastownhall#2843 design intends every work bead to carry a durable session back-reference so run-detail resolves the executing session after the transient Assignee is cleared on close. graphroute implements this for DIRECT routing but deliberately defers the POOL case to claim time — and `gc hook --claim` only ever stamped `gc.work_branch`, never `gc.session_id`, though `GC_SESSION_ID` is in hand at claim. 2. **Resolver gate rejects real ids.** `sessionIDRe` is a TS-supervisor port accepting only `gc`/`td`/`th`/4-letter prefixes; it rejects real OSS session-bead ids (`mc-`/`ga-`/`gcy-`), so even a live or stamped id resolved to nothing. ## Fix - `cmd/gc/cmd_hook_claim.go`: stamp `gc.session_id` + `gc.session_name` on the claimed work bead at claim time — one combined, compare-and-skip-idempotent write; stamped even with no worktree; skipped for control beads; best-effort (never fails the claim). - `internal/runproj/detail_sessionlink.go`: resolve the durable `gc.session_id` **first**, index-independently, so closed steps resolve to the correct session even after it leaves the active-only index; validated by a provenance-trusted `sessionBeadIDRe`. The legacy name/assignee fallback keeps the strict `sessionIDRe` gate, so a recycled pool-slot-name collision yields **no** link, never a wrong one. ## Review Adversarially red-teamed. A wrong-attribution P1 (recycled-slot byName) was found and fixed (durable-id-first precedence); a follow-up re-verify cleared all four attack angles (sibling-preassign stamps only Assignee; retry-clone staleness self-heals, tracked ga-se3gb5; garbage rejected). RED-confirmed tests for each. ## Validation `go build ./...`, `go vet`, `go test ./cmd/gc ./internal/runproj`, cold `make test-fast-parallel` (pre-push) — all green. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## Summary - Replace the redundant normal-binary process test with exact `go/build.MatchFile` checks and direct normal command-tree assertions. - Reuse the normal `gc` binary already built by `check-native-dependency-surface.sh` for symbol, literal, and help-surface checks. - Keep the tagged real-binary end-to-end test unchanged. - Bank the resulting subprocess and slow-process-marker reductions in the checked resource census. ## Assertion ownership | Risk | Owner after this change | | --- | --- | | Normal versus `productmetrics_testhook` file selection | Fast in-process `MatchFile` assertions for all six tagged/normal files | | Normal command tree contains `gc metrics` but excludes the testhook command | Fast in-process command-tree assertion | | Normal artifact excludes private symbols and literals | Existing native-dependency guard, using its one already-built binary | | Normal artifact help excludes the private command | Existing native-dependency guard with isolated `HOME` and `GC_HOME` | | Tagged artifact runtime contracts | Existing `TestProductMetricsTaggedBinaryProcessContracts`, unchanged | No production behavior changes. ## Timing and resource impact | Measure | Before | After | | --- | ---: | ---: | | Blacksmith normal product-metrics process test | 10.45s | approximately 0s test-body time | | Full normal `gc` builds across these checks | 2 | 1 | | Child processes in the fast Go test | 5 | 0 | | Tagged real-binary builds | 1 | 1 | The focused test passed 10 times in 2.453s package time. The native dependency guard passed in 17.64s and still performs exactly one normal build. ## Verification - Focused test, `-count=10` - `scripts/check-native-dependency-surface.sh` - Resource-census ledger and generated-table consistency test - Pre-commit lint, `go vet ./...`, and doc-sync checks - Two independent read-only council reviews of the final effective diff - `git diff --check`; `go.mod` and `go.sum` unchanged The broad local pre-push sweep also ran. Its affected gates passed; the remaining failures were the existing host-umask-sensitive run-map tests, which are unrelated to this diff and run in a clean environment in CI. Tracking: `ga-yrotsuu`
## Outcome Replace wall-clock coordination in the concurrent managed-Dolt starter proof with strict `flock`, `sleep`, and logical-clock doubles while continuing to execute the real materialized `gc-beads-bd` lifecycle script. The behavior is unchanged; the proof is faster, deterministic, and more mutation-sensitive. ## Exact edge > Lock acquisition exhausts all six attempts; the first concurrent-start observation is non-reusable; its managed probe reaches a query and fails closed; after one logical 500 ms wait the second observation is reusable on port 3311; PID 4242 and the adopted port are persisted; Dolt is never launched. ## Ownership map | Risk | Owning proof | | --- | --- | | Six start-lock failures, failed probe/query ordering, reusable second observation, PID/port persistence, no launch | `TestGcBeadsBdStartWaitsForConcurrentStarterSuccess` using the real lifecycle script and strict PATH doubles | | Real kernel `flock` and lock-file inode behavior | `TestGcBeadsBdStartDoesNotReplaceLiveLockFileInode` (unchanged) | | Readiness beyond the legacy 10-second window | `TestGcBeadsBdStartWaitsForSlowConcurrentStarterSuccess` (unchanged) | | Remaining-budget plumbing into `existing-managed` | `TestGcBeadsBdStartConcurrentWaitPassesRemainingExistingManagedBudget` (unchanged) | ## Measurements | Measurement | Before | After | | --- | ---: | ---: | | Focused test, local | 4.32 s | 0.17–0.25 s | | Focused test, CI baseline | 4.07 s | pending CI | | Repeated focused run | — | 10/10 in 4.29 s package time | Independent council measurement reproduced 4.28–4.36 s before and 0.17–0.25 s after. ## Resource ratchets | Scope | Resource | Before | After | | --- | --- | ---: | ---: | | All tracked test source | subprocess | 530 | 529 | | All tracked test source | fixed sleep | 440 | 439 | | Untagged test source | subprocess | 401 | 400 | | Untagged test source | fixed sleep | 286 | 285 | | Untagged Small debt | subprocess | 398 | 397 | | Untagged Small debt | fixed sleep | 286 | 285 | ## Verification - focused edge: 20 consecutive passes in correctness review - retained real-boundary owner quartet: pass - resource ledger consistency: pass - `git diff --check`: pass - pre-commit lint, generated-doc checks, `go vet ./...`, and docsync: pass - two independent read-only council approvals on effective diff `7ebe79acc338d85269ba0522aa13c2bcb32a7568f63558af748078dfee7c58ba` The full pre-push fan-out encountered the known host-umask `TestPruneRunMapReapsStaleKeepsFresh` failure plus a load-only product-metrics failure. The product-metrics owner passed 10/10 immediately in isolation, and the changed focused edge passed another 10/10; no product-metrics or run-map code is touched here.
## Outcome Move the import-state missing-lock and invalid-config assertions to their smallest owning seams, and remove a redundant full-doctor registration journey. This is behavior-neutral and test-only: one file changes, with no production, policy, ledger, or dependency edits. ## Assertion migration | Retired assertion | Smallest owner after this change | Retained composition owner | | --- | --- | --- | | Import-state check is registered for a valid city | `TestBuildDoctorChecks_NameSetUnchanged` plus `doctor_check_names.golden` containing `packv2-import-state` | Existing `doDoctor` compositions and `internal/doctor` register/run/render tests | | Missing `packs.lock` reports the import-state error and both repair commands | `TestImportStateDoctorCheckReportsMissingLockfile`, through the real read-only `packman.CheckInstalled` path | `TestDoDoctorFixConvergesWave1CityRootImportsThroughImportState` | | Malformed `city.toml` excludes the import-state check while retaining the core config check | `TestBuildDoctorChecksSkipsImportStateCheckWhenCityConfigInvalid` | Core `city-config` run/render coverage | The existing `TestImportStateDoctorCheckReportsInstallHint` continues to own detailed result and repair-hint formatting with an injected report. The new missing-lock owner deliberately does not stub `checkInstalledImports`, so the production integration with `packman.CheckInstalled` remains covered. ## Measurements CI baselines come from run `29697921488`; the three old journeys landed on separate `cmd/gc process` shards. | Edge | Before | After | | --- | ---: | ---: | | Valid registration journey | 7.22 s | removed as duplicate | | Real missing-lock state | 6.90 s | 0.00–0.01 s | | Invalid-config registration gate | 6.99 s | 0.00–0.01 s | The two new owners passed 10 repetitions in 2.52 s total package time, including `cmd/gc` TestMain overhead. The change removes about 21.1 seconds of aggregate CI test work and roughly 7 seconds from each affected shard. ## Verification - new direct owners, 10 repetitions: pass - retained `TestBuildDoctorChecks_NameSetUnchanged`: pass - broader import-state and builder slice: pass - retained full `doDoctor` convergence composition: pass - poisoned GC/BEADS path run: pass - resource census: pass, unchanged - `git diff --check`: pass - pre-commit lint, generated-doc checks, and `go vet ./...`: pass - two independent read-only council approvals on effective diff `02a3935e3586b66b69d08d5e340ed487523c95b87c70ff51a74c43511c0bf916` A pre-change local full-doctor measurement activated the host managed-Dolt leak guard, so the before table uses the successful like-for-like CI timing artifact rather than presenting that contaminated local run as a benchmark.
…n with SHOW COLUMNS (gastownhall#4272) ## Problem `repairIDDefault` probes `INFORMATION_SCHEMA.COLUMNS` once per repair table (`dependencies`, `events`, `wisp_events`) on **every native store open**. Dolt does not push the `WHERE` predicate into `INFORMATION_SCHEMA`, so each probe is a full catalog scan. Observed live on a shared fleet Dolt server during a polecat batch (load avg 64 on a 6-core host, Dolt ~77% CPU): `SHOW FULL PROCESSLIST` dominated by these `SELECT COUNT(*), COUNT(COLUMN_DEFAULT) …` probes. Measured on that server (idle): the catalog-scan probe costs **50.65 ms/op** vs **0.74 ms/op** for the equivalent `SHOW COLUMNS` (68×) — ×3 tables ≈ 150ms of server CPU per store open, eliminated. (Upstream beads made the same replacement for its content_hash probe in gastownhall/beads#4479, same rationale.) ## Fix Probe with `SHOW COLUMNS FROM \`<table>\` LIKE 'id'` and read the `Default` cell directly. Semantics are identical: NULL Default → same idempotent `ALTER`; present Default → no-op; absent column → no-op; absent table (now surfaced as error 1146 / "table not found" instead of zero rows) → tolerated via `isTableNotExistError`, covering both the go-sql-driver error type and the embedded driver's message shape. Verified against dolt 2.1.10: intact expression default shows as `(uuid())`, stripped default as NULL, missing table errors `table not found`. ## Tests New `TestRepairIDDefaultAgainstDoltServer` (integration tag) runs the probe + repair end-to-end against a real throwaway `dolt sql-server` over the same wire protocol the fleet uses: stripped default detected and repaired, intact default untouched, absent table and id-less table tolerated. The pre-existing `TestNativeDoltStoreEventsIDDefaultRepair` continues to cover the repair through the vendored storage handle where that handle exposes a raw DB. `./internal/beads` unit suite green (1106 tests). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Eddie the Engineer <julianknutsen@users.noreply.github.com>
…e to the worktree reaper (gastownhall#4655) ## Summary - Bead: ga-vzt5pq.1 (implements FR-1/FR-2/FR-3/FR-5/FR-7 + NFR-1/NFR-3/NFR-5 from ga-vzt5pq's design) - Before reaping a closed-bead worktree at path P, batch-queries the rig's bead store for ANY bead in ANY molecule whose `gc.work_dir`/`work_dir` metadata equals P, and protects the worktree if any match is non-terminal — fixes cross-molecule worktree reuse, where a bead in a different, unrelated molecule can still be actively using a path whose nominal owner molecule already closed. - Adds a config-driven freshness quarantine (`AutoReapClosedBeadWorktreesMinAgeMinutes`): a worktree younger than this is exempt from reaping regardless of other gates, computed from the `.git` pointer file's mtime, fails closed if unstattable. - Extends `reapDecision.Reason` to name the referencing bead ID when protecting via borrow-veto, matching the existing liveness/git-state gate reasoning detail. - Rebased cleanly onto the now-merged liveness-gate base (PR gastownhall#4598 / ga-e2g9do); no enable flag needed — strictly additive protection gated by the existing `AutoReapClosedBeadWorktreesEnabled`/`DryRun` switches. ## Test plan - [x] 26/26 reaper-related tests green (`TestReapClosedBeadWorktrees*`, `TestExtractBeadIDFromWorktreeName*`, `TestIsStrictlyUnderDir*`) - [x] Full `internal/config` suite green - [x] `go vet ./...` clean - [x] `make test-fast-parallel` — all 8 shards green <!-- mpr:issue-refs v1 --> --- 🔗 **Maintainer cross-reference** — added by the gascity maintainers, no action needed from you: - Related to gastownhall#4492 — implements the daemon-side borrow veto and freshness quarantine proposed in part 2 of that issue's fix — the reaper now protects a closed-bead worktree when any non-terminal bead in any molecule still points at its path via gc.work_dir/work_dir metadata, and exempts worktrees younger than a configurable window; it does not cover part 1 (converging do-work worktree creation on the framework discovery root), publisher-owned self-removal, or the remaining reaper defects in part 3, and the veto checks the known work-dir metadata keys rather than every metadata key <sub>Linked for triage visibility — not auto-closing. If this looks off, just delete this block.</sub> <!-- /mpr:issue-refs --> --------- Co-authored-by: investigator <investigator@gascity.local>
## What If `CachingStore.SetMetadataBatch` returns an error, treat the backing outcome as unknown. The cache now advances the row mutation fence and marks the pre-write row dirty, without applying the proposed patch or emitting a success notification. The next ordinary read installs backing truth. This is an independent reconciler-safety extraction; it does not depend on PR gastownhall#4652 and adds no new abstraction. Tracking: ga-f7v2ft.64.1 ## TDD evidence RED before the production change: ```text ambiguity fence = seq:0 start:0 dirty:false local:false ``` The failure reproduced for rejected, partially committed, and fully committed backing outcomes. GREEN after the seven-line production change: - All `TestCachingStoreSetMetadataBatch*` tests pass. - Focused race test passes. - Full `internal/beads` package passes. - All six fast `cmd/gc` shards pass. - `go vet ./...` and changed-package lint pass. `make test-fast-parallel` retains one unrelated environment failure in `internal/doctor/TestCustomTypesCheck_TableDrift`: the installed bd binary has `CGO_ENABLED=0` and cannot initialize embedded Dolt. The exact failure was already reproduced on pristine base for PR gastownhall#4652; no doctor, bd, or Dolt code is changed here. ## Scope guard Two files and exactly 100 added lines. The monolith version used 305 lines and a dedicated 295-line harness; this extraction uses the existing cache invariants and one table-driven test instead.
## What this changes
This documents the claim identity convention for pack authors: Tier-1
recovery and claim commands should use the concrete running session
identity (`${GC_ALIAS:-$GC_TEMPLATE}`), while Tier-2 and Tier-3
discovery should continue to use the shared template route.
The main addition lives beside the existing prompt-template tier table,
with a short cross-reference from the session identity design note. That
keeps the rule close to the place pack authors already look when writing
prompt claim loops.
## Review notes
- This PR is docs-only in the Gas City repo:
`engdocs/architecture/prompt-templates.md` and
`engdocs/design/session-model-unification.md`.
- The related prompt-template changes are in the local-only
`gc-management` repo, which has no remote and cannot have a GitHub PR.
The merge authority has to handle that local merge separately.
- No Go code, config schema, generated docs, OpenAPI, or dashboard files
change here.
## Test plan
- [x] `make check-docs`
- [x] Local pack-branch acceptance checks: remaining bare `$GC_TEMPLATE`
matches are only Tier-2 `bd ready --assignee` lines; 37
concrete-identity replacements present
- [x] Local pack-branch TOML parse check for
`packs/actual/deployer/formulas/mol-deployer-gate.formula.toml`
- [x] Release gate:
[`release-gates/concrete-identity-claims-gate.md`](release-gates/concrete-identity-claims-gate.md)
---------
Co-authored-by: quad341 <james@wordelman.name>
…astownhall#4490) Fixes gastownhall#4488. Five documentation defects in `internal/bootstrap/packs/core/skills/`, all re-verified against the running binary immediately before this PR (`go version -m $(which gc)`: `vcs.revision=730c9b2e0a99e29dc9aefc1ec58b14d8da1b36ef`, `vcs.modified=false`). 1. **Dangerous, in gc-dispatch/SKILL.md** — `gc convoy check`/`gc convoy autoclose` descriptions were inverted. `check` takes no id and is an unscoped city-wide auto-close mutation; `autoclose` is the scoped one requiring `<bead-id>`. A reader who copies the doc's `gc convoy check <id>` gets an argument error, and the doc's own `autoclose` line (no id) models "fix" as dropping the argument — which yields the unscoped sweep under the name that reads as a safe check. Swapped the descriptions, fixed the arg placeholders, and marked `check` as mutating. 2. **gc-work/SKILL.md** — documented a claim path (`gc hook show <agent>`, `gc agent claim <agent> <id>`) whose subcommands don't exist. Replaced with the real `gc hook --claim` path, and fixed two more dead flags in the same section (`--label`/`--note` → `--add-label`/`--append-notes`), plus a race caveat on `bd update --claim`. 3. **Four more dead flags/commands**: `gc dashboard --port` (no such flag — replaced examples with real ones: `--no-open`, `serve`), `gc order check <name>` (takes no name), and a `gc skills dashboard` reference (top-level command is `skill`, not `skills`, and no `dashboard` subcommand exists under it either — pointed at the gc-dashboard skill by name instead). 4. **gc-dashboard/SKILL.md self-contradiction** — the per-city `[api]` port section didn't note that supervisor mode overrides it, which contradicted the "per-city `[api]` ports are ignored" statement later in the same file. Added the precedence note where the config is first introduced. 5. **gc-mail/SKILL.md** — `archive`/`delete` were presented as routine operations with no indication that both permanently delete the underlying bead (they're the same operation under two names; there's no reversible "put this away" path). Added an explicit warning and pointed at `mark-read` as the non-destructive alternative. Also documented three formulas that ship in the core pack but were missing from gc-dispatch/SKILL.md's formula catalogue (`mol-prompt-synth`, `mol-review-quorum`, `mol-scoped-work`) — a smaller sixth item from the same issue. **Verification**: `go test ./internal/bootstrap/packs/core/... ./internal/config/... ./internal/doctor/... ./internal/materialize/... ./internal/validation/...` all pass. Not in scope for this PR: `gc mail delete --help`'s own description text (in `cmd/gc/cmd_mail.go`) also undersells what the command does — the issue's "sharper half" — but that's a code change, not a skill-doc fix; flagging it here in case a maintainer wants it as a follow-up. <!-- mpr:issue-refs v1 --> --- 🔗 **Maintainer cross-reference** — added by the gascity maintainers, no action needed from you: - Related to gastownhall#4422 — documents in the gc-mail skill that `archive` and `delete` are the same operation and both irrecoverably destroy the message's underlying bead, and points readers at `mark-read` as a non-destructive alternative; this is a docs-only change — the destructive behavior itself, and the absence of a safe drain verb inside the `gc mail` namespace, are untouched <sub>Linked for triage visibility — not auto-closing. If this looks off, just delete this block.</sub> <!-- /mpr:issue-refs --> --------- Co-authored-by: Jacob Hausler <jacob@hausler.cc>
…nhall#4658) Fixes `registry-sfn`. The pack registry now serves community packs under **scoped** names (`owner/pack`), but rig include-list resolution rejected any slash-bearing token *before* it ever looked the name up — so `--include alice/foo` silently resolved as a local directory path instead of the registry pack. The failure was a confusing "not found" or a *wrong local pack*, never a clear error. Before scoping, every pack name was single-segment, so "contains a slash" was a safe proxy for "this is a path". Scoped names broke that assumption. ## The obvious fix is a no-op — worth knowing why Flipping the grammar check alone changes **nothing observable**: every bundled pack name is single-segment, so `alice/foo` still falls through to a broken `./alice/foo` local import, and *no test can fail on revert*. So this also adds the registry-catalog lookup that fix implies, behind a nil-optional `rig.Deps.ResolveRegistryPack` seam. `cmd/gc` implements it read-only over the on-disk registry caches — no fetch, no config write, so `gc rig add` stays offline. (Also: the bead points at `cmd/gc/cmd_rig.go:684`, but that resolution has since moved to `internal/rig/imports.go`. Same code, same bug.) ## Classification and precedence A token is a pack-*name* candidate only if it matches `packregistry.ValidatePackName` — the existing grammar, reused rather than copied a fourth time. Precedence is now documented in the function comment rather than incidental: 1. `[packs]` entry (raw token or `packs/`-stripped) 2. real local pack in the city (`<city>/<tok>/pack.toml`) 3. bundled builtin matching the `packs/`-stripped name 4. exact name in a cached registry catalog 5. verbatim fallback (path / URL) Two ambiguities decided deliberately: **local content beats the registry** (a directory you can see and edit must never be silently swapped for a fetched pack), and **builtins beat the registry** (a published pack cannot shadow a name shipped in the binary). Two extra refusals: a token that *declares* itself a path (`./x`, or the documented city-local `packs/<name>`) is never read as a scoped name — so a registry owner segment literally named `packs` cannot reinterpret existing include lists — and *any* existing directory at that path blocks registry resolution, even without a `pack.toml`. Requiring `./` for local imports was rejected outright: it breaks every existing bare-directory include. ## Compatibility The registry step is appended **after** every existing step, so no existing decision changes. A bare builtin, `packs/<builtin>`, `./<builtin>`, a `[packs]` key, and a local pack directory all take the same branch they took before. **Zero existing test expectations changed** — `TestDoRigAdd_WithPack`, `TestRigAddIncludeCanonicalizesBuiltinPackSource` and `TestRigAddIncludePrefersConfiguredPackOverBuiltin` pass unmodified. That's the compatibility evidence that matters. ## Verification Red→green proven by restoring the original slash gate: the end-to-end failure is the bug verbatim — `rig import sources = ["./wespd/cacc-twin-team"]` persisted as a local import. `gofmt` clean · `go build ./...` · `go vet` · `golangci-lint run` (v2.12.0, the Makefile pin) **0 issues** on both touched packages · `go test ./internal/rig/... ./internal/packregistry/... ./test/docsync/...` · full `GC_FAST_UNIT=1 go test ./cmd/gc/` **765s ok** · `make check-core-boundary check-native-dependency-surface check-eventexport-isolation` · genschema drift-clean. All under the Makefile's `env -i` discipline to match CI. `internal/rig` now imports `internal/packregistry`; no cycle, `check-core-boundary` passes. **Pushed with `--no-verify`**: the pre-push hook's parallel suite kept being killed by the tooling's timeout rather than failing, and the verification above is a strict superset of it for the touched packages. CI re-runs everything here. ## Caveats, for follow-up rather than this PR - **Cache-only resolution.** A user who never refreshed a registry gets today's behaviour. Deliberate — `rig add` must not become a network op — but the fix depends on a warm cache. - **No version pin.** The legacy include→import conversion has no version channel, so a registry-resolved include writes a bare source that resolves latest at install. Identical to pasting the URL, but weaker than the registry's own `--version >=<latest>` suggestion. - **Ambiguity across registries** (same name, two sources) resolves to *unresolved* rather than a clear error, because `canonicalizePackIncludes` has no error channel. So the confusing not-found persists for that narrow case. - The remote `gc rig add --git-url` path resolves against the *server's* cache; wired for consistency but not exercisable here (no network egress). <!-- mpr:issue-refs v1 --> --- 🔗 **Maintainer cross-reference** — added by the gascity maintainers, no action needed from you: - Related to gastownhall#1396 — extends what `--include` accepts to registry pack names, including scoped owner/pack forms, in the same include-canonicalization code path that issue is about; it does not change how a bundled or `packs/<name>` token is handled, so the system-pack case reported there is untouched by this change <sub>Linked for triage visibility — not auto-closing. If this looks off, just delete this block.</sub> <!-- /mpr:issue-refs --> --------- Co-authored-by: Claude <noreply@anthropic.com>
…ga-n2d Gap C) (gastownhall#3373) ## Summary Reduces this PR to **Gap C only**: a one-time **startup sweep** that releases stale runtime session-name claims held by CLOSED configured named-session beads, so a freshly started controller/supervisor begins from a clean name index and on-demand respawn of a same-named session (refinery, witness, …) is not blocked by a pre-fix legacy claim inherited across a binary restart (the ga-n2d "refinery no-respawn" class). Rebased onto current `main`. ## What changed vs the original PR The original PR bundled two parts: - **Gap A — read-side lazy release** (`ensureSessionNameAvailableForSelfAndOwner` recognizing a closed bead by the full identity signal set). **Dropped** — superseded on `main` by gastownhall#3366 (`0c5c1b912`) plus the existing `ensureConfiguredSessionNameAvailable`, which already release a closed configured-named bead's name lazily via `wasConfiguredNamedSession` when the configured identity reclaims it. - **Gap C — startup sweep** (`ReleaseStaleConfiguredNameClaims`). **Kept** — still absent from `main`; the lazy path alone does not eagerly clean the name index for ownerless availability checks or `gc session list`, nor for legacy pre-flag beads whose identity survives only on an `alias` / `agent_name` / `template` (role) label. `configuredNamedIdentitySignalsMatch` is retained as the sweep's legacy-signal recognizer (its former Gap-A read-side use is removed). ## Behavior - Wired into `runController` and `reconcileCities`, **best-effort** — a sweep failure never blocks startup. The `IncludeClosed` query reads through the cache to the backing store, so it is effective regardless of cache priming. - Only **CLOSED** beads are swept; a live or asleep bead keeps its name. - A closed bead's claim is released only when its reserved `session_name` matches a configured named-session runtime name AND the bead is recognized as that configured identity (boolean flag, recorded identity, or a legacy alias/agent_name/template signal that resolves to it). ## Scope 5 files, +335 / -0 (purely additive on `main`): - `internal/session/name_claim_sweep.go` (new) — the sweep - `internal/session/name_claim_sweep_test.go` (new) — release (legacy/flagged) + preserve (live/ad-hoc) cases - `internal/session/named_config.go` — `configuredNamedIdentitySignalsMatch` helper - `cmd/gc/controller.go`, `cmd/gc/cmd_supervisor.go` — startup wiring ## Test `make test` green locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: test <test@test.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tring (gastownhall#4649) ## Summary `mapRunPhase` ORed a substring scan into the authoritative status check: ```go if i.status == "blocked" || strings.Contains(textForIssue(i), "blocked") { ``` `textForIssue` concatenates a step's title, description and metadata, so any run whose text merely **contains** the word — a verdict enum, a prompt, an instruction — was bucketed into the blocked lane. `mol-review-quorum` hits this on every run: its review step describes the verdict as `"pass, pass_with_findings, fail, or blocked"`, so mid-review quorum runs surface as **BLOCKED** in the dashboard Runs summary, and the operator is offered a claim-a-worker remedy that cannot apply to them. Hoisting the terminal check above this branch (already in `main`) fixed only the fully-closed case — an **open** run still mislabels, because it never reaches the terminal branch. This drops the substring scan so the blocked lane is driven solely by `status == "blocked"`. That's the invariant the codebase already states elsewhere, in `detail_displaystate_fixes_test.go`: > `"blocked"` is reserved for nodes the store itself marks blocked. `textForIssue` is retained for the `"review"` keyword path. ### How it was found Observed on a live city: completed and mid-review `mol-review-quorum` runs both showed in the blocked lane. The same root cause was independently diagnosed and fixed downstream before this PR; only the substring half is still outstanding on `main`, since `main` already has the terminal-check reorder (and the `rootID`/`gc.outcome=fail` labelling that came with it). ## Testing - [x] `make check` — every gate passes except one load-sensitive flake in `internal/productmetrics`, detailed below. Not caused by this change. - [ ] `make check-docs` — not applicable, no docs/navigation/link changes - [ ] `make test-integration` — not applicable; this is a pure projection/labelling change in `internal/runproj` with no runtime, controller, or workflow behaviour change Green: `fmt-check`, `golangci-lint run ./...` (**zero findings**), `go vet ./...`, `check-release-dist-ignore`, `check-routed-test-rows`, and the unit suite including `cmd/gc` (881s) and `internal/runproj` in full with goldens. **One possible upstream issue worth your attention, now filed separately as gastownhall#4653** — `internal/productmetrics`, the `DisableAndPurge` family, appears to be load-sensitive under `make test`'s `-p=4`. Across two full runs it failed on two *different* tests: - `TestDisableAndPurgeExactTokenConflictAndPeerCleanRecovery` — `control_unix_test.go:1386: purge error = productmetrics: disable-write-failed, want class "state-changed-concurrently"` - `TestDisableAndPurgeRejectsPeerSuccessorReplacedDuringCleanProof` The package passes **3/3 standalone**, and under `GOMAXPROCS=1`. The differing test names across runs suggest a genuine scheduling flake on a CPU-constrained machine (2 cores here) rather than anything to do with run-phase mapping. Filed as gastownhall#4653 with the mechanism analysis so it does not clutter this PR. <details> <summary>Two earlier local failures were my own environment, not upstream — retracted</summary> An earlier revision of this description reported four failures in `cmd/gc` (`pool_test.go:119`) and `internal/doctor` (`TestCustomTypesCheck_TableDrift`) as reproducing on unmodified `main`. They did reproduce, but the cause was entirely local: my `bd` binary had been built with `CGO_ENABLED=0`, so it could not open an embedded Dolt store and every test shelling out to `bd init` failed with `embedded Dolt requires a CGO build`. Rebuilding `bd` correctly (`CGO_ENABLED=1` **and** `-tags gms_pure_go` — the combination `make doctor-build` warns about) fixed all four. No upstream defect there; apologies for the noise. `cmd/gc` also initially exceeded `make test`'s `-timeout 15m` at 900.5s on this hardware; it now completes in 881s. Tight on 2 cores, but passing. </details> Three cases added in `phasemapping_blocked_status_test.go`: | Test | Before | After | |---|---|---| | open run whose step text only *mentions* "blocked" | **FAILS** (`phase = "blocked"`) | passes | | fully-closed run with the same text | passes | passes | | open run with a real `status == "blocked"` member | passes | passes | The first is the regression test proper — verified failing against unmodified `main` and passing with the change. The second documents the already-correct terminal behaviour so a future reorder cannot silently regress it. The third guards against over-correcting, asserting a genuine store-marked blocked member still drives the lane. Existing `runproj` goldens (summary + detail) are **unchanged** — their blocked fixture is a real `status == "blocked"` bead, not a text match. ## Checklist - [ ] Linked an issue — no issue exists upstream for *this* defect; the reproducer is the in-repo `mol-review-quorum` formula, whose verdict-enum wording is what triggers it, so it is self-evident from the diff. Happy to file one if you'd prefer it tracked. (gastownhall#4653 is referenced above but is an unrelated flake found while validating, not this fix.) - [x] Added or updated tests for behavior changes - [x] Updated docs for user-facing changes — none needed; no documented behaviour describes text-matched blocking - [x] Called out breaking changes or migration notes — none. The only behaviour change is that runs which merely mention "blocked" stop being reported as blocked. Any run genuinely marked `status == "blocked"` is unaffected.
…#4660) ## What this changes The test resource census now treats `testing.T`/`testing.TB` calls to `Setenv` and `Chdir` as auto-restoring helpers instead of ambient environment or working-directory debt. Direct process mutations through `os.Setenv`, `os.Unsetenv`, `os.Clearenv`, and `os.Chdir` continue to count. The checked `cmd/gc+untagged` environment/CWD baselines and generated testing ledger are lowered to the remeasured values, so migrations can adopt `t.Setenv` and `t.Chdir` without consuming the anti-growth ratchet. ## Review notes - Receiver classification remains type-based; there is no environment-key special case. - Unresolvable receiver bindings still fail closed. - The shared classifier feeds both repository census and reviewed-hermetic-body reachability. - No new resource type, scope, runtime behavior, or configuration surface is introduced. ## Test plan - [x] Differential regression proves `t.Setenv`/`t.Chdir` are excluded while aliased direct `os.*` calls still count. - [x] Full resource-census package and exact ledger/document synchronization pass. - [x] Repository-wide build and vet pass. - [x] `make test-fast-parallel` passes all eight jobs, including the real push hook. - [x] Release gate: [`release-gates/ga-lay45s-resourcecensus-testing-receiver-gate.md`](release-gates/ga-lay45s-resourcecensus-testing-receiver-gate.md) --------- Co-authored-by: investigator <investigator@gascity.local> Co-authored-by: quad341 <quad341@users.noreply.github.com>
…0p) (gastownhall#4661) ## Summary - Pre-push gate had no concurrency control: independent agents converging on the gate at the same time oversubscribed the box and manufactured red gates indistinguishable from real regressions (measured twice on 2026-07-25, load 88.07 with 5 concurrent `test-fast-parallel` runs + 2 gates + 1 `make test`). - `scripts/test-local-parallel` now acquires one of `PUSH_GATE_MAX_CONCURRENT` (default 2) numbered `flock(1)` slots under `<city_root>/.gc/gate-slots` before running any jobs, holding it for the invocation's entire lifetime. On contention it polls with a bounded wait (`PUSH_GATE_MAX_WAIT_SECONDS`, default 600s), printing current slot holders immediately so a queued agent knows it's queued, not hung. Exhausting the wait maps to `exit 75`, distinct from a real test failure. `GC_PUSH_GATE_NO_CAP=1` bypasses the cap for one invocation. - Adapted from `packs/maintainer-pr-review/scripts/run-lock-lib.sh`'s `mpr_acquire_global_slot` pattern. - The self-test (`scripts/test-push-gate-lock.sh`, 29 assertions) runs as a direct `test-local-parallel` job (`push-gate-lock-selftest`, wired into `fast` and `full` modes) rather than through a `go test` trampoline. A trampoline's `exec.Command` call would add a tracked subprocess occurrence to `internal/testpolicy/resourcecensus`'s baselines, including the `scope=all` audit row, which fails on any change (growth or shrinkage) with no per-file exemption available — so the self-test is driven as a plain shell job instead, following the existing `fsys-darwin-compile` precedent for non-`go-test` jobs in the same file. ## Deviations from the original design (documented in `ga-owh20p`'s bd notes) - FR7 not implemented: it assumed an existing bd claim-lease heartbeat mechanism that needed extending across the wait+run phases. Verified false — no such mechanism exists (`bd heartbeat` leases are node-local/ephemeral, never committed to Dolt). The underlying claim-staleness concern is tracked separately under `ga-aw5356`. - Mayor's test-local-job-count addendum (governing total shard concurrency across in-flight gates, not just gate count) deferred to a follow-up bead (`ga-g6h06h`, P2) rather than expanding this bead's scope further. ## Test plan - [x] `go build ./...` - [x] `go vet ./...` - [x] `bash scripts/test-push-gate-lock.sh` direct run — 29/29 assertions pass - [x] `go test ./internal/testpolicy/resourcecensus/...` — ratchet green, baseline unchanged (535/163, 396/112, 391/109) - [x] `go test ./scripts/...` — pass - [x] `./scripts/test-local-parallel fast` (real pre-push hook run) — all 9 jobs pass, including `push-gate-lock-selftest` --------- Co-authored-by: investigator <investigator@gascity.local>
…get (gastownhall#4664) ## Summary - Converts the remaining fixed hang-guard literals in `cmd/gc/cmd_stop_test.go` to the shared `hangBudget` constant / `awaitCond`/`awaitClose` helpers, matching the pattern established elsewhere in this sweep (ga-wbjjvx/ga-ezitr0). - Best-effort cleanup waits (not hang detectors) now use `hangBudget` directly. - Real hang-detector assertions now use `awaitCond`/`awaitClose` instead of a raw `time.After` race against the fatal path. ## Scope notes - Out of scope, left untouched: the sub-~200ms site, and the `cmdStop(..., N*time.Second, ...)` argument-feed sites — those are tracked separately under ga-5lsj2k. - Rebased onto current `origin/main` (5 unrelated commits landed since fork, none touching this file). ## Test plan - [x] `go build ./cmd/gc/...` - [x] `go test ./cmd/gc/... -run 'TestCmdStop'` — all pass - [x] `go vet ./cmd/gc/...` — clean - [x] Pre-push hook fast suite (`test-local-parallel fast`, 8 jobs) — all pass refs ga-m77au0 Co-authored-by: investigator <investigator@gascity.local>
…l#4669) ## What this changes Three `cmd_config_test.go` tests now set `GC_CITY_PATH` to their temporary city instead of relying on ambient upward `city.toml` discovery. This keeps the tests hermetic and prepares them for the later test-binary guard that will disable ambient discovery. There is no production behavior change in this PR. Explicit city-path resolution already precedes ambient directory discovery in the command startup flow. ## Review notes - The diff is test-only: three one-line environment bindings in one file. - The tests retain their existing temporary-directory and `clearGCEnv` setup. - The broader ambient-discovery guard is intentionally not included; the migration is landing in small batches first. ## Test plan - [x] `make test-fast-parallel` — all 9 jobs pass - [x] `go build ./...` - [x] `go vet ./...` - [x] All three changed `cmd_config_test.go` tests pass in a focused run - [x] Release gate: [`release-gates/ga-clpi8u-cmd-config-ambient-discovery-gate.md`](release-gates/ga-clpi8u-cmd-config-ambient-discovery-gate.md) --------- Co-authored-by: investigator <investigator@gascity.local>
…se name (gastownhall#4659) ## Summary Fixes `ga-vqs6xr`: pooled agent sessions (`max_active_sessions > 1`) got their trigger bead's `work_dir`/`gc.work_dir` metadata bound to the shared **base** qualified name instead of their own per-slot identity, on every reconcile tick that **rebinds** an already-existing pooled session to a new work bead (routine and frequent — not just first-create). ### Root cause In `realizePoolDesiredSessions` (`cmd/gc/build_desired_state.go`): - `qualifiedName := cfgAgent.QualifiedName()` is computed once, at function entry, from the base agent config — before any per-slot resolution. - The bind call `bindPoolSessionTriggerBead(bp, cfgAgent, qualifiedName, sbInfo, item.request)` used that stale base name for *every* pooled slot. - The correct per-slot identity (`manualSession` branch, or `poolDesiredRequestIdentity(cfgAgent, slot)`) was computed 12-16 lines *after* the bind call had already run. `bindPoolSessionTriggerBead` → `poolTriggerWorkDir` → `resolveConfiguredWorkDir` expands the agent's `work_dir` template using whatever qualified name it's handed. Because the stale base name was handed in, every pooled instance's session-bead metadata got bound to the **same** path whenever a reconcile tick reassigned a pooled session to a new work bead. This only manifests on **rebind**, not on a fresh multi-slot create: create- time planning (`selectOrPlanPoolSessionBead`/`poolTriggerMetadata`) already sets correct per-slot metadata, and a same-trigger preservation guard (`oldWorkBeadID == workBeadID`) protects the very first bind. It's the routine "rebind an existing pooled slot to new work" path that regresses. ### Fix Hoist per-slot identity resolution above the `bindPoolSessionTriggerBead` call, and pass the freshly-resolved `qualifiedInstance` instead of the loop-invariant `qualifiedName`. `cfgAgent` (not the deep-copied `resolveAgent`) is kept to match existing create-time precedent. The stale `qualifiedName` var is left as-is for the unrelated `fmt.Fprintf` error-log string. ### Verification - New regression test: `TestRealizePoolDesiredSessionsRebindPreservesDistinctWorkDirPerSlot` — red before the fix, green after. - `go test ./cmd/gc/... -run 'Pool'` clean. - Full sharded suite (`make test-cmd-gc-process-parallel`): 2 shard failures observed, both independently root-caused as pre-existing/ unrelated: - `TestBdRigWorktreeStoreConsistentAcrossRawBdGcBdAndProviderStore` — Dolt schema-init flakiness under load (unrelated subsystem), confirmed via differing failure symptoms across reruns. - `TestSendReloadControlRequestNoChange` — reconcile-timing flake under 6-way parallel contention; its injected fake `buildFn` never calls `realizePoolDesiredSessions`, and it passed 3/3 in isolation. - Pre-push `test-fast-parallel` also hit one transient failure (`TestDockerSessionProtocol` in the unrelated `scripts` package — a 10ms-poll-interval tmux/Docker timing test, confirmed unrelated by diff scope and 3/3 clean isolated reruns); the retried push ran all 8 fast jobs clean. - `go vet ./...` clean. - Checked for merge/file overlap against the bead's flagged PRs: gastownhall#4501 (merged, no file overlap) and gastownhall#4551 (open, touches `cmd/gc/build_desired_state.go` but in a fully disjoint line range, ~3944-4017 vs this change's ~2765-2790). ### Out of scope (per bead description, left to `ga-ighomh`) `SharedCwdGuard`, config validation for `max_active_sessions` without per-instance `work_dir` variance, and `gc session list` real-cwd display — tracked separately by `ga-ighomh` (P1, defense-in-depth/observability follow-up). ## Test plan - [x] New regression test fails before the fix, passes after - [x] `go test ./cmd/gc/... -run 'Pool'` passes - [x] `make test-cmd-gc-process-parallel` — clean aside from two independently-confirmed pre-existing/unrelated flakes (see above) - [x] `go vet ./...` clean - [x] Pre-push fast suite passes clean --------- Co-authored-by: investigator <investigator@gascity.local>
…all#4676) ## Summary - Normalize registry attribution into safe effective `tier` and `publisher` values; malformed or missing claims downgrade without rejecting the catalog. - Expose attribution consistently in `gc pack registry search` and `show`, in text output and schema-v1 JSON. - Stamp new pack releases with safe `community / Unknown publisher` attribution so generated catalogs are valid by construction. - Keep attribution presentation-only: it does not authorize installs or alter pack selection. ## Testing - [x] `make test-fast-parallel` on rebased HEAD via the normal pre-push hook (all 9 jobs passed) - [x] `go vet ./...` - [x] formatting and `git diff --check` - [x] focused release-stamp, catalog normalization, CLI entrypoint, text, JSON, and schema tests - [x] full local parallel lane: all feature-relevant unit and integration groups passed; REST shards 7 and 8 passed on isolated rerun after repairing a transient shared `bd` install race - [x] delegated five-axis pre-commit review: APPROVE, no required findings The full lane also reproduced pre-existing `TestSweep_ReapsRealDoltDataDirAfterSIGKILL` twice. It is unrelated to this diff and is tracked in `ga-em9pd`; the cause is context-canceled `lsof` output being treated as a completed nonzero result. ## Checklist - [x] No standalone issue is needed; this is the Gas City half of the coordinated Registry publisher-trust feature. - [x] Added or updated tests for behavior changes. - [x] Documentation impact reviewed; no existing command-output field reference requires an update. - [x] No breaking changes or migration steps. Registry schema remains version 1.
…l#4671) ## What this changes Seventeen command tests now set `GC_CITY_PATH` to the temporary city they already enter. Order show/history, event emission, formula preview, and formula version-check tests therefore select their fixture city explicitly instead of depending on an ambient upward search for `city.toml`. This is a test-hermeticity change only; production command behavior is unchanged. ## Review notes - The diff is 17 identical one-line additions across four `cmd/gc` test files. - The explicit city path is set immediately after each existing `t.Chdir` call. - This is batch 2 of the migration. The test-binary ambient-discovery guard is intentionally not included and must wait until every affected test file has migrated. - There are no config, API, wire-format, or migration changes. ## Test plan - [x] `go build ./...` - [x] `go vet ./...` - [x] All 17 directly affected tests - [x] `make test-fast-parallel` (all nine jobs) - [x] Release gate: [`release-gates/ga-e66rtz-ambient-city-discovery-batch-2-gate.md`](release-gates/ga-e66rtz-ambient-city-discovery-batch-2-gate.md) --------- Co-authored-by: investigator <investigator@gascity.local>
## Summary - Resolve the non-city push-gate fallback through the repository common Git directory. - Make sibling linked worktrees share one valid slot directory instead of trying to create a directory beneath their .git gitfile. - Preserve city-root precedence and normal-clone behavior. Tracks bead ga-3rd1m. ## Testing - [ ] `make check` (not run; the documented sharded fast gate and vet were run directly) - [ ] `make check-docs` (not applicable; no docs changed) - [ ] `make test-integration` (not applicable; no runtime, controller, or workflow behavior changed) - [x] `bash scripts/test-push-gate-lock.sh` (48/48) - [x] `shellcheck scripts/push-gate-lock-lib.sh scripts/test-push-gate-lock.sh` - [x] `go test ./scripts -count=1` - [x] `make test-fast-parallel` - [x] `go vet ./...` ## Checklist - [x] Linked bead ga-3rd1m - [x] Added a real two-linked-worktree regression and acquisition proof - [x] No user-facing documentation change required - [x] No breaking change or migration required
…paths (gastownhall#4674) ## What this changes Makes the `gc prime` session-hook tests, session-nudge tests, and formula-cook tests select their temporary city explicitly through `GC_CITY_PATH` instead of relying on an upward search from the process working directory. This keeps the tests hermetic and prevents an unrelated ambient city from changing their behavior. The shared formula test helper now accepts the working directory and exact city root separately. That preserves cwd-based rig selection while still making city resolution explicit. ## Review notes - This is test-only; no production command behavior changes. - `internal/formulatest.SetupHermeticCookEnv` changes from one path argument to separate `chdirDir` and `cityRootDir` arguments; its only two callers are updated here. - This intentionally does not add the test-binary ambient-discovery guard. Remaining migration batches must land before that guard is enabled. ## Test plan - [x] Run all 36 directly affected, indirectly affected, and guard-blind control tests in `./cmd/gc`. - [x] Run `make test-fast-parallel`; all nine jobs pass. - [x] Run `go build ./...` and `go vet ./...`. - [x] Release gate: [`release-gates/ga-ql2s5k-ambient-city-discovery-batch-3-gate.md`](release-gates/ga-ql2s5k-ambient-city-discovery-batch-3-gate.md) --------- Co-authored-by: investigator <investigator@gascity.local>
## Summary - Forward the documented push-gate bypass and tuning variables from `make test-fast-parallel` across its scrubbed `env -i` boundary. - Keep the environment scrub intact; an unrelated ambient sentinel remains excluded. - Extend the existing Make contract without adding another subprocess-census entry. Tracks bead ga-4bbeq. ## Testing - [ ] `make check` (not run; the relevant sharded inventory and vet were run directly) - [ ] `make check-docs` (not applicable; no docs changed) - [ ] `make test-integration` (not applicable; no runtime, controller, or workflow behavior changed) - [x] RED proof: focused contract failed on missing `GC_PUSH_GATE_NO_CAP` forwarding before the Makefile change - [x] `go test ./scripts -run TestTestFastParallelUsesSanitizedEnvironmentAndMachineAwareConcurrency -count=1` - [x] `go test ./scripts -count=1` - [x] Live linked-worktree proof: `GC_PUSH_GATE_NO_CAP=1 make test-fast-parallel` launched all nine shards instead of failing at `.git/gate-slots` - [x] Full non-cmd/gc core inventory with a pinned CGO-capable `bd` - [x] All six fast `cmd/gc` shards, push-gate self-test, and Darwin compile - [x] `go vet ./...` Host note: the wrapper run itself had one unrelated failure because another process replaced the global `bd` with a CGO-disabled build during the run. The exact failing doctor test and the complete core inventory passed with a pinned CGO-capable `bd`. ## Checklist - [x] Linked bead ga-4bbeq - [x] Added a regression for all four controls plus unrelated-variable exclusion - [x] No user-facing documentation change required - [x] No breaking change or migration required
## What this changes Go test binaries now refuse to proceed when a surviving Dolt-port environment variable matches the managed Dolt port of a city discoverable from their current working directory. Previously, the guard only recognized the static local port `3307`; tests launched beneath a live city could instead discover that city’s actual port from runtime state and escape the guard. The new check is additive. It keeps the existing environment-based arm, walks upward for the nearest `city.toml`, and reads that city’s `.gc/runtime/packs/dolt/dolt-state.json` with a minimal standard-library parser. This makes the comparison self-relative without introducing another fleet-specific magic port. ## Review notes - Scope is limited to `internal/testenv`; production command behavior and configuration are unchanged. - The runtime-state arm accepts only a positive JSON `port` and only adds refusal conditions. - Synthetic end-to-end coverage uses ports `19999` and `20000`, distinct from both `3307` and the fleet port used during the incident. - `GC_ALLOW_PROD_DOLT_PORT_IN_TESTS=1` remains the explicit opt-out for deliberate local-Dolt tests. - A separately executed production `gc` subprocess does not import `internal/testenv`; that known boundary is documented and remains out of scope. ## Test plan - [x] `go build ./...` and `go vet ./...` - [x] Focused ambient-city and legacy production-port tests (36 subtests) - [x] Full `internal/testenv` package and resource-census ledger-sync test - [x] `make test-fast-parallel` (9/9 jobs) - [x] Release gate: [`release-gates/ga-ceutvg-ambient-city-dolt-port-gate.md`](release-gates/ga-ceutvg-ambient-city-dolt-port-gate.md) --------- Co-authored-by: investigator <investigator@gascity.local>
## Summary - distinguish a controller that was definitely unavailable before request entry from a stop request that may already have entered - accept only the exact `ok\n` acknowledgement - fail closed after any post-connect write, read, timeout, malformed-response, or socket-identity ambiguity instead of starting direct provider/tmux cleanup - preserve legacy direct cleanup when no request could have entered This is an independently useful reconciler-adjacent correctness fix. It does not introduce the new reconciler or shadow-mode implementation. ## Why Previously, any non-`ok` result collapsed to “controller absent.” If the controller accepted the stop but the response was lost or malformed, the CLI could become a second shutdown owner and race the controller over session/provider cleanup. ## Verification - regression tests were written against the unsafe fallback and observed failing before the implementation - focused stop-client and caller tests pass - focused race tests pass - all `cmd/gc` fast shards pass - `make test-fast-parallel` passes - changed-package lint passes - `go vet ./...` passes - resource census and Darwin cross-compile pass - active pre-commit hook passes Requirement: `SESSION-RECON-012` Bead: `ga-f7v2ft.64.2`
…#4678) ## Summary Fresh provider sessions can otherwise reach an empty prompt after a context-cycle handoff: the handoff is durable, but ordinary mailbox injection waits for a later `UserPromptSubmit` hook that may never occur. Deliver explicitly marked auto-handoff mail in the managed `SessionStart` context instead. The change uses the existing handoff labels and the existing sanitized, priority-aware mail formatter. It archives only the messages that were actually delivered, and only after provider-hook output succeeds. ## Behavior - Given a managed `SessionStart` and unread mail carrying both auto-handoff delivery labels, when `gc prime --hook` writes startup context successfully, then the successor receives the handoff before its first user prompt and the delivered handoff is archived. - Given ordinary, already-read, or partially marked mail, it is not injected at `SessionStart`; the normal `UserPromptSubmit` inbox path is unchanged. - Given provider-hook output fails, the handoff remains durable and unread for retry. ## Why this is safe This does not change handoff, reset, or wake decisions. It only supplies durable continuation context at the `SessionStart` hook boundary. Continuation mail is deliberately read through beadmail because `gc handoff --auto` persists that class of mail there regardless of an independently configured ordinary-mail provider. ## Related work - gastownhall#1552 introduced `gc handoff --auto` for PreCompact handoffs. - gastownhall#2920 archives injected auto-handoff mail after successful delivery. - gastownhall#3762 is a related fresh-start handoff issue on the manual attach path; it is not fixed by this PR. ## Scope - `cmd/gc`: SessionStart hook context and regression coverage. - `internal/mail/beadmail`: explicit selector for delivery-marked auto-handoff messages. ## Testing - [x] `go test ./cmd/gc -run '^TestDoPrimeWithHook_DeliveredStartupPromptKeepsStepReminder$' -count=1` - [x] `go test ./internal/mail/beadmail -run '^TestCheckAutoHandoffsReturnsOnlyUnreadDeliveryMarkedMail$' -count=1` - [x] `go build ./cmd/gc/` - [x] `go vet ./...` - [ ] `make check` (CI) - [ ] `make test-integration` (CI runtime coverage) ## Checklist - [x] Related upstream work is linked above; no separate issue is needed for this narrow regression fix. - [x] Tests cover the delivery, exclusion, archive, and output-failure boundaries. - [x] No docs change is needed: there is no public CLI or configuration surface change. - [x] No breaking change or migration is required. --------- Co-authored-by: wbern <kenneth.bernting@me.com>
…ess (gastownhall#4012) (gastownhall#4137) ## Summary Adds an opt-in `[session] claim_holder_stall_timeout` for a desired, alive session that still owns in-progress work but has stopped reporting provider activity. The existing `progress_stall_timeout` remains claim-less only. A confirmed stale holder is fresh-restarted only when its provider is healthy. A new pool worker re-adopts the same canonical session bead and its existing in-progress work. ## Safety contract - Default remains disabled; no city changes behavior without the new timeout. - The claim read must succeed. Unknown ownership, human attachment/interaction, startup grace, and a known-unhealthy provider all suppress the destructive restart. - The pool minimum-floor exemption remains for truly idle workers, but cannot hide a real in-progress claim when the new policy is enabled. - Claim-holder and claim-less thresholds are independent, so a holder is not recycled at the shorter claim-less deadline. ## Verification - Serial focused and package suites: `go test -p=1 -parallel=1 ./cmd/gc ./internal/config ./internal/doctor` - `go vet ./...` - `make check-docs` and regenerated config schema/reference docs - Scoped changed-file lint: zero issues - Adversarial reconciler coverage proves stale recovery, default-off behavior, unknown claim fail-safe, red-provider suppression, independent thresholds, and two-pass pool re-adoption with the in-progress bead preserved. Addresses gastownhall#4012. Co-authored-by: wbern <kenneth.bernting@me.com> Co-authored-by: architect <architect@gascity.local>
Merges gastownhall/gascity origin/main (bccc52f) into the Voxist fork, spanning v1.3.5 -> v1.4.0. 30 conflicted files / 65 hunks resolved; every non-trivial resolution carries an inline MERGE INTENT note naming what was kept and why. Notable resolutions ------------------- internal/events/reader.go: both sides changed the same function's second return for different purposes — the fork renamed readFilteredTracked to readFilteredCore and used it for degraded-read warnings (vc-89s), upstream kept the name and used it for the archive seq-window set consumed by ReadFilteredWithInFlight. Both are load-bearing and neither is a superset, so the core now returns BOTH and three thin wrappers take what they need. cmd/gc/order_dispatch.go: orderTrackingHistoryIndexLimit stays at the fork's 2048 — it has no config override, so taking upstream's 256 would be an unescapable behaviour change on a fleet with a documented starvation incident (vp-cixi.6); settle it upstream via PR gastownhall#3961. defaultMaxOrderDispatchesPerTick lands at 5, not upstream's 4: 4 is the old starvation default, and TestOrderDispatchBudgetDefaultRaised guards that floor. 5 is the value NOTE(vc-wz5.4) itself named. cmd/gc/cmd_dolt_cleanup.go: protected-port set is now the UNION of the fork's live-state detection and upstream's recorded rig ports. Dropping the recorded ports left a port with no attributable live process unprotected in a DESTRUCTIVE path (SIGKILL + DataDir removal). Defects found in CLEAN merges (no conflict marker) -------------------------------------------------- 719 files auto-merged; intent-per-hunk covers only the 30 conflicts, and this fork's failure mode is silent loss in the other 97%. Found by build, vet and tests: - internal/api/server.go: same import merged twice - cmd/gc/cmd_nudge.go: upstream's clockless signature wired to the fork's clock-using body — did not compile - cmd/gc/dolt_project_id_test.go: 4 call sites kept, definitions deleted - internal/api/status_warm.go: the fork's wedged-leader escape forgot only the outer singleflight, so the retry it starts rejoins upstream's wedged inner storeHealthFlight — a no-op for exactly the case it handles - cmd/gc/status_provider.go: the fork's stale-while-revalidate path served last-known-good without marking the result partial - cmd/gc/api_state.go: rig containment compared a canonicalized target against a raw city root, rejecting valid rigs Regenerated, not hand-merged ---------------------------- OpenAPI/schema docs, the dashboard client, and the command census. The census manifest (productmetrics_command_census.json) is an INPUT, not an output: unioned by path (upstream 285 + 5 fork-only), with the fork's "gc provider quota" reallocated 195 -> 199 where it collided with upstream's runtime-heartbeat, and next_id bumped to 200. Resource-census baselines and the TESTING.md ledger re-derived from a fresh scan; CI policy hashes re-derived per pin (the nightly pin lands on the fork's prior value). Test state ---------- Build and go vet ./... clean. Of the failures on this tree, ~60 are PRE-EXISTING upstream macOS failures — reproduced on a clean origin/main worktree, caused by upstream's symlink resolution meeting /var -> /private/var, invisible to upstream's Linux CI. 8 of 9 genuinely merge-induced failures are fixed here. Known red: TestAgentImageRebuildsBDAndGCWithPatchedGRPC. Upstream's new agent image builds bd from a release URL and cannot consume the fork's TIME-BOXED commit pin (deps.env, ADR-0026 C5); repinning is not a drop-in because that commit is not an ancestor of beads v1.1.2. Tracked for WS-2c.
| if seq > uint64(math.MaxInt) { | ||
| total = math.MaxInt | ||
| } else { | ||
| total = int(seq) |
This was referenced Jul 27, 2026
Closed
Brings #105, #106, #107 and #108 onto the resync branch. #108 landed while this branch was open and raised the cwd census baseline 284->287 / 43->44 to make CI green. #105 landed too and fixes the same failure properly, by deleting the three t.Chdir calls in cmd_config_lint_test.go so the count genuinely returns to 284/43. With both merged, fork/main held a raised ceiling over a reduced count — inconsistent in the opposite direction, and against the ledger's own rule that "reductions must lower this baseline". Resolved to the correct values: - cwd baselines stay at the pre-#108 figures; the calls really were removed - catalog assertion is 195, not #108's 194 — the resync restores 4 fork-only runnable commands to productmetrics_command_census.json, which is an INPUT to the generator - TESTING.md ledger block and census.go kept in sync with the above Verified: internal/testpolicy/resourcecensus and the catalog round-trip both pass on the merged result.
…oard retirement) Clean merge, no conflicts. The 4607-file cmd/gc/dashboard tree is now gone from this branch too, matching upstream.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges
gastownhall/gascityorigin/main(bccc52f61) into the fork, spanning v1.3.5 → v1.4.0. 30 conflicted files / 65 hunks resolved; every non-trivial resolution carries an inlineMERGE INTENTnote naming what was kept and why.Resolutions worth reviewing
internal/events/reader.go— both sides changed the same function's second return for different purposes: the fork renamedreadFilteredTracked→readFilteredCoreand used the slot for degraded-read warnings (vc-89s); upstream kept the name and used it for the archive seq-window setReadFilteredWithInFlightneeds. Neither is a superset, so the core now returns both, with three thin wrappers.cmd/gc/order_dispatch.go—orderTrackingHistoryIndexLimitstays at the fork's 2048: it has no config override, so upstream's 256 would be an unescapable change on a fleet with a documented starvation incident (vp-cixi.6). Settle upstream via gastownhall#3961.defaultMaxOrderDispatchesPerTicklands at 5, not upstream's 4 — 4 is the old starvation default andTestOrderDispatchBudgetDefaultRaisedguards that floor; 5 is whatNOTE(vc-wz5.4)itself named.cmd/gc/cmd_dolt_cleanup.go— protected-port set is now the union of the fork's live-state detection and upstream's recorded rig ports. Dropping the recorded ports left a port with no attributable live process unprotected in a destructive path (SIGKILL + DataDir removal).Six defects found in clean merges (no conflict marker)
719 files auto-merged; intent-per-hunk covers only the 30 conflicts, and this fork's failure mode is silent loss in the other 97%. Found by build/vet/tests:
internal/api/server.go— same import merged twicecmd/gc/cmd_nudge.go— upstream's clockless signature wired to the fork's clock-using body; did not compilecmd/gc/dolt_project_id_test.go— 4 call sites kept, definitions deletedinternal/api/status_warm.go— the fork's wedged-leader escape forgot only the outer singleflight, so the retry it starts rejoins upstream's wedged innerstoreHealthFlight— a no-op for exactly the case it exists to handlecmd/gc/status_provider.go— SWR path served last-known-good without marking the result partialcmd/gc/api_state.go— rig containment compared a canonicalized target against a raw city root, rejecting valid rigsGenerated artifacts
Regenerated, not hand-merged. Note
productmetrics_command_census.jsonis an input, not an output: unioned by path (upstream 285 + 5 fork-only), withgc provider quotareallocated 195 → 199 where it collided with upstream'sruntime-heartbeat, andnext_id→ 200. Resource-census baselines and theTESTING.mdledger re-derived from a fresh scan; CI policy hashes re-derived per pin.Test state
go build ./...andgo vet ./...clean. 8 of 9 merge-induced failures fixed.Roughly 60 remaining failures are pre-existing upstream macOS breakage — reproduced on a clean
origin/mainworktree, caused by upstream's symlink resolution meeting/var → /private/var, invisible to upstream's Linux CI. Not introduced here.Known red:
TestAgentImageRebuildsBDAndGCWithPatchedGRPC. Upstream's new agent image builds bd from a release URL and cannot consume the fork's TIME-BOXED commit pin (deps.env, ADR-0026 C5); repinning isn't a drop-in because that commit is not an ancestor of beads v1.1.2. Tracked for WS-2c — deliberately not worked around, since quietly weakening a container-security test is worse than a visible failure.