📝 Gremlins Phase 3 digest: amendment after pre-build check
This commit is contained in:
@@ -590,3 +590,95 @@ Fixing POSIX beyond the seam (M14, a macOS process table, POSIX survival): hando
|
||||
| C20 | Release title `🤖 Spire 0.3.0: trained implementer, gremlins per block (spire:gremlins)` | the build plan's title with the old name |
|
||||
| — | An `!` injection whose command exits 2 (`where` on a closed platform) is untested: it may fail the skill load on Linux/macOS. Flagged for Phase 4 and the porting Igors; the text keeps the plain form (design §2). | `… where \|\| true` (may break the `Bash(uv:*)` allow match) |
|
||||
| — | WSL uv install only through the permission prompt (download and execute); otherwise the WSL check stops at inventory and interop | install without asking (not allowed) |
|
||||
|
||||
---
|
||||
|
||||
## Amendment after pre-build check (2026-10-16 18:44 +0200, the Athanor, `claude-opus-5-5[1m]`)
|
||||
|
||||
Source: `docs/workpad/reports/2026-10-16-19-gremlins-phase3-digest-check.md` (`52c5911`, checker `claude-opus-5-5[1m]`). Igor: apply B1 and A1–A12 exactly as stated, plus the `kill`/`expire` timeout note; everything else (C1–C20) stands. **This section overrides the sections above where they conflict.** Block owners read it first.
|
||||
|
||||
### B1. GateTests use a Windows-path fake platform (§4 "Tests")
|
||||
|
||||
- The fake closed platform is a `WindowsPlatform` subclass (or the real `PLATFORM` with `supported` and `describe` patched) with `supported = False`, `is_wsl() → True`, `describe() → {"name": "posix", "sys_platform": "linux", "wsl": True, "supported": False, "detach": "setsid", "override": …}`. Path handling stays Windows, so `--binary C:\…`, `--run C:\…` and `script_path()` work on the host.
|
||||
- `init` on a closed gate asserts `error == "platform not supported"` (not just exit 2).
|
||||
- **The gate check is the first thing `init` does**, before `state_dir_for` and any `norm_path`.
|
||||
- The pure unit tests `PosixPlatform().supported is False` (with `sys.platform` patched to `linux` and `darwin`) and `WindowsPlatform().supported is True` stay as written.
|
||||
|
||||
### A1. The gate also closes launches on an existing registry (§4, C11, §7.2)
|
||||
|
||||
- The dispatcher refuses `train`, `spawn`, `continue`, `rebase` and `tick` on a closed gate (exit 2, `error: "platform not supported"`, `reason`, `platform`), in the same place as the N3 refusal.
|
||||
- The tick inside `wait` and inside the supervisor launches no pings on a closed gate (`tick_pass` returns early, nothing written).
|
||||
- Athanor intake (§7.2): run `where` **first**, then adopt (`list`) if the run log has a `Gremlins:` line. If `where` is not ok, use fresh agents even when a state dir exists.
|
||||
- New `GateTests` case: a registry present (made with the gate open), gate closed → `spawn` exits 2 with `error == "platform not supported"` and no job entry is written.
|
||||
|
||||
### A2. C16 is narrowed (§5.3)
|
||||
|
||||
`kill_tree`'s verification drops a snapshot pid as dead **only** when one of these holds:
|
||||
|
||||
- the table (from the module-level `process_table()`) is **non-empty** and lacks the pid; or
|
||||
- the snapshot name is known (not `None`), the table's name for that pid differs, **and** `proc_ctime(pid)` is `None` (the unverifiable case, class (a)).
|
||||
|
||||
In every other case `record_alive` decides, as today. Tests (fake table, module-level patches): an empty table keeps the survivor; a snapshot name `None` keeps it; a differing name with a verifiable ctime leaves the decision to `record_alive`; the class (a) case (non-empty table, other name, ctime `None`) drops it.
|
||||
|
||||
### A3. N3 tests split (§5.1)
|
||||
|
||||
- Stored file present, `$CLAUDE_CODE_EXECPATH` unset, PATH without claude: stored path kept, the "could not re-resolve" warning shown, exit 0.
|
||||
- Stored file deleted: exit 2, `claude binary not found` (today's loud failure).
|
||||
|
||||
### A4. N3 re-resolves through the stored source only (§5.1, C14)
|
||||
|
||||
Re-resolve only through the source the stored path came from: `CLAUDE_CODE_EXECPATH` from `$CLAUDE_CODE_EXECPATH`, `PATH` from a PATH lookup. A `--binary` pin is kept. If the stored source gives nothing now, keep the stored path and warn. Never cross sources. Add a test: stored via EXECPATH, re-run with EXECPATH unset and a different `claude` on PATH → stored path kept, warning.
|
||||
|
||||
### A5. Path matrix row 3 (§3.4)
|
||||
|
||||
`C:` and `C:x` on `WindowsPlatform`: **refused**, as today ("cannot normalise path"). On `PosixPlatform`: refused (drive form).
|
||||
|
||||
### A6. C18 wording (§7.2)
|
||||
|
||||
The fallback line in athanor.md reads: "a fresh agent reads the code the blocks change and writes the trunk notes". The phrase "the code the phase touches" must not appear (G-text 1).
|
||||
|
||||
### A7. No version number in the platform wording
|
||||
|
||||
Release gating keeps 0.3.0 unreleased until Linux and macOS lift their gates, so no text ties "Windows-only" to a version.
|
||||
|
||||
- SKILL.md description (§7.1) and Platforms section, README row (§9.1): "Windows-tested; other platforms fail closed until tested (see Platforms)". Drop "Windows-only in 0.3.0" everywhere, including §7.3's implementation-skill line.
|
||||
- Gate reason (§4): "spire:gremlins is not tested on <sys_platform><, WSL> yet; use fresh agents for every block (see SKILL.md, Platforms)."
|
||||
- Release commit body (§9.4): "tested on Windows; Linux and macOS gated pending the platform handoff (<path>)".
|
||||
- Handoff §8.8 lists every place a porter updates when lifting a gate: `PosixPlatform.supported`, the gate tests, SKILL.md (description and Platforms), the README row, athanor.md's fallback line if wording changes, the handoff report itself, and the changelog of the release that ships it.
|
||||
|
||||
### A8. Three more routed text items (§2.6, §7.1, §7.7)
|
||||
|
||||
- (a) `preamble.md` no longer points at `plugins/spire/skills/implementation/references/run-log.md` (it does not resolve in other projects). Block 3.1 **inlines the handoff-note format** in `preamble.md`: the seven fields `Model`, `Start / end` (from `date`), `Done`, `Deviations from plan`, `Flagged for review`, `Left for later`, `Expected broken`, `Commits`, as a short bullet template.
|
||||
- (b) SKILL §6/§7: `stalled` together with `clock_jump` is a host suspend, not a hung gremlin; `wait` again before acting.
|
||||
- (c) SKILL §6: an action per failure reason. `model_refused` → the model id is not admitted (`availableModels`), the user must change settings. `usage_limit` → plan usage hit; stop launching, flag it, hand back. `overloaded`, `api_error` → transient; `continue` once later, else flag. `prompt_too_long` → the base is too large; re-train or rebase smaller. `is_error`, `exit_code`, `no_result` → read `raw/<job>.err` and the note, `continue` once, else flag. `detach_failed`, `launch_error`, `supervisor_error` → helper or host problem; flag it, do not retry blindly.
|
||||
- Add these three rows to the §7.7 checklist.
|
||||
|
||||
### A9. Vacuous `-forks` assertions (§2.7)
|
||||
|
||||
The existing `assertFalse(os.path.exists(… "-forks"))` lines (`test_forks.py:155`, `:934`, `:1011`, `:1079`, and any other literal state-dir suffix in the tests) must derive the path from `gremlins.state_dir_for(run)` (or `forks`' equivalent at the time of the change), never from a literal suffix. List them in the 3.1 handoff note.
|
||||
|
||||
### A10. Residue categories outside the skill (§2.8)
|
||||
|
||||
New category: **"Igor text (D4) and non-session meanings: leave untouched"**. It covers `plugins/spire/skills/igor/SKILL.md:66`, `igor/references/mindset.md:11`, `igor/references/harness-notes.md:3` and `implementation/references/superpowers.md:36` (repository forks). 3.1 neither edits these lines nor reports them as residue.
|
||||
|
||||
### A11. `where` catches path refusals (§4)
|
||||
|
||||
`cmd_where` catches a `GremlinsError` from `resolve_binary` (and from the binary's `norm_path`) into `binary.error` and `reasons`, so a closed-gate `where` always carries the gate reason and the full report. Test: `where --binary <a path the platform refuses>` → exit 2, `binary.error` set, the report's other keys present.
|
||||
|
||||
### A12. `platform.override` defined (§4)
|
||||
|
||||
- `override = (env set) and not PLATFORM.supported`. On Windows, `CliTests` assert `override: false` even though C13 sets the env.
|
||||
- `PosixPlatform.describe()` reads `self.supported`, never a literal, so lifting the gate is one change.
|
||||
- `platform_gate()` reads `PLATFORM.describe()` (and `PLATFORM.supported`), never `sys.platform`, so it passes the seam grep.
|
||||
|
||||
### Naming fix (check note on C12)
|
||||
|
||||
The porting override is **`SPIRE_GREMLIN_UNSUPPORTED_OK`** (singular prefix, like `SPIRE_GREMLIN_CHILD` and `SPIRE_GREMLIN_DETACH_*`). Every mention of `SPIRE_GREMLINS_UNSUPPORTED_OK` above means this name.
|
||||
|
||||
### Other check notes applied
|
||||
|
||||
- **`kill`/`expire` timeout** (check note on C16 (b)): SKILL §7 tells the Athanor to call `kill` and `expire` from Bash with a long `timeout` (600000, as for `wait`): `expire` kills its jobs one after another, each verify can take up to `KILL_VERIFY_S`, and the Bash tool backgrounds a call past its timeout.
|
||||
- No local variable may be named `platform` in `gremlins.py` (the module imports `platform`).
|
||||
- C15: set `parent_inactive` only when NEW is actually created, not on the `rebase_conflict` early return.
|
||||
- C13: the handoff (§8.3) says that a green suite on Linux says nothing about the gate; only `GateTests` cover it.
|
||||
- C17: Phase 4 must smoke the renamed helper before anything ships (the handoff and the run log say so).
|
||||
|
||||
Reference in New Issue
Block a user