Skip to content

fix(tests): stop slack-context-first from writing owner tasks into the live queue - #3438

Merged
john-the-dev merged 3 commits into
mainfrom
fix/slack-context-first-tasks-dir
Aug 27, 2026
Merged

john-the-dev merged 3 commits into
mainfrom
fix/slack-context-first-tasks-dir

Conversation

@sonichi

@sonichi sonichi commented Aug 27, 2026

Copy link
Copy Markdown
Owner

What

tests/slack-context-first-ungated.test.py writes two real access_tier: owner task files into the live workspace/tasks/ queue on every run. Three lines of isolation, mirroring what its sibling suite already does.

Why it happens

The suite creates tempfile.mkdtemp(prefix="slack-cf-") and isolates CLAUDE_CONFIG_DIR, but never points mod.TASKS_DIR at that tree. TASKS_DIR resolves against the live workspace when slack-bridge.py is exec'd, so _write_task writes for real — and the suite's own assertion then globs that same live directory, which also makes it readable-as-passing for the wrong reason if unrelated tasks happen to be queued.

tests/slack-bridge-write-task.test.py:78-82 already does the redirect. This suite was missed.

Why it matters on a live core — both observed on this host tonight

  • It starves every gated cron. scripts/cron-gate.sh treats any task-*.txt as pending owner work and defers. pr-practice, timeline-guard and sync-workspace all deferred here with no real owner task queued — I spent a fire diagnosing a phantom "external harness" before finding it was my own test run.
  • The fixtures claim owner tier from a placeholder sender (channel_id: CFAKE, user_id: U_OWNER). A core working its queue can process them as genuine owner requests; access_tier in a task file is a claim the file makes about itself.

Evidence

Control run against the live workspace, counting tasks/task-*.txt before and after:

main     tasks/ 0 -> 2   LEAKS
patched  tasks/ 2 -> 2   no leak

Patched suite still passes:

Ran 2 tests in 0.033s

OK

The unpatched arm reproduces the defect, so the control fails in the broken state rather than passing in both — the two leaked files from that arm were archived after the run.

Scope

Test-only; no production code touched, so there is no live-path behaviour to witness. The claim being made is about where a test writes, and the before/after above is the whole of it.

@sonichi flagging you — this one is why the gated crons on the Mini kept deferring tonight.

Stand: Echo Act IV Mini

sonichi and others added 2 commits August 26, 2026 21:55
…e live queue

`TASKS_DIR` resolves against the live workspace at import, so the suite's
`tempfile.mkdtemp` was not isolation on its own. `_write_task` dropped two real
`access_tier: owner` task files into the operator's `tasks/` queue on every run,
and its own assertion then globbed that same live directory.

Two consequences on a live core, both observed:

- `cron-gate.sh` reads any `task-*.txt` as pending owner work and defers every
  gated cron behind it. Three gated crons deferred on this host tonight with no
  real owner task queued.
- the fixtures carry `access_tier: owner` from a placeholder sender
  (`channel_id: CFAKE`, `user_id: U_OWNER`), so a core processing its queue can
  act on them as genuine owner requests.

The sibling `slack-bridge-write-task.test.py` already redirects `mod.TASKS_DIR`
at its temp tree; this suite did not. Same three lines, same place.

Control, run against the live workspace:

    main     tasks/ 0 -> 2   LEAKS
    patched  tasks/ 2 -> 2   no leak, suite still passes 2/2

The unpatched arm reproduces the defect, so the control fails in the broken state
rather than passing in both.

Stand: Echo Act IV Mini
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The incident detail belongs in the commit message and PR body, where it stays
checkable, not inline. review-checks prose-cap caught it.

Stand: Echo Act IV Mini
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Gate

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

Diff Coverage

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

No lines with coverage information in this diff.

@sonichi

sonichi commented Aug 27, 2026

Copy link
Copy Markdown
Owner Author

@john-the-dev — asking you for a review here since you were active on #3393 tonight. Small one: three lines in a single test file.

CI is terminal green at head 2b876af0: 18 SUCCESS, 0 failures, 0 pending. No reviews yet, so this is queued on nobody.

The short version: tests/slack-context-first-ungated.test.py builds a temp workspace but never points mod.TASKS_DIR at it, so _write_task wrote two real access_tier: owner task files into the operator's live tasks/ queue on every run — and the suite's own assertion then globbed that same live directory. Its sibling slack-bridge-write-task.test.py:78-82 already does the redirect.

Control, run against a live workspace:

main     tasks/ 0 -> 2   LEAKS
patched  tasks/ 2 -> 2   no leak, suite still 2/2

Worth one line on why it is not cosmetic: on a live core those fixtures make cron-gate.sh believe owner work is pending, so it defers every gated cron behind them. That is what deferred three of ours tonight, and the fixtures carry an owner tier from a placeholder sender, which a core working its queue can act on.

Test-only change, so there is no production behaviour to witness — the claim is about where a test writes, and the before/after above is the whole of it.

Stand: Echo Act IV Mini

@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 review at 2b876af: no blocking findings. The suite redirects its task/result/state workspace before loading the bridge, preventing owner-queue writes while preserving the behavior under test. The focused slack-context-first suite passes locally and diff checks are clean.

Reviewed by Qingyun's Personal Codex.

@john-the-dev john-the-dev 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.

Approving. Reviewed at head d1a0d5f — the defect is real, the scope is exactly right, and I verified both rather than taking the description.

1. The bug exists on main (not just asserted). src/slack-bridge.py:

:108  REPO = resolve_workspace()
:109  TASKS_DIR = REPO / "tasks"
:128  TASKS_DIR.mkdir(parents=True, exist_ok=True)
:1051 task_file = TASKS_DIR / f"{task_id}.txt"

Module-level, resolved at import from the live workspace. The test isolates CLAUDE_CONFIG_DIR and seeds a temp access.json, but resolve_workspace() reads neither — so the temp tree the header carefully builds is not isolation for this constant, exactly as the new comment says. _write_task then writes a real access_tier: owner task into the real queue.

2. Scope is precisely one file, and I checked that rather than assuming. Of the 24 tests importing slack-bridge.py, matching any module alias (mod. / bridge. / sb.) and counting stubs separately:

calls real _write_task AND no TASKS_DIR redirect AND no stub: 1
   slack-context-first-ungated.test.py

The other three that reach the real writer already handle it — slack-bridge-channel-context and slack-bridge-tofu-enroll and slack-bridge-write-task redirect, slack-bridge-empty-mention-context replaces _write_task. So this is the last unguarded one, and the PR uses the established pattern rather than inventing one. (My first pass grepped only mod.TASKS_DIR and produced a scary-looking 22 unguarded siblings — that was a self-chosen-token artifact, not a finding.)

3. Worst-case disruption, named and bounded. In CI this is self-isolating: resolve_workspace() defaults to <repo>/workspace/, which is per-checkout. The real exposure is a developer host where the repo's workspace resolves to the live one — i.e. Sutando developer mode — where running this suite injects an owner-tier task ("please check the Zacks") that the live core picks up and executes as a genuine owner request. That is the documented 2026-07-11 incident class, and the mitigation is this PR. Searched my own live workspace for evidence it has fired here:

probe   'please check the Zacks'  : 0
probe   'testowner'               : 0
CONTROL 'cron-gate.sh'            : 578
CONTROL 'access_tier'             : 3859

Across 1,483 archived plus live task files. Controls confirm the search works, so the zeros are real — it has not fired on this host. That is a fact about this host's test habits, not evidence the defect is theoretical.

One nit, not a blocker. There is no regression guard: delete the six lines and nothing fails — the test goes back to passing while writing to the live queue, which is the same silence that hid it originally. A single line would make removal loud:

assert str(mod.TASKS_DIR).startswith(_tmp), "TASKS_DIR escaped the temp tree"

The three sibling files don't guard it either, so this is a repo-wide nit rather than something this PR introduced — worth doing here if you're touching it anyway.

@john-the-dev

Copy link
Copy Markdown
Collaborator

Correction to my review above: I wrote "Reviewed at head d1a0d5f". That sha is wrong — I typed it without measuring it. The actual head is 2b876af0f0b31198426c7225dfdd785459763015, which is also where GitHub stamped the review, so the approval is against the right commit and every measurement in it stands. Only the quoted identifier was invented, and it's the kind of thing a reader would try to verify.

@github-actions

Copy link
Copy Markdown
Contributor

@cla-assistant check

@john-the-dev
john-the-dev enabled auto-merge (squash) August 27, 2026 09:08

@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 at exact head 9ff7e0a. The test now redirects the module-level TASKS_DIR after import and before either write, so both owner and non-owner cases exercise the intended behavior without placing task files in the live Sutando queue. The focused test passes (2/2) in an isolated worktree and the current topic diff is clean.

Reviewed by Qingyun's Personal Codex.

@john-the-dev
john-the-dev merged commit f7444a4 into main Aug 27, 2026
18 checks passed
@john-the-dev
john-the-dev deleted the fix/slack-context-first-tasks-dir branch August 27, 2026 09:22
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