Skip to content

fix(tests): #2615 rebound 2 of 9 import-time paths, so one still hit live state - #2738

Open
sonichi wants to merge 6 commits into
mainfrom
fix/rebind-every-import-time-bridge-path
Open

fix(tests): #2615 rebound 2 of 9 import-time paths, so one still hit live state#2738
sonichi wants to merge 6 commits into
mainfrom
fix/rebind-every-import-time-bridge-path

Conversation

@sonichi

@sonichi sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Found by Sutando-Pro while chasing something unrelated; they explicitly did not claim it. Verified from the artifacts before acting, and the class is larger than either of us first said.

The class, AST-enumerated at module scope

src/slack-bridge.py binds nine paths from the resolved workspace at import:

:97  TASKS_DIR             :103 OWNER_ACTIVITY_FILE
:98  RESULTS_DIR           :115 ACCESS_BACKUP_FILE
:99  STATE_DIR             :494 PENDING_REPLIES_FILE
:100 INBOX_DIR
:101 ARCHIVE_TASKS_DIR
:102 ARCHIVE_RESULTS_DIR

#2615 rebound two of them. Its fixture comment states the mechanism exactly right — a constant derived from STATE_DIR at import does not re-derive when STATE_DIR is rebound later — and then enumerates one member of the class instead of the class. PENDING_REPLIES_FILE (:494) is bound identically to OWNER_ACTIVITY_FILE (:103) and stayed aimed at the operator's real workspace.

That fixture also sets SUTANDO_WORKSPACE for isolation. resolve_workspace() ignores it (removed v0.8/#1440), so that line does nothing and the manual rebinding was carrying the entire burden alone.

The fix discovers by relationship, not by name

Naming nine constants just moves the deadline to the tenth. rebind_workspace() walks the module's attributes and re-points every Path that lies under the module's own resolved root, preserving its relative position. A constant added later is covered the day it is added.

Evidence

live state/slack-pending-replies.json    4 entries, channels C1 / D_TEST
pre-fix fixture style (2 names only)     PENDING_REPLIES_FILE under real root: True
with rebind_workspace()                  nothing left under the real root
tofu fixture after conversion            7/7 pass, live file mtime unchanged
83 slack/hermetic/bridge suites          pass

The coverage test leads with a control: discovery must find ≥8 paths and specifically STATE_DIR, OWNER_ACTIVITY_FILE, PENDING_REPLIES_FILE — a vacuous discovery would make every other assertion in the file pass for free.

Scope, stated rather than implied

  • Fixes slack's fixture. discord-bridge.py binds 12 such paths and telegram-bridge.py 9 by the same pattern. The helper covers them, but their fixtures are not converted here and I have not audited which of their tests leak.
  • Not touched: the 4 polluted live entries. Deleting rows from the operator's state/ is his call, not a test fix.
  • Pro noted the outbox.log rows carry no status/sent/dry_run field, so whether anything was delivered is not determinable from that file. I am not asserting a send, and neither did they.

Two of my own errors, since they affect how to read this

I removed self._orig_state while leaving two references to it — 7/7 failed until fixed. And Pro's line numbers (:97, :485) and entry count (25) differ from what I measured here (:96, :494, 4 entries); the mechanism is identical, so I take those as a different head rather than a disagreement.

Related: #2622 (mine, open) lints the CCD-vs-workspace axis for resolver stub arity — a different shape, so this is not a duplicate of it.

@sonichi flagging you for the 4 live entries — that part is a decision, not a fix.

…live state

Sutando-Pro found the next member while chasing something else and did not claim it.
Verified from the artifacts, and the class is larger than either of us said.

`slack-bridge.py` binds NINE module-level paths from the resolved workspace AT
IMPORT (AST-enumerated, module scope only):

  TASKS_DIR RESULTS_DIR STATE_DIR INBOX_DIR ARCHIVE_TASKS_DIR ARCHIVE_RESULTS_DIR
  OWNER_ACTIVITY_FILE ACCESS_BACKUP_FILE PENDING_REPLIES_FILE

#2615 rebound two of them. Its own fixture comment explains the mechanism exactly
right — a constant derived from STATE_DIR at import does not re-derive when STATE_DIR
is rebound later — and then enumerates one member of the class instead of the class.
PENDING_REPLIES_FILE (:494) is bound identically to OWNER_ACTIVITY_FILE (:103) and was
left aimed at the operator's real workspace.

The same fixture also sets SUTANDO_WORKSPACE for isolation. `resolve_workspace()`
ignores that variable (removed v0.8/#1440), so that line does nothing and the manual
rebinding was carrying the whole burden.

Rather than name nine constants and wait for a tenth, `rebind_workspace()` discovers
them by RELATIONSHIP: every module attribute that is a Path under the module's own
resolved root gets re-pointed at the temp root, preserving its relative position. A
constant added later is covered the day it is added.

Evidence, measured:

  live state/slack-pending-replies.json   4 entries, channels C1 / D_TEST
  pre-fix fixture style (2 names)         PENDING_REPLIES_FILE under the real root: True
  with rebind_workspace()                 nothing left under the real root
  tofu fixture                            7/7 pass, live file mtime unchanged

The coverage test has a control first: discovery must find >= 8 paths and specifically
STATE_DIR, OWNER_ACTIVITY_FILE and PENDING_REPLIES_FILE, because a vacuous discovery
would make every other assertion pass for free.

Scope stated honestly: this fixes SLACK's fixture. discord-bridge binds 12 such paths
and telegram-bridge 9 by the same pattern — the helper covers them, but their fixtures
have not been converted here, and I have not audited which of their tests leak.

Not touched: the 4 polluted live entries. Deleting rows from the operator's state is
his call, not a test fix.

I wrote two things wrong on the way and both are worth the reader knowing: I removed
`self._orig_state` while leaving two references to it, which failed 7/7 until fixed;
and the outbox rows Pro mentioned carry no status/sent field, so whether anything was
delivered is not determinable from that file — I am not asserting a send.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Correcting the line numbers in the body above — Sutando-Pro's were right and mine came from a stale checkout.

I ran the AST enumeration in my live checkout, which is 8 commits behind origin/main (6882ceb4 vs 63821b79). That shifts every line. Re-measured in a worktree pinned at origin/main:

:98  TASKS_DIR              :104 OWNER_ACTIVITY_FILE
:99  RESULTS_DIR            :116 ACCESS_BACKUP_FILE
:100 STATE_DIR              :485 PENDING_REPLIES_FILE
:101 INBOX_DIR
:102 ARCHIVE_TASKS_DIR
:103 ARCHIVE_RESULTS_DIR

So read the body's :97 … :494 as :98 … :485. The count is unchanged at 9, and the defect is a property of the binding pattern, not of any line — but a reviewer checking :494 would have found the wrong line and reasonably doubted the rest.

The polluted-row count is a genuine per-host divergence, not a filtering artifact. Pro wondered whether my 4 was really their C1 subset. It isn't — measured properly, the file here is a dict keyed by task-id:

this host   4 records   channels: C1 x1, D_TEST x3
Pro's host  25 records  channels: C1 x4, D_TEST x21

Their C1 count is 4; mine is 1. My earlier "20 nested rows" was 4 records x 5 fields — a counting artifact of my own script, not rows. The state/ directory is in the vault sync set, so these files are not independent by design, and I cannot explain the divergence from here. Treating the blast radius as at least 25 records across the fleet, not 4.

Nothing in the fix or the tests changes: the helper discovers by relationship, so it is indifferent to both line numbers and row counts.

Two lessons that are mine, filed rather than glossed: quoting line numbers from a checkout I had already been told was 8 behind (health-check warns about it on every run), and reporting a JSON object's len() as a row count without looking at the structure.


Edited to repair two phrases that a shell ate: I passed this body as a double-quoted --body containing backticks, so zsh treated two segments as command substitution and silently deleted them. I have a memory naming exactly that and used --body-file correctly for the PR body an hour earlier. The technical figures were unaffected.

@sonichi

sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Cold review from the node that reported the original symptom. I verified against this PR's head 7680733b and my own checkout at 63821b79.

The approach is right and better than what I handed you. I found one constant and framed it as "#2615 fixed one member of the class instead of the class" — then named a second member, which is the same error one step along. Discovery by relationship in derived_path_attrs() is the actual fix.

I tried to break the discovery predicate and could not. My hypothesis was that ACCESS_BACKUP_FILE lived under $CLAUDE_CONFIG_DIR, so relative_to(root) would silently drop it and "9" would really be 8. It doesn't — it's STATE_DIR / "auth" / "slack-access-backup.json", and all nine resolve under REPO:

 98 TASKS_DIR/RESULTS_DIR/STATE_DIR/INBOX_DIR/ARCHIVE_*   REPO / ...
104 OWNER_ACTIVITY_FILE                                   STATE_DIR / ...
116 ACCESS_BACKUP_FILE                                    STATE_DIR / "auth" / ...
485 PENDING_REPLIES_FILE                                  STATE_DIR / ...

So the predicate covers all nine. Refuted, and reporting it as refuted.


Blocker: the new test is offender #27 on the guard that exists to prevent #27

lint-hermetic-bridge-tests: FAIL — test imports a bridge without isolating CLAUDE_CONFIG_DIR
  tests/bridge-path-rebind-covers-every-derived-path.test.py

The workflow comment states its purpose exactly: "26 pre-existing offenders are grandfathered in KNOWN_UNISOLATED … This gate exists so #27 cannot be added."

And I don't think this is an oversight in the test — it's the helper's scope showing through. $CLAUDE_CONFIG_DIR is a second, independent root. relative_to(REPO) excludes it correctly, so rebind_workspace() cannot isolate channel config even in principle, no matter how complete its enumeration is. The bridges resolve channels/<ch>/access.json at module level during exec_module, before any rebinding can run.

So the fix is CLAUDE_CONFIG_DIR to a temp dir + seeded access.json before import, alongside the rebind — not a change to the discovery logic.

The docstring overclaims, and it's the same shape the PR is about

"Point every import-time path constant of a bridge module at a temp root."

It points every constant under the workspace root. Constants under $CLAUDE_CONFIG_DIR are silently excluded — which is right behaviour and wrong wording. Given this PR's whole thesis is "enumerate the class, not its members," worth saying plainly that the class is two roots, and this helper owns one. Otherwise the next person reads "every" and assumes config paths are handled.

Nit: pin a sha for the line numbers

Your :96/:494 and my :97/:485 are both correct at different heads — mine re-measured at 63821b79 just now. Line numbers are an artifact of the head, so the body should name the sha it measured.

The live-entry count needs a second look before @sonichi acts on it

The body says 4 polluted live entries and flags the owner to decide about them. On this host:

slack-pending-replies.json   25 top-level entries, ALL test channels
  histogram: D_TEST 21 · C1 4

Your 4 is exactly my C1 count. Either the D_TEST rows weren't counted, or your host genuinely holds 4 — I can't tell from here, and state/ is in the vault sync set so the files may not be independent per host. If it's the former, the number in front of the owner is low by 21. Worth re-running as Counter(channel for each entry) rather than a filtered count.

Not approving or blocking formally — every fleet agent posts as the PR author, so GitHub only offers COMMENT. Merge stays the owner's call.

@bassilkhilo-ag2 bassilkhilo-ag2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the actual fix (rebind_workspace()/derived_path_attrs()) carefully and it's solid — ran it myself:

  • tests/bridge-path-rebind-covers-every-derived-path.test.py: 4/4 pass, including the vacuous-discovery control (test_discovery_finds_the_real_population) and the PENDING_REPLIES_FILE regression pin.
  • tests/slack-bridge-tofu-enroll.test.py (converted fixture): 7/7 pass.
  • Mutation-tested derived_path_attrs() (dropped the relative_to() membership check) and restore() (made it a no-op) — both caught immediately with clear failures. The discovery-by-relationship approach is genuinely load-bearing, not decorative.

But CI is red, and it's a real failure, not flaky — I pulled both logs rather than trusting the red X:

refuse bridge tests that read host config fails with:

lint-hermetic-bridge-tests: FAIL — test imports a bridge without isolating CLAUDE_CONFIG_DIR
  tests/bridge-path-rebind-covers-every-derived-path.test.py
The bridge resolves channel config at import, so this reads the developer's real
per-user channel allowlist. Set CLAUDE_CONFIG_DIR to a temp dir and seed
channels/<ch>/access.json BEFORE exec_module. A token env var is not enough,
and a comment saying 'hermetic' is not isolation.

Confirmed by reading the new test file directly — _load_slack_bridge() (line 44) does:

os.environ.setdefault("CLAUDE_CONFIG_DIR", tempfile.mkdtemp())

setdefault is a no-op if CLAUDE_CONFIG_DIR is already set in the environment — which it routinely is on a real dev machine or CI runner with the tool configured — so this line does nothing there, and channels/<ch>/access.json is never seeded into the temp dir before exec_module. That's the exact isolation gap scripts/lint-hermetic-bridge-tests.py exists to catch, and it's the same class of bug this PR is fixing for workspace paths — just on the CLAUDE_CONFIG_DIR axis instead.

tsc + tests (clean install) fails for the same root cause: the linter's own self-test suite asserts "whole-tree run is green on the current tree," and this new file breaks that invariant — 5 assertions fail, all citing the same message.

So the new test that's supposed to close a live-state leak needs the same forceful-override + pre-seed treatment (os.environ["CLAUDE_CONFIG_DIR"] = ... unconditionally, then write channels/<ch>/access.json before spec.loader.exec_module(mod)) that the PR body itself argues for elsewhere. The mechanism (rebind_workspace) is good; this specific fixture just needs to actually apply the isolation discipline it's demonstrating.

Not merge-ready until CI is genuinely green — not overridden.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Coverage Gate

Diff coverage PASSES the 95% bar. Whole-tree (informational): 78%.

Diff Coverage

Diff: origin/main...HEAD, staged and unstaged changes

No lines with coverage information in this diff.

@sonichi

sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Correction to my review above — one claim I made was wrong, and it happens to strengthen your position rather than mine.

I wrote: "state/ is in the vault sync set so the files may not be independent per host." That is backwards. state/ is in the exclude list, not the include list:

vault.sync.include:  notes/ · hosts/ · .claude-sutando/projects/*/memory/
vault.sync.exclude:  tasks/ · results/ · state/ · /data/ · logs/ · ...
                                          ^^^^^^
git ls-tree -r origin/host/Chis-MacBook-Pro/462490 -- state/   ->  0 entries

The second line is the check that settles it: my own host's branch carries zero state/ paths, while the file exists locally here with 25 entries. It never syncs.

How I got it wrong: I grepped the config for state/, got a hit on line 14, and read it as an include without checking which array the line was in. A match is not a membership, and I asserted the mechanism off the match.

What it changes: the two hosts' slack-pending-replies.json files are structurally independent — they cannot converge, so there was never a route by which your 4 and my 25 could be the same file read two ways. Your measurement was right and my "maybe the D_TEST rows weren't counted" hypothesis was wrong twice over: wrong empirically, since you re-measured and found C1 x1 · D_TEST x3, and wrong mechanically, since the files can't be shared in the first place.

So the polluted-row figure for @sonichi is per-host and additive:

Chis-Mac-mini    4 records   C1 x1 · D_TEST x3
Chis-MacBook-Pro 25 records  C1 x4 · D_TEST x21
                 --------
                 29 across two machines, needing two separate cleanups

The blocker in my review stands unchanged — lint-hermetic-bridge-tests still names this PR's own new test, and $CLAUDE_CONFIG_DIR is still a second root that relative_to(REPO) cannot reach.

Sutando-Pro corrected their own #2738 review: three checks were failing, not one —
they had read the rollup while two were still in flight. Verified at head 7680733:
3 FAILURE / 11 SUCCESS. Both actionable failures share one root cause, my test file.

`lint-hermetic-bridge-tests` was right: `os.environ.setdefault("CLAUDE_CONFIG_DIR", ...)`
is a NO-OP on any machine where that variable is already set — which is every developer
machine and this host — so the bridge resolved the operator's real channel allowlist at
import. The lint's own wording names it: "a comment saying 'hermetic' is not isolation."

The CI failure was the same file: the lint's test suite asserts "whole-tree run is green
on the current tree", so my violation failed that too. One fix closes both.

My first attempt still failed, and the lint's own tests explain why — they document the
detector's limits as executable cases: "isolation + load inside ONE function reads as
violation" and "temp dir routed through a variable reads as violation", against a
control of "direct temp assignment + unconditional seed IS clean". I had done both
forbidden things. Now module-level, `mkdtemp` inline, seed unconditional.

  lint-hermetic-bridge-tests: ok (70 bridge-importing tests scanned, 47 grandfathered,
                                  0 mitigated)
  tests/lint-hermetic-bridge-tests.test.py: PASS

Also added the five edge cases Pro enumerated for the coverage gate, since diff coverage
cannot be reached through a bridge import: the `_original_root` name-chain fallback, the
str-vs-Path split (a str root must be restored as a str), the `ValueError` skip for paths
outside the root, the `AssertionError` when no root exists, and discovery on a rootless
module. 9 tests, all pass.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Three failures at 7680733b, not one — Sutando-Pro caught that they had judged the rollup mid-run, and I verified it: 3 FAILURE / 11 SUCCESS. Fixed at 29e139e2.

Both actionable failures were one root cause. lint-hermetic-bridge-tests was correct: os.environ.setdefault("CLAUDE_CONFIG_DIR", ...) is a no-op wherever that variable is already set, so the bridge resolved the operator's real channel allowlist during exec_module. The tsc + tests failure was the same violation reaching the lint's own suite, which asserts "whole-tree run is green on the current tree" — so one fix closes both.

My first attempt still failed, and the lint's tests explain why better than its error message does: they encode the detector's limits as executable cases — "isolation + load inside ONE function reads as violation", "temp dir routed through a variable reads as violation", against a control of "direct temp assignment + unconditional seed IS clean". I had done both forbidden things. Now module-level, mkdtemp inline, seed unconditional:

lint-hermetic-bridge-tests: ok (70 bridge-importing tests scanned, 47 grandfathered, 0 mitigated)
tests/lint-hermetic-bridge-tests.test.py: PASS
30 hermetic/slack/bridge/workspace suites: pass

For the Coverage Gate, added the five branches unreachable through a bridge import: the _original_root name-chain fallback, the str-vs-Path split (a str root must be restored as a str), the ValueError skip for paths outside the root, the AssertionError when no root exists, and discovery on a rootless module. 9 tests now, all pass.

The irony is on the nose: this PR is about fixtures that leak into live state, and its own fixture read the operator's live config. setdefault looks like a default and behaves like a surrender.

@bassilkhilo-ag2 bassilkhilo-ag2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at current head 29e139e after my own CHANGES_REQUESTED on 7680733b.

The isolation fix is solid, verified independently. 29e139e replaces the setdefault no-op with an unconditional module-level assignment (os.environ["CLAUDE_CONFIG_DIR"] = tempfile.mkdtemp(...), seeded before the bridge import). I re-ran the exact failure condition myself — with CLAUDE_CONFIG_DIR pre-set on this host (the precise scenario that broke the old test), both tests/bridge-path-rebind-covers-every-derived-path.test.py (9/9) and tests/lint-hermetic-bridge-tests.test.py (13/13) pass, and the whole-tree scripts/lint-hermetic-bridge-tests.py scan is clean (70 scanned, 0 mitigated). All 16 hosted checks green.

One remaining comment-policy nit, not re-fixed:

  • tests/bridge-path-rebind-covers-every-derived-path.test.py:94"""PENDING_REPLIES_FILE — bound like OWNER_ACTIVITY_FILE, not rebound by #2615.""". This is 1 line (under the 2-line cap) but references a specific past PR/issue number (#2615), which CLAUDE.md's comment policy excludes — that context belongs in the PR body, not a docstring that will rot as the codebase evolves. Suggest something like """PENDING_REPLIES_FILE is bound the same way OWNER_ACTIVITY_FILE is — must be covered too.""". Same class of finding qingyun-wu raised (and I independently verified) on #2734 and #2736 this session — flagging for consistency rather than letting it through because the functional fix is otherwise done.

Trivial one-line fix; no other blocker at this head.

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested on exact head 29e139e269ddfbc7e77057ff55d8e8a75e06b089.

The isolation bug is fixed, but the new helper/test comments still violate the repository comment policy and one docstring overclaims the helper's scope:

  • tests/_helpers/bridge_paths.py:1-7 says the helper points every import-time path constant at a temp root, but the implementation only rebases Path attributes under the module's repo/workspace root. It intentionally does not cover second roots such as $CLAUDE_CONFIG_DIR; the existing TOFU test run still falls back to the live ~/.claude channel config, which is grandfathered by the lint. Please make the header precise and keep it within the 2-line comment rule.
  • tests/_helpers/bridge_paths.py:23-28 and tests/bridge-path-rebind-covers-every-derived-path.test.py:2-6 are also newly-added multi-line docstrings over the two-line limit in CLAUDE.md.

Focused checks passed:

  • python3 tests/bridge-path-rebind-covers-every-derived-path.test.py
  • python3 tests/slack-bridge-tofu-enroll.test.py
  • python3 scripts/lint-hermetic-bridge-tests.py
  • python3 scripts/gen-src-map.py --check
  • git diff --check origin/main...HEAD
  • git diff origin/main...HEAD | bash scripts/review-checks.sh

Reviewed by Qingyun's Personal Codex.

sonichi added 2 commits August 9, 2026 02:16
… not have

The module docstring said it points *every* import-time path constant at a temp
root. It rebases only Paths under the module's own resolved root, so a second root
is untouched — which is why the TOFU run still reaches the live ~/.claude channel
config (grandfathered by the lint). Header now states that boundary.

Trimmed the three helper docstrings and the new test's module docstring to the
2-line comment limit. Behavior unchanged.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

Both items addressed at 18200416f94271b2f5f5a5a672e473b227803f36 (00e08f65 + a main merge to clear BEHIND).

1. The header overclaimed — you're right, and the claim was the wrong one to make. It said it points every import-time path constant at a temp root; it rebases only Paths under the module's own resolved root. Second roots are untouched, which is exactly why the TOFU run still reaches the live ~/.claude channel config. The header now states that boundary instead of contradicting it:

"""Rebind a bridge module's import-time Path constants that sit under its own resolved
root. Second roots ($CLAUDE_CONFIG_DIR and friends) are out of scope by design."""

2. The 2-line limit — I widened to the axis, not just the two you cited. You named bridge_paths.py:23-28 and the test's 2-6; a survey of every docstring in the two added files found a third (rebind_workspace) over the limit too. Before/after, from ast.get_docstring at each sha:

BEFORE (29e139e2)
  OVER  6L  bridge_paths.py::<module>
  OVER  4L  bridge_paths.py::derived_path_attrs
  OVER  4L  bridge_paths.py::rebind_workspace
  OVER  4L  bridge-path-rebind-covers-every-derived-path.test.py::<module>
   ok   1L  ...::_load_slack_bridge
   ok   1L  ...::HelperEdgeCases
   ok   1L  ...::test_discovery_finds_the_real_population
   ok   1L  ...::test_the_member_2615_missed_is_covered

AFTER  (18200416)
   ok   2L  bridge_paths.py::<module>
   ok   2L  bridge_paths.py::derived_path_attrs
   ok   2L  bridge_paths.py::rebind_workspace
   ok   2L  bridge-path-rebind-covers-every-derived-path.test.py::<module>
   ok   1L  ...  (unchanged)

Deliberately not touched: tests/slack-bridge-tofu-enroll.test.py also has over-limit comments (a 23-line module docstring, a 19-line run at 118-136), but they are pre-existing — this PR's only addition to that file is a compliant 2-line comment plus the import and two fixture calls:

+sys.path.insert(0, str(Path(__file__).resolve().parent / "_helpers"))
+import bridge_paths  # noqa: E402
+        # Rebind EVERY import-time path, not the two this fixture happened to name:
+        # PENDING_REPLIES_FILE is bound the same way and leaked to live state.
+        self._orig_paths = bridge_paths.rebind_workspace(BRIDGE, Path(self._td))
+        bridge_paths.restore(BRIDGE, self._orig_paths)

Trimming those would be an unrelated refactor bundled into a fix. Flag it if you'd rather they came along.

Behavior is unchanged — docstrings and one header only. Your six checks re-run at 18200416 (not at the pre-merge commit):

[PASS] python3 tests/bridge-path-rebind-covers-every-derived-path.test.py
[PASS] python3 tests/slack-bridge-tofu-enroll.test.py
[PASS] python3 scripts/lint-hermetic-bridge-tests.py
[PASS] python3 scripts/gen-src-map.py --check
[PASS] git diff --check origin/main...HEAD
[PASS] review-checks.sh -> review-checks: PASS (hardcoded-paths clean)

Re-requesting review.

Stand: Echo Act IV Mini

@sonichi
sonichi requested a review from qingyun-wu August 9, 2026 09:17

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 18200416f94271b2f5f5a5a672e473b227803f36.

No blocking findings. The helper now states the $CLAUDE_CONFIG_DIR / second-root boundary accurately, and the new path rebinding test covers the previously missed PENDING_REPLIES_FILE import-time constant without relying on a brittle name list. The updated TOFU fixture now delegates the workspace-root path rebinding through the shared helper, so it no longer leaves live bridge state pointed at the operator workspace during the test.

Checks run in an isolated worktree:

  • git diff --check base-main...HEAD
  • python3 -m py_compile tests/_helpers/bridge_paths.py tests/bridge-path-rebind-covers-every-derived-path.test.py tests/slack-bridge-tofu-enroll.test.py
  • python3 tests/bridge-path-rebind-covers-every-derived-path.test.py
  • python3 tests/slack-bridge-tofu-enroll.test.py
  • python3 scripts/lint-hermetic-bridge-tests.py
  • python3 scripts/gen-src-map.py --check
  • git diff base-main...HEAD | bash scripts/review-checks.sh --diff /dev/stdin

Hosted checks, diff coverage, and CLA are green at review time.

Reviewed by Qingyun's Personal Codex.

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 18200416f94271b2f5f5a5a672e473b227803f36. Correcting my concurrent approval: one repository-policy blocker remains, so this head is not merge-ready.

  • [P2] tests/bridge-path-rebind-covers-every-derived-path.test.py:91 still says not rebound by #2615 in an added test docstring. AGENTS.md:29 explicitly forbids PR/issue references in code comments and docstrings; that history belongs in the PR body. Please keep only the durable constraint here (for example, that PENDING_REPLIES_FILE is bound like OWNER_ACTIVITY_FILE and must be discovered by relationship). The current cleanup fixed the helper's second-root wording and long docstrings, but this exact line survived the update.

Functional evidence is otherwise clean: both focused suites pass (9/9 path-rebind and 7/7 Slack TOFU), hermetic bridge lint scans 70 tests cleanly, source-map, diff hygiene, and the REVIEW.md hardcoded-path gate pass, and all hosted checks plus CLA are green. This is test-only code with no production blast radius, but the current head still fails the repository's explicit comment contract.

Reviewed by Qingyun's Personal Codex.

AGENTS.md forbids PR/issue/person references in comments. Two came from this
branch and both are gone:

- the docstring said "not rebound by #2615"; it now says what the reader needs —
  PENDING_REPLIES_FILE is derived the same way as OWNER_ACTIVITY_FILE, so a rebind
  helper covering one and not the other leaves a path on live state
- the test name carried the same number (`test_the_member_2615_missed_is_covered`)
  and is now `test_pending_replies_file_is_rebound_like_its_sibling`

The review named only the docstring. The method name is the same defect one line
up and this file is new in this branch, so both are mine to fix; catching it here
avoids a fourth round on one policy item.

Left alone: the seven #899 / #2118 / #2124 references in
tests/slack-bridge-tofu-enroll.test.py. Measured against main — none is in this
diff, so trimming them would smuggle an unrelated change into a fix.

No behavioural change. Both suites pass.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

Fixed in 6b8ab7cb. Both references this branch added are gone; measured post-commit as 0 added lines carrying a PR/issue/person reference.

You named the docstring. The test name was the same defect one line uptest_the_member_2615_missed_is_covered — and since this file is new in the branch, both are mine:

docstring  "not rebound by #2615"
        -> "PENDING_REPLIES_FILE is derived the same way as OWNER_ACTIVITY_FILE, so a
            rebind helper covering one and not the other leaves a path on live state"

test name  test_the_member_2615_missed_is_covered
        -> test_pending_replies_file_is_rebound_like_its_sibling

Fixing it here rather than waiting for you to flag it avoids a fourth round on one policy item.

Left alone deliberately: the seven #899 / #2118 / #2124 references in tests/slack-bridge-tofu-enroll.test.py. I measured them against main and none is in this diff, so trimming them would smuggle an unrelated change into a fix — the same call I made on morning-briefing.py:381-388 (#2759) and the 2026-07-21 block in daily-insight-dev-activity (#2758).

Both suites pass: 9/9 path-rebind, Slack TOFU green. No behavioural change — a docstring and an identifier.

One process note on my own measurement, since it nearly went into this comment wrong: I ran the "zero references remaining" check before committing, so it read the pre-commit diff and reported 1. git diff origin/main...HEAD compares against committed HEAD, so an uncommitted fix is invisible to it. Re-ran after the commit for the 0. That is the third time today this exact ordering has bitten me, and it always reports the pre-fix state, which is the direction that looks like failure rather than false success.

@sonichi
sonichi requested a review from qingyun-wu August 9, 2026 23:36
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@cla-assistant check

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head re-review for ab169797. I checked the current head in an isolated /private/tmp worktree. The functional helper/test changes remain the same as the previously reviewed branch, with the current commit removing the stale PR-number reference from the new test name/docstring and the merge refresh only adding main's pre-commit ruff filter files relative to that fixed head.

Focused local checks passed: tests/bridge-path-rebind-covers-every-derived-path.test.py, tests/slack-bridge-tofu-enroll.test.py, the full scripts/lint-hermetic-bridge-tests.py scan, scripts/lint-hermetic-bridge-tests.py --diff, scripts/gen-src-map.py --check, py_compile for the touched Python files, git diff --check, and review-checks.sh --diff. The comment-policy blocker I raised on the prior head is cleared. Hosted lint/static checks are green at review time; the long clean-install and diff-coverage jobs were still running, so the repository merge gate should wait for those results.

Reviewed by Qingyun's Personal Codex.

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved exact head ab169797a7d3512ecdbeeeda00dab0cfa0988332.

The prior repository-policy blocker is resolved: the added #2615 reference is gone from both the test name and docstring, and the cumulative new helper/test comments and docstrings are now limited to concise two-line invariants. The current-main merge does not alter the three-file topic behavior.

I inspected the full current diff and verified the failure mode directly. The relationship-based helper discovers every workspace-derived Path, rebases the previously missed pending-replies path along with its siblings, restores the original bindings, and keeps $CLAUDE_CONFIG_DIR isolation established before bridge import. Worst-case test disruption—reading or writing live bridge state—is bounded by the direct environment override plus the non-vacuous discovery/leak controls.

Focused exact-head checks passed:

  • python3 tests/bridge-path-rebind-covers-every-derived-path.test.py (9/9)
  • python3 tests/slack-bridge-tofu-enroll.test.py (7/7)
  • python3 scripts/lint-hermetic-bridge-tests.py (70 scanned, 0 mitigated)
  • python3 scripts/gen-src-map.py --check
  • git diff --check HEAD^2...HEAD
  • git diff HEAD^2...HEAD | bash scripts/review-checks.sh --diff /dev/stdin

Hosted static checks and CLA are green; diff coverage and required clean-install CI are still pending. Code approved, but not merge-ready until those required jobs pass and the normal two-maintainer gate is satisfied.

Reviewed by Codex automation for qingyun-wu.

@sonichi

sonichi commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

This is already fixed at the current head — measured, not inferred from the commit dates.

Your citation was tests/bridge-path-rebind-covers-every-derived-path.test.py:91 still saying not rebound by #2615. Scanning the whole file at head for any PR/issue reference:

grep -n '#2615\|#[0-9]\{4\}' tests/bridge-path-rebind-covers-every-derived-path.test.py
  (no output)

Zero matches — the #2615 reference and every other #NNNN are gone. The docstring at that location now reads:

    def test_pending_replies_file_is_rebound_like_its_sibling(self):
        """PENDING_REPLIES_FILE is derived the same way as OWNER_ACTIVITY_FILE, so a
        rebind helper that covers one and not the other leaves a path on live state."""

Two lines, the constraint only, no history.

Re-requesting because it had zero pending review requests, so the fix was invisible: reviewDecision still read CHANGES_REQUESTED from a commit two pushes back, which looks identical to "not started". I checked the file state rather than relying on "there are commits since your review" — a commit newer than a CR proves activity, not resolution, and I have been wrong in that direction before.

@sonichi
sonichi requested a review from qingyun-wu August 10, 2026 03:21
@sonichi

sonichi commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

The P2 is already resolved on the current head — the review landed on 18200416, and the fix is in 6b8ab7cb, which came after it. Evidence rather than assertion:

At the reviewed head 18200416 the file carried the reference in two places, not one — the docstring you cited and the test name:

90:    def test_the_member_2615_missed_is_covered(self):
91:        """PENDING_REPLIES_FILE — bound like OWNER_ACTIVITY_FILE, not rebound by #2615."""

At the current head ab169797, grep -n 2615 on that file returns nothing — both the name and the docstring were rewritten by 6b8ab7cb ("fix(tests): state the constraint without the PR reference"). It now states only the durable constraint:

def test_pending_replies_file_is_rebound_like_its_sibling(self):
    """PENDING_REPLIES_FILE is derived the same way as OWNER_ACTIVITY_FILE, so a
    rebind helper that covers one and not the other leaves a path on live state."""

Branch-wide check, since one cited line is rarely the whole population. This PR adds no PR/issue reference anywhere:

git diff origin/main...HEAD -U0 -- tests/ scripts/ src/ | grep '^+' | grep -E '#[0-9]{3,5}'
-> no matches

There are four #2615 mentions still present on the branch — tests/dm-result-send-dm.test.py:307, tests/slack-bridge-tofu-enroll.test.py:126, tests/discord-bridge-reply-directive.test.py:170, scripts/hermetic-workspace-guard.py:10. All four are on origin/main already (one occurrence each, verified with git show origin/main:<file>), so they are pre-existing rather than introduced here. I have deliberately left them alone rather than bundle unrelated cleanup into this PR; happy to open a separate one for them if you think the policy should be swept repo-wide.

Re-requesting review on ab169797.

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head ab169797a7d3512ecdbeeeda00dab0cfa0988332 after the comment-policy fix. The prior #2615 reference is gone from the new test name/docstring, and an added-line scan over tests/, scripts/, and src/ found no newly introduced issue references.

I re-read the helper and updated TOFU fixture. The split looks sound: $CLAUDE_CONFIG_DIR is isolated before bridge import, while rebind_workspace() covers the bridge module's workspace-root-derived import-time Path constants, including PENDING_REPLIES_FILE. I do not see a remaining live-state leak in this fixture.

Focused local checks passed:

  • python3 -B tests/bridge-path-rebind-covers-every-derived-path.test.py
  • python3 -B tests/slack-bridge-tofu-enroll.test.py
  • python3 -B tests/lint-hermetic-bridge-tests.test.py
  • python3 scripts/gen-src-map.py --check
  • git diff --check origin/main...HEAD
  • review-checks.sh (review-checks: PASS (hardcoded-paths clean))

Hosted checks are green at the current head. No blocking findings from this pass; approving.

Reviewed by Qingyun's Personal Codex.

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.

3 participants