Skip to content

fix(session): make the remote-session bootstrap reachable and honest - #341

Merged
Jammy2211 merged 3 commits into
mainfrom
claude/mobile-performance-review-5qwv8r
Aug 26, 2026
Merged

Jammy2211 merged 3 commits into
mainfrom
claude/mobile-performance-review-5qwv8r

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

The Mind half of a mobile-performance review. Companion to PyAutoLabs/PyAutoBrain#289, which is already merged — this PR's firewall change depends on it (see Merge order).

The hook that never fired

Claude Code registers project hooks from the session's project directory. A session holding several organs clones them side by side under that directory, so the project directory is their parent: not a repo, no .claude/, no hook registered.

So in exactly the sessions holding the most repos, no repo's SessionStart hook ran at all, and the session came up on the container's Python 3.11 — one minor below the floor this organism set for itself and below every CI leg, with mypy and flake8 reading the interpreter and judging code against 3.11 rules. Nothing announced it; it surfaced as local-green/CI-red.

Measured, not inferred: running the hook by hand ~40s into a live session printed building /root/.pyauto/session-py312 and rebuilt all seven uv tools. Nothing had built it.

What changed

  • policy/session_start_hook.sh derives its repo from the hook's own location, not $CLAUDE_PROJECT_DIR, so session-python.txt is read from the repo that owns it rather than from a parent that has none.
  • On detecting the multi-repo layout it installs a workspace-root settings.json plus a fan-out that runs each sibling repo's hook, so the next session in the container starts correctly.
  • It unshallows the session's clones. A shallow clone makes git merge-base --is-ancestor report "not an ancestor" for a commit whose ancestry is merely absent, and the ship/close-out procedures act on that answer — already logged once in complete/2026/08/status-sh-repos-missing-source.md as an environment note. Observed here: PyAutoMind had 249 of 4398 commits.
  • Git history and hook reachability now run before, and independently of, the interpreter legs. A container that cannot build the venv still wants honest ancestry and a hook that fires next time. PYAUTO_SESSION_SKIP_PYTHON=1 is the documented seam the tests use.
  • The env file now also exports PYAUTO_ROOT.

scripts/session_bootstrap.sh is the other half — the door anything can knock on to fix the session it is already in. bin/pyauto-brain calls it before dispatch, so no /verb runs unbootstrapped. Its --check resolves each tool's shebang to report the interpreter it actually runs on, because a tool's own --version says nothing about that — and a 3.11 mypy is the whole problem.

Tenant firewall: seven entries dropped or narrowed

FIREWALL_ALLOWLIST shrinks. Each of those entries named the owner only because it hardcoded a workspace root under $HOME; PyAutoBrain#289 makes those consumers delegate to resolvers that name no absolute path.

Worth recording: the firewall check caught the first draft of that fix naming ~/Code/PyAutoLabs as a fallback — correctly, since an instance fact in organ code is precisely what caused the bug. The fallback proved redundant as well as wrong, so the list shrank instead of growing.

Merge order

Mind's firewall_gate.yml checks PyAutoBrain out pinned to main, and this PR touches scripts/repos_sync.py, so it triggers. Reproduced locally: 7 mismatches against the old Brain main, 0 against the merged one. PyAutoBrain#289 is merged, so this PR's first CI run lands against a main that satisfies it.

Also in this PR

draft/feature/pyautobrain/board_without_gh.md — the follow-up prompt for the eleven board legs that read GitHub through gh api and stay dark in a remote session, carrying the measurements so the next session need not re-derive them. Cross-linked with the board's small-nit catch-all; dashboard regenerated in the same commit.

Validation

  • 224 tests pass; lifecycle.py check and repos_sync.py --check both clean.
  • 8 new tests covering the layout that used to defeat the hook entirely, the fan-out's reach, and the shallow-clone lie — the last asserted against git itself, before and after. Four of them fail against the previous hook, confirmed rather than assumed.
  • Fictional fixtures only, per the tests/** KEEP-copy rule.
  • ruff clean on every file touched.

🤖 Generated with Claude Code

https://claude.ai/code/session_012PDoeCuecjutdnwkxsTqg7


Generated by Claude Code

claude added 2 commits August 26, 2026 13:40
A session holding several organs clones them side by side under the session's
project directory. Claude Code registers project hooks from that directory —
which is then their parent: not a repo, no `.claude/`, no hook registered. So
in exactly the sessions holding the most repos, no repo's SessionStart hook
ran, and the session came up on the container's Python 3.11: one minor below
the floor this organism set for itself and below every CI leg, with mypy and
flake8 reading the interpreter and judging code against 3.11 rules. Nothing
announced it; it surfaced as local-green/CI-red.

- `policy/session_start_hook.sh` derives its repo from the hook's own location
  instead of `$CLAUDE_PROJECT_DIR`, so `session-python.txt` is read from the
  repo that owns it rather than from a parent that has none.
- When it detects the multi-repo layout it installs a workspace-root
  `settings.json` plus a fan-out that runs each sibling repo's hook, so the
  next session in the container starts correctly.
- It unshallows the session's clones. A shallow clone makes
  `git merge-base --is-ancestor` report "not an ancestor" for a commit whose
  ancestry is merely absent, and the ship and close-out procedures act on that
  answer (already logged once in
  `complete/2026/08/status-sh-repos-missing-source.md`). Here that was 249 of
  4398 commits.
- Git history and hook reachability now run before, and independently of, the
  interpreter legs: a container that cannot build the venv still wants honest
  ancestry and a hook that fires next time. `PYAUTO_SESSION_SKIP_PYTHON=1` is
  the seam the tests use.
- The env file now also exports `PYAUTO_ROOT`.

`scripts/session_bootstrap.sh` is the other half — the door anything can knock
on to fix the session it is already in, which `bin/pyauto-brain` now calls
before dispatch. `--check` reports each tool's real interpreter (resolved via
its shebang; a tool's own `--version` says nothing about what it runs on).

`repos_sync.py`: seven tenant-firewall allowlist entries dropped or narrowed.
Each named the owner only because it hardcoded a workspace root under `$HOME`;
those consumers now delegate to the Brain's resolvers, which name no absolute
path at all.

Tests: 8 new, covering the layout that used to defeat the hook entirely, the
fan-out's reach, and the shallow-clone lie (asserted against git itself, before
and after). All four of the behavioural ones fail against the previous hook.

224 PyAutoMind tests pass; `lifecycle.py check` and `repos_sync.py --check` OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PDoeCuecjutdnwkxsTqg7
…ot read

The Brain board is the morning door and on mobile it is mostly blind: eleven of
its legs read GitHub through `gh api`, and a Claude Code remote session has no
`gh` at all. The 2026-08-26 work made that blindness visible rather than
green-and-wrong; this prompt is for closing it.

Carries the measurements so the next session does not re-derive them: gh absent,
MCP tools working but agent-only (a subprocess cannot call them), the injected
$GH_TOKEN refused at the proxy with an org-level message, git and api.github.com
otherwise fine. That combination is why "port the board to MCP" is a design
question rather than a substitution, so phase 0 is a probe and a decision
between three named options, not code.

Filed separately from brain_board_follow_ups.md, which is the small-nit
catch-all for the same board; cross-linked both ways. Sized `large` on the
sizing faculty's own read (score 9) rather than the medium first guessed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PDoeCuecjutdnwkxsTqg7
…ance-review-5qwv8r

# Conflicts:
#	dashboard.html
#	dashboard.md
@Jammy2211
Jammy2211 merged commit 713e35c into main Aug 26, 2026
4 checks passed
@github-actions
github-actions Bot deleted the claude/mobile-performance-review-5qwv8r branch August 26, 2026 20:07
Jammy2211 added a commit that referenced this pull request Sep 3, 2026
Jammy2211 pushed a commit that referenced this pull request Sep 3, 2026
mind: dashboard refresh on batches/**; dev batch stays collected-once, reviewed-once (#341)
Jammy2211 pushed a commit that referenced this pull request Sep 27, 2026
…profiling#342)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MwuV47ESjoLFM8MuFZjw2s
Jammy2211 pushed a commit that referenced this pull request Sep 27, 2026
…); dashboard regen

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MwuV47ESjoLFM8MuFZjw2s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants