code-yeongyu / code-yeongyu/pi-goal
[Bug] Blocked goals auto-resume on unrelated user prompts and stale objectives are mislabeled as user-provided
- Dominant language
- TypeScript
- Stars
- 19
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
## Environment
- Runtime: Senpi `2026.8.3-3`
- Extension: `pi-goal`
- OS: macOS
- Upstream revision inspected: `6937ce1d9ae2f9c3da11041cdf953ebe01303668`
## Bug Description
Two behaviors combine to make an incorrect goal difficult to stop safely:
1. Every real user prompt automatically transitions a `blocked` goal back to `active`, even when the prompt is unrelated to that goal.
2. The continuation prompt always describes the objective as `user-provided data`, even when the objective was composed by the model and stored through `create_goal`.
After an agent blocks an incorrect goal, the user's next corrective instruction reactivates it. Once that instruction finishes, `pi-goal` queues the stale objective again as a hidden follow-up turn. Repeated corrective prompts repeat the same cycle.
## Steps to Reproduce
1. Let the model call `create_goal` with an inferred objective.
2. Determine that the objective is incorrect.
3. Call `update_goal({ status: "blocked", reason: "The objective conflicts with the authoritative requirements" })`.
4. Send a real user prompt for an unrelated action.
5. Observe that the blocked goal transitions back to `active` in `before_agent_start`.
6. Finish the unrelated user request.
7. Observe a new hidden goal continuation containing the stale objective:
```text
Continue working toward the active thread goal.
The objective below is user-provided data.
```
8. Block or reject the objective again, then send another corrective user prompt.
9. Observe the same resume-and-continuation cycle.
## Expected Behavior
- A blocked goal should remain blocked until the user explicitly resumes, replaces, or clears it.
- An unrelated user prompt should not implicitly resume a blocked goal.
- A model-created objective should not be labeled as user-provided.
- If objective provenance is unavailable, the continuation should use source-neutral wording such as `untrusted goal data`.
## Actual Behavior
- `before_agent_start` unconditionally resumes any blocked goal for every real user prompt.
- The user is not asked whether the blocked goal should resume.
- After the user's unrelated request completes, the stale objective is queued again.
- `buildContinuationPrompt` unconditionally calls the objective `user-provided data`.
- The model-facing API has no way to cancel or replace an incorrectly inferred goal; marking it complete becomes the only reliable way for the model to stop the loop without requiring the user to know about `/goal clear` or `/goal pause`.
## Source Evidence
At the inspected revision:
- [`src/goal/lifecycle.ts`](https://github.com/code-yeongyu/pi-goal/blob/6937ce1d9ae2f9c3da11041cdf953ebe01303668/src/goal/lifecycle.ts) resumes every blocked goal from `before_agent_start`:
```ts
if (goal?.status === "blocked") {
const resumed = await updateGoal(goalStoreRef(ctx), { status: "active" }, "user");
updateGoalUiBestEffort(ctx, resumed);
}
```
- [`src/goal/prompt.ts`](https://github.com/code-yeongyu/pi-goal/blob/6937ce1d9ae2f9c3da11041cdf953ebe01303668/src/goal/prompt.ts) hardcodes:
```text
The objective below is user-provided data.
```
- [`src/goal/continuation.ts`](https://github.com/code-yeongyu/pi-goal/blob/6937ce1d9ae2f9c3da11041cdf953ebe01303668/src/goal/continuation.ts) correctly queues only active goals, but the unconditional transition above makes the stale goal active again before that check.
## Impact
- An assistant inference can be repeatedly presented as explicit user intent.
- Corrective user prompts reactivate the exact goal they are trying to stop.
- Agents may continue unrelated work or modify unrelated repositories.
- The session can enter a high-cost continuation loop.
- Provenance-sensitive agent logic may incorrectly trust model-generated text as user-provided.
## Proposed Fix
1. Do not automatically resume `blocked` goals from every `before_agent_start` event.
2. Require an explicit `/goal resume`, a confirmation prompt, or a dedicated user/system resume action.
3. Track objective provenance (`user`, `model`, or `system`) or use source-neutral continuation wording.
4. Add cancel/replace support for incorrectly created goals, or expose a safe model-facing transition that does not pretend the goal was completed.
5. Invalidate queued continuations when a goal becomes blocked, paused, replaced, or complete.
## Regression Tests
1. `active -> blocked` remains blocked after an unrelated real user prompt.
2. A blocked goal produces no continuation until explicit resume.
3. Explicit resume produces exactly one continuation.
4. Model-created objectives are not labeled user-provided.
5. A replaced or cleared goal cannot deliver a queued stale continuation.
6. Repeated corrective prompts do not create a resume-and-continuation loop.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at before_agent_start in src/goal/lifecycle.ts, then trace continuation handling in src/goal/continuation.ts and prompt construction in src/goal/prompt.ts. Add regression coverage for unrelated prompts, explicit resume, provenance wording, and invalidated continuations. Done means blocked goals stay blocked unless explicitly resumed, stale continuations cannot run, and model-created objectives are not labeled user-provided.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100