Skip to content

Pi re-injects the work-items nudge on every restart or resume #785

Description

@alexeyzimarev

Pi's kcap.ts extension re-fires session_start for the same session file on a restart (startup, reload) and on resume (PiHookCommand.LifecycleFor declares CallbackMayRepeat: true for exactly this reason). The memory index is fenced against the repeat by the durable once-per-session lease, keyed on the canonicalized session file path (PiSessionPathCanonicalizer), so a resume is deduped and a fork (new file) is freshly eligible. The work-items nudge is not: WorkItemsNudgeEmitter.Resolve is called unconditionally at the output site (src/Capacitor.Cli/Commands/Harness/PiHookCommand.cs, the workItemsNudge assignment just before WriteMemoryFragment), so every restart or resume of the same session hands the extension the nudge again.

Same shape as #668 (Antigravity, per turn) and the Kiro repeat fixed by #697 (per prompt). The Pi repeat is per restart/resume rather than per turn, so it accumulates one duplicate per restart instead of one per turn. That is why it was carved out of #697 rather than fixed there. Sibling: #784 (OpenCode, same shape); one NudgeLease wiring pass can close both.

Read from source, not reproduced against a live Pi. A repro is two invocations of the hook for the same session file with --memory-contract >= 1, the second with reason=resume: the memory fragment appears once, the nudge appears both times.

Fix path

#697 introduced NudgeLease: a durable once-per-session claim riding SessionStartMemoryLeaseStore under a nudge-scoped key domain (SessionStartMemoryIdentity.CreateNudgeKey). It is harness-agnostic, and NormalizeSessionId already routes HarnessId.Pi through PiSessionPathCanonicalizer, so a nudge claim inherits the lease's identity semantics for free: resume deduped, fork eligible. Pass the session file path to the claim, as the memory lease does, not the derived session id.

Wire it the way KiroHookCommand does: start the claim beside the memory fetch, never let the fragment write wait on it, and refuse to emit on a repeat or an unavailable store. Kiro's deferred post-flush append exists because Kiro's ceiling is tight; check whether Pi's budget needs it or whether awaiting the claim bounded at the output site is enough.

The harness-setup nudge shares the call site but carries its own 6-hour evaluation throttle, which bounds it. Decide whether to fold it under the same claim (as #697 did for Kiro) or leave the throttle as the gate.

Activity

  1. linear-code commented on Sep 5, 2026

    @linear-code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions