mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
83e1dd0cb5
## Defect
Gas City materializes Codex session homes with project-local hooks. The
first
Codex process in an untrusted home can stop at the interactive
workspace/hook
trust dialog, leaving the agent pane alive but unable to take dispatched
work.
Codex persists two independent decisions in `$CODEX_HOME/config.toml`:
1. workspace trust under `[projects."<dir>"]`
2. one content hash per hook under `[hooks.state."<hook-key>"]`
Trusting a parent directory does not trust a session home, and the hook
digest
input is intentionally owned by Codex rather than reimplemented here.
## Change
`ao gc prepare` now discovers the Gas City directories that exist when
it runs
(city and rig roots, materialized agent homes, and materialized rig
worktrees)
and pre-seeds both trust layers for those exact targets.
- Hook identities and current hashes come from Codex's `hooks/list`
app-server
method.
- Returned hooks are restricted to the discovered targets; user- or
plugin-level hooks are never granted trust by this command.
- Explicit operator decisions are preserved. An untrusted workspace,
modified
hook, disabled hook, unusable hash, malformed response, or malformed
TOML
fails loudly rather than being rewritten or accepted as complete.
- The merged TOML is validated in memory and installed with the CLI's
durable
atomic writer while preserving existing permissions.
- `ao gc check` verifies the same values from local files only. It
starts no
Codex subprocess and writes nothing.
## Deliberate boundary
Discovery is filesystem-based. A home Gas City creates *after* `prepare`
is not
pre-seeded by an earlier invocation. `prepare` compares configured agent
identities with materialized homes and warns about missing homes,
including the
real dotted-name shape (`gastown.mayor` → `.gc/agents/mayor`). The
operational
rule is documented explicitly:
```text
prepare → start the city → prepare again → dispatch
```
This PR does not claim that one pre-start invocation covers future homes
or
that every future pane can never encounter a prompt.
## Evidence
Automated tests cover:
- value-based workspace and hook trust, including `enabled = false`
- malformed/unexpected `hooks/list` responses
- regular local `hooks.json` files that derive zero hook identities
(`{}`,
`{"hooks":null}`, and `{"hooks":{}}`), keeping `prepare` and `check`
aligned
- real TOML spellings, invalid merges, idempotence, and mode
preservation
- target filtering and derived hook-key fidelity
- subprocess-free `check`
- missing-home identity reporting for nested and dotted qualified names
- operation with no Codex binary
- package-wide HOME isolation
An isolated real-Codex smoke on a disposable Gas City home established
the
behavioral differential: with the home's trust entries removed, Codex
rendered
the trust dialog; after seeding the same home, it reached the composer
without
the prompt. This proves the existing-home mechanism, not future-home
timing.
Final recovery checks on commit
`a4b52b2354b9f96e5e10e07b2916339c87190bfc`:
```text
go test -count=1 ./internal/gcmaintainer
ok github.com/boshu2/agentops/cli/internal/gcmaintainer 11.943s
go test -race -shuffle=on -count=2 ./internal/gcmaintainer
PASS
go test -count=1 ./internal/testsupport
PASS
go vet ./internal/gcmaintainer ./internal/testsupport
PASS
scripts/check-test-home-isolation.sh
PASS
scripts/check-test-isolation.sh
PASS (raw os.Setenv remains at the 10/10 baseline)
GOCACHE=/private/tmp/agentops-gocache \
GOLANGCI_LINT_CACHE=/private/tmp/agentops-golangci-cache \
WORKTREE_DISPOSITION_CI_SKIP=1 \
./bin/ao gate check --full --workflow-coverage --require-workflow-parity
PASS (68/68 full/head checks)
GOCACHE=/private/tmp/agentops-gocache bash scripts/regen-all.sh --check
PASS
git diff --check
PASS
```
Recovery fixed the prior CI findings with `storage.AtomicWriteFile`,
package-wide
HOME isolation, and `json.Encoder.Encode`. The first repaired CI replay
exposed
one further ratchet: raw `os.Setenv` calls in the new `_test.go`
TestMain raised
the repository baseline from 10 to 12. The final commit moves that
one-time
setup into the existing shared test-support boundary, keeps environment
changes
outside `m.Run`, and teaches the HOME-isolation gate only the exact safe
helper
shape. CI will rerun on the exact pushed commit.