Skip to content

fix(memory): rollback cycle-reflection trailer — DM regression - #296

Closed
samxu01 wants to merge 1 commit into
mainfrom
fix/revert-cycles-trailer
Closed

fix(memory): rollback cycle-reflection trailer — DM regression#296
samxu01 wants to merge 1 commit into
mainfrom
fix/revert-cycles-trailer

Conversation

@samxu01

@samxu01 samxu01 commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 2.J's `withCyclesDirective` trailer (PR #295) is causing live agents to skip DM responses. Rolling back ASAP — the trailer instructs agents to call `commonly_save_my_memory({sections:{cycles:{append:...}}})`, but no openclaw extension tool with that name exists. Agents waste 3+ turn-budget tool calls per heartbeat hunting for it before falling back to the real `commonly_write_agent_memory`, which exhausts their budget before they can post a chat reply.

Evidence

Nova went silent on Sam immediately after Phase 2.J reprovision-all rolled the trailer to the gateway PVC at ~05:30 UTC:

Time (UTC) Sender Message Nova reply
2026-05-03 22:43 xcjsam hey "hey" (~6 min later) ✅
2026-05-04 00:34 xcjsam hey reply 13 min later ✅
2026-05-04 01:05 xcjsam what up reply 1 min later ✅
2026-05-04 06:01 xcjsam hey Nova (silent) ❌
2026-05-04 06:21 xcjsam hey (silent) ❌

Reprovision-all completed ~05:30 UTC. First missed DM was 06:01 UTC.

Session log `/state/agents/nova/sessions/*.jsonl` confirms: 3× attempted `commonly_save_my_memory` (the missing tool name from the trailer), 1× successful `commonly_write_agent_memory` fallback.

Fix

`withCyclesDirective` is now a no-op. HEARTBEAT.md will revert to its pre-Phase-2.J shape on the next reprovision-all. The helper + the four call-sites stay in place so re-enabling is a one-line flip once the openclaw extension exposes a real cycles-write tool.

Forward path (separate branch)

  1. Add `commonly_log_cycle(content, podId?)` to `Team-Commonly/openclaw` extension (`extensions/commonly/src/{tools,client}.ts`)
  2. Build + push gateway image, helm upgrade clawdbot-gateway
  3. Update trailer to call `commonly_log_cycle(...)` instead of the dotted-section shape
  4. Flip this no-op back to the real implementation
  5. Reprovision-all + observe

Test plan

  • tsc:check clean
  • Merge → Deploy Dev → reprovision-all → DM Nova → confirm she replies again

🤖 Generated with Claude Code

…udget

Phase 2.J's withCyclesDirective trailer (#295) instructed agents to call
\`commonly_save_my_memory({sections:{cycles:{append:...}}})\`, but the
openclaw extension exposes no tool by that name — agents waste 3+ turns
per heartbeat hunting for it before falling back to the real
\`commonly_write_agent_memory\`. The wasted budget caused Nova to go
silent on Sam's '@nova hey' (06:01 UTC) and 'hey' (06:21 UTC) DMs
immediately after the trailer rolled out via reprovision-all.

Verified in /state/agents/nova/sessions/*.jsonl: 3× attempted tool
calls for the missing 'commonly_save_my_memory' before 1× successful
'commonly_write_agent_memory'.

This commit makes withCyclesDirective a no-op so HEARTBEAT.md reverts
to its pre-Phase-2.J shape on the next reprovision-all. The helper +
its four call-sites stay in place so re-enabling is a one-line flip
once the forward fix ships.

Forward fix path (separate branch): add \`commonly_log_cycle(content,
podId?)\` to the Team-Commonly/openclaw extension, build + push the
gateway image, then update the trailer to instruct agents to call the
new tool name. After that, this no-op gets reverted in one line.
samxu01 added a commit that referenced this pull request May 4, 2026
Phase 2.J's withCyclesDirective trailer (PR #295) instructed agents to
call commonly_save_my_memory({sections:{cycles:{append:...}}}), but no
openclaw extension tool with that name exists today. Agents waste 3+
turn-budget tool calls per heartbeat hunting for it before falling
back to the real commonly_write_agent_memory, which exhausts their
budget before they can post a chat reply.

Verified on Nova: silent on Sam's "hey Nova" (06:01 UTC) and "hey"
(06:21 UTC) DMs immediately after the trailer rolled out via
reprovision-all. Pre-rollout, Nova was responding cleanly to four
prior pings within minutes.

Session log /state/agents/nova/sessions/*.jsonl confirms 3× attempted
'commonly_save_my_memory' tool calls (missing tool name) before 1×
successful 'commonly_write_agent_memory' fallback.

This commit makes withCyclesDirective a no-op so HEARTBEAT.md reverts
to its pre-Phase-2.J shape on the next reprovision-all. The helper +
its four call-sites stay in place so re-enabling is a one-line flip
once the openclaw extension exposes a real cycles-write tool.

Forward fix path (separate branch): add commonly_log_cycle(content,
podId?) to Team-Commonly/openclaw fork, build + push gateway image,
update trailer to call the new tool name, flip this back to the real
implementation, reprovision-all + observe.
@samxu01

samxu01 commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

Squash-merged to main as b8681a3.

@samxu01 samxu01 closed this May 4, 2026
@samxu01
samxu01 deleted the fix/revert-cycles-trailer branch May 4, 2026 06:41
samxu01 added a commit that referenced this pull request May 9, 2026
…_log_cycle (#307)

Phase 2.J's withCyclesDirective trailer was rolled back in e4b1dd9 /
PR #296 because it instructed agents to call:

  commonly_save_my_memory({sections:{cycles:{append:...}}})

That tool neither accepts the `cycles` section nor the nested
`{sections:{...}}` envelope — agents wasted 3+ tool-call turns per
heartbeat hunting for the missing surface before falling back to
commonly_write_agent_memory, exhausting their turn budget and dropping DM
responses (Nova on 2026-05-04).

Forward fix:

- Bumps `_external/clawdbot` to a67f0df6 (Team-Commonly/openclaw#7) — adds
  a dedicated `commonly_log_cycle({content, podId?})` tool that maps
  directly onto the kernel's {cycles:{append:{content,podId?}}} contract
  via /memory/sync, mode: 'patch'. Append-only by construction.
- Rewrites CYCLES_REFLECTION_TRAILER to call commonly_log_cycle directly,
  no nested envelope, no missing surface.
- Restores withCyclesDirective from no-op to template + trailer.
- Replaces the rollback comment block with a re-enable note that preserves
  the failure-mode archaeology for future readers.

After Deploy Dev + reprovision-all, dev agents should produce cycles[]
writes inside the next heartbeat window — closing the empirical gap from
the original Phase 2 observation (0 agent-authored cycle entries across
25 deployed agents in the +10min window).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
samxu01 pushed a commit that referenced this pull request Aug 4, 2026
…and tell them to skip

Taking this branch over: unowned for 4h past the pod's 30-minute threshold,
green-lit by @ux-lead. Merged main to clear the ADR-016 conflict (union of
both refinements; every distinct claim on each side preserved).

Three things folded in.

1. The cue's new comment ends 'an instruction must name a tool that can serve
   it', and the cue it ships names commonly_log_cycle -- which serves MCP seats
   and NOT moltbots. The openclaw extension declares 25 commonly_* tools
   without it at the tip, at the ref _external/clawdbot pins, and in the
   running gateway image. Both channels reach a moltbot in one turn (this cue
   and its HEARTBEAT.md, injected by extensions/commonly/src/channel.ts) and
   since 2026-05-09 both have named something it cannot execute. That is the
   fleet's 87-day cycles silence.

   So the cue now tells a caller without the tool to SKIP rather than
   substitute. Naming one tool makes a diligent agent exhaust that tool's
   schema and conclude the capability is absent -- the turn-burn that forced
   the #296 rollback. Comment records the surface split so the next reader
   does not inherit 'names a tool that exists' as unconditional.

2. First test for this cue, and it had none through two rewrites in one day.
   Asserts the DELIVERED payload via AgentEventService.enqueue, not the source
   constant, so extracting the string cannot make it pass vacuously. Includes
   a length control against an empty cue satisfying the negative assertions.
   Mutation-checked: dropping the skip clause reds exactly one test.

3. The sync handler's comment named the wrong hazard -- 'do not send cycles
   through sync', which every shipped caller does safely. The real condition
   is cycles MIXED with syncable sections in a resend. Cycles-only payloads
   return at the branch three lines below, before computeSyncDedupKey.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
samxu01 pushed a commit that referenced this pull request Aug 4, 2026
This branch and #804 fixed the same bug independently — a cue naming a call
shape no tool can emit. #804 merged first, so this branch's remaining value
is the extraction: the cue moves to services/heartbeatCue.ts with a test that
pins the delivery surfaces, not just the constant.

The merge caught a regression this refactor would otherwise have shipped.
#804's wording gained a final clause that this branch's extracted copy
predates:

  'If commonly_log_cycle is not in your tool list, skip the write and move
   on: no other memory tool can append to cycles, so do not substitute one.'

commonly_log_cycle reaches MCP seats and not moltbots, so without that clause
a diligent agent exhausts the tool's schema and concludes the capability is
absent — the turn-burn that forced the #296 rollback. Extracting the older
text would have silently reverted #804 for the whole moltbot fleet while every
test stayed green, because the suite pins the module and the module would have
been self-consistently wrong.

Ported main's live text into the constant verbatim and verified the two are
identical after normalization. Net behavior change: none. An extraction is a
move, never an edit — now stated in the constant's comment.

24/24 heartbeat tests pass, including main's skip-clause assertion against the
extracted module.
lilyshen0722 added a commit that referenced this pull request Aug 5, 2026
)

* fix(ax): the tool-contract guard skipped the strongest cue surface

The guard reads the presets.ts cycles trailer and the inline mention cues.
It did not read backend/services/heartbeatCue.ts — which by ADR-012 s10.3's
own reasoning is the strongest agent-facing surface we ship, reaching every
agent on every tick.

That gap had already been paid for. The heartbeat cue named
commonly_save_my_memory for a `cycles` write from 2026-05-03 (#293) to
2026-08-04 (#804/#818) — a tool that refuses the section by design — and
neither repo's suite could see the other, so both stayed green for three
months. A peer re-derived the same contradiction from source on 2026-08-05,
hours after it was fixed, which is what surfaced the omission.

Adds the cue as a required-tool source. The constant interpolates
${CYCLES_WRITER_TOOL}, so it is resolved from the same file rather than
restated here — a restated name is the drift this script exists to catch.
No namedForOtherDrivers exemption: #840 reconciled the lineages and the pin
declares commonly_log_cycle, so this is a hard requirement and a future bump
that drops it goes red instead of the fleet going quiet.

Two assertions the name-matching check cannot make, because existence is not
capability — the #295 cue would PASS a declares-the-tool check against
today's pin, since commonly_save_my_memory is declared at :526 right above a
description saying `cycles` is intentionally unavailable there:

  - the cue names exactly one writer tool, so a cue that also names a second
    (the #295 shape, and the shape a well-meaning "mention both" edit
    reproduces) fails
  - the escape-hatch clause survives. It looks redundant now that the pin has
    the tool and would be the first thing an editor cuts; deleting it re-arms
    the turn-burn that forced the #296 rollback the next time a bump drops it.

Mutation-verified: each of the three fails exactly its own assertion, with
measured anchors and byte-identical restores.

CLAUDE.md's pin-skew entry described the divergence in the present tense and
prescribed the fix #840 had already executed. It cost a wrong claim in the
sprint pod nine hours later. Dated, struck, and led with the resolution;
verified against the running gateway container rather than the source tree.

AX entry 21: remediation text quotes the defect verbatim, so a repo
accumulates copies of what is no longer true in the surfaces agents grep
first. Six verbatim copies of the dead cue, zero live ones — and the only two
queued events matching it were the peer's own reports about it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: the cycles silence is moltbot-scoped, and dated by measurement

The pin-skew entry asserted the skew caused "the fleet's" cycles silence
with an undocumented ~87-day figure. Measured against the memory collection
2026-08-05:

  moltbots (agentName=openclaw)  22 docs with entries, newest 2026-05-24T08:49:56Z
  non-moltbot seats              13 docs with entries, newest same evening

The moltbot cutoff falls on the exact day of the d6e63b2 bundled-skills
bump that dropped commonly_log_cycle — so the root cause is corroborated by
a source independent of the submodule log, rather than inferred from it.

Two corrections this forces. The silence is moltbot-scoped, not fleet-wide:
MCP and wrapper seats wrote cycles throughout, including during the outage
being debugged. And every moltbot array sits at the 40-entry cap — they are
FULL, not empty — so a recovery check looking for "cycles appear" reads
healthy off both the cap and the unaffected seats. It has to filter to
agentName=openclaw and require an entry newer than 05-24.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant