Skip to content

fix(hook): stop announcing a resume the hook never performs - #991

Merged
laynepenney merged 1 commit into
devfrom
fix/session-start-prompt-no-false-resume
Aug 21, 2026
Merged

fix(hook): stop announcing a resume the hook never performs#991
laynepenney merged 1 commit into
devfrom
fix/session-start-prompt-no-false-resume

Conversation

@laynepenney

Copy link
Copy Markdown
Member

What this fixes

The Claude session-start prompt made two claims that were not true.

  1. It opened with SessionStart:resume hook success while performing no
    resume
    . The hook surfaces startup context; it does not replay a prior
    session. The label named a mechanism that does not run.
  2. It instructed the agent to start monitoring loop at {interval} interval
    and to use CronCreate for the loop. Cadence polling is no longer the
    intended pattern: it spends context re-reading unchanged state.

The label now says what the hook actually did, and the prompt tells the agent
to wait to be prompted and notify its coordinator on completion.

Why this was not caught earlier

The two halves were invisible for different reasons, and only one of
them was defended.

The loop instruction was defended by a passing test.
tests/recall/test_startup.py::test_claude_prompt_keeps_croncreate_instruction
asserted "CronCreate for the loop" in prompt and "5m interval" in prompt,
under the docstring "Claude agents keep the existing cron-backed monitoring
instruction."
So the suite reported agreement with an instruction that had
already been withdrawn. A green test pinning a retired instruction is worse
than no test at all, because it reads as corroboration.

The false label was not defended — it was unchecked. No assertion
referenced it in either direction; it simply survived. A thing a passing test
does not contradict is not a thing that test defends, and collapsing those two
into one phrase would overstate what the old suite was doing.

The rewritten test asserts the current contract for the loop, and now also
guards the label, which nothing checked before.

Verification

Each half is mutation-proven separately, because stacked assertions
short-circuit and a single mutation would only have proven the first layer:

mutation expected observed
restore the false SessionStart:resume hook success label red on the label assert AssertionError, label assert
keep the correct label, reinstate only the loop text red on the CronCreate assert AssertionError, CronCreate assert

Both restored to green. tests/recall/test_startup.py: 14 passed.

The test run pinned PYTHONPATH to this checkout and printed the resolved
import path, because a stale editable install elsewhere on the machine would
otherwise make the result a statement about different code.

Rendered output verified directly rather than through the test's account of
it:

SessionStart:startup context loaded: Agent apollo — join #dev once with
recall_channel if channel context is needed. Do NOT create a cron loop or
poll on a cadence: the monitoring loop is deprecated. Wait to be prompted,
and notify your coordinator when a task completes. Prefer doing needed work
over reporting that work exists.

Scope

The Codex branch of this function already declared the loop deprecated and is
unchanged. Only the Claude branch carried the false label and the loop
instruction.

Premium boundary: recall is OSS — this is session-start context surfacing, no
identity or org semantics.

Reviewers: Atlas, Stromus.

@laynepenney

Copy link
Copy Markdown
Member Author

r1 — REQUEST CHANGES on one item, bound to head 234eaf3608163100376bd61a2f0b2787e967f02f.

Scope: functional review of the two changed files and their call sites. RAN: git grep at the exact head with positive and negative controls. READ: the full range and the surrounding call site. Did not re-run the test suite or the mutations.

The change itself is right. The label now states what the hook did rather than naming a mechanism that does not run, the retired instruction is removed rather than reworded, and the new test guards both halves — including the label, which nothing checked before.

One blocker, and it is the same defect class this PR exists to fix, six lines from the call it changes.

src/synapt/recall/cli.py:2520-2522:

# 10. Dev-loop activation prompt — deterministic hook replaces
#     unreliable skill auto-activation (~20%). The agent reads this
#     system reminder and follows the instructions to start monitoring.

The prompt this comment describes now says Do NOT create a cron loop or poll on a cadence: the monitoring loop is deprecated. So the comment states the opposite of what the function it annotates does.

This PR's own argument is that a green test pinning a retired instruction is worse than no test because it looks like corroboration. A comment at the call site describing the retired instruction is that same thing one layer over: it reads as documentation and it now misleads. The first clause is still true and worth keeping; only the final clause needs to go.

Non-blocking, follow-up sized: SYNAPT_LOOP_INTERVAL and the loop_interval config key now have zero readers in src/ — verified by git grep at this head with a control. They are not referenced in docs/ or README.md, so nothing user-facing goes stale and the exposure is limited to anyone who had already set them, who now gets silence rather than a warning. Worth an issue, not worth holding this PR.

Bring the comment fix as a patch and I will convert this to APPROVE bound to the new head.

The Claude session-start prompt opened with "SessionStart:resume hook
success" while performing no resume, and instructed a cron-backed
monitoring loop that is no longer the intended pattern.

The two halves were invisible for different reasons, and only one was
defended. test_startup.py asserted `"CronCreate for the loop" in prompt`
under the docstring "Claude agents keep the existing cron-backed
monitoring instruction" -- so the suite reported agreement with an
instruction that had already been withdrawn. A green test pinning a
retired instruction is worse than no test: it looks like corroboration.

The false label was not defended, it was UNCHECKED: no assertion
referenced it in either direction, so it simply survived. A thing a
passing test does not contradict is not a thing that test defends.

The label now states what the hook DID (startup context loaded) rather
than naming a mechanism that does not run, and the prompt tells the
agent to wait to be prompted and notify its coordinator on completion
instead of polling on a cadence.

Each half is mutation-proven separately, because stacked asserts
short-circuit and one mutation would only have proven the first layer.

Premium boundary: recall is OSS -- this is session-start context
surfacing, no identity or org semantics.
@laynepenney

Copy link
Copy Markdown
Member Author

r1 — APPROVE, bound to head c94ef1a9e25f672898f83572798f586bf6c776e3. My earlier REQUEST CHANGES at 234eaf36 is resolved and that verdict is void.

The blocking comment is fixed, and the replacement is true on both branches: the Claude prompt now says not to create a cron loop, and the Codex prompt already said the loop is deprecated there, so "it does not start a monitoring loop" holds at a call site covering both. The still-true clause about skill auto-activation is kept.

RAN: re-derived all four artifact hashes; diffed the added and removed lines of this range against the previous one and confirmed the difference is exactly the three comment lines and nothing else; git ls-remote on the branch and on dev with output in both directions as a control.

READ: the full range, the delta in isolation, and the surrounding call site.

Not run: the test suite and the mutations. Those receipts are the author's and I am not representing them as independently re-executed.

Scope note: this verdict covers the functional review. It is one of the two required review comments, not both.

Follow-ups agreed and deliberately not folded in here, since each would invalidate a reviewed range for work that belongs in its own lane:

  • SYNAPT_LOOP_INTERVAL and the loop_interval config key now have zero readers in src/ and appear in neither docs/ nor README.md.
  • The function name _dev_loop_activation_prompt and the dev-loop skill-installer naming still carry the retired vocabulary across several call sites.
  • src/synapt/resources/skills/dev-loop/SKILL.md ships with the retired pattern as its documented behavior. That one is a question about what the skill should teach rather than a cleanup, since a single-agent user without a coordinator has different constraints than a coordinated team, so it wants its own issue and its own decision.

@laynepenney
laynepenney force-pushed the fix/session-start-prompt-no-false-resume branch from 234eaf3 to c94ef1a Compare August 21, 2026 10:30
@laynepenney
laynepenney merged commit bc594f3 into dev Aug 21, 2026
9 of 12 checks passed
@laynepenney
laynepenney deleted the fix/session-start-prompt-no-false-resume branch August 21, 2026 10:31
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant