Skip to content

🤖 refactor: extract a pure goal continuation policy from workspaceGoalService - #4009

Open
ibetitsmike wants to merge 4 commits into
mainfrom
mike/arch-goal-policy
Open

🤖 refactor: extract a pure goal continuation policy from workspaceGoalService#4009
ibetitsmike wants to merge 4 commits into
mainfrom
mike/arch-goal-policy

Conversation

@ibetitsmike

Copy link
Copy Markdown
Contributor

Summary

Extracts the goal-continuation decision logic out of WorkspaceGoalService into a pure, synchronous policy module (goalContinuationPolicy.ts). The service becomes the I/O shell (file locks, goal-file reads/writes, chat-tail sync, analytics/timeline emission) around a single decision point that returns a discriminated union: continue | defer(untilMs) | stop(reason, dropCandidate).

Background

workspaceGoalService.ts (5,401 lines) interleaved continuation decisions with I/O: checkGoalContinuationEligibility mixed in-memory candidate maps, runtime-bridge probes, gated goal-file reads, normalizeGoalLimits (a locked read-modify-write with chat-tail reconciliation), one-shot budget wrap-up gating, and cooldown math. The decision had no interface of its own, so testing one cooldown branch required a real session directory, file locks, and mocked services. Refactor #9 of the 2026-08-29 architecture review, based on main @ f04e0f8. Behavior-preserving.

Implementation

  • evaluateGoalContinuation(state) mirrors the previous branch order and candidate-disposition semantics exactly; every skip reason keeps its value (they feed logs and CLI eligibility hints).
  • A staged probe (evaluateGoalContinuationBeforeGoal) preserves the pre-existing I/O gating: undefined probe fields mean "not gathered yet", so the shell still performs no goal-file read while the workspace is busy/streaming and runs normalizeGoalLimits only after all runtime gates pass.
  • Pure helpers moved with it: budget/turn-cap limit checks, budget-driven status transitions (applyBudgetDrivenStatus, now takes nowMs), wrap-up origin eligibility, and the cost micro-cent helpers.
  • Per ADR-0004, interactive and CLI goal runs drive the same policy with different inputs: continuationCooldownMs (CLI: 0) and allowUserOriginBudgetWrapup (CLI: true) are plain policy-state fields; no CLI-vs-interactive conditionals in the policy. checkGoalContinuationEligibility keeps its public shape, so src/cli/goalRunDriver.ts is untouched.
  • Stateful race guards stay in the shell unchanged: admissionStale generation probes, dispatch closures, pause/terminal/identity generations, chat-tail reconciliation.

Net LOC (vs f04e0f8)

  • Production: +126 (+342/-216)
  • Tests: -151 (+350/-501)
  • Combined: -25

The production increase is the cost of giving the decision an explicit interface: the policy-state/probe/decision types (~70 lines) had no prior representation (state was implicit in service fields and closure context), and the staged-probe evaluation preserving I/O gating adds ~15 lines. All decision branches were moved, not duplicated; the service shed the same logic plus its duplicated cost helpers. On the test side, 42 table-driven pure cases (zero filesystem, zero mocks) replace 18 disk-harness permutation tests; all stateful race-invariant and shell-wiring tests were retained.

Validation

  • Remote dogfood UAT (Coder Agents, real UI + real model, unmodified 60s cooldown) passed all five live goal scenarios on the pushed SHA: continuation fire + cooldown defer, turn-cap flip to budget_limited with exactly one wrap-up, re-arm on cap raise/removal, pause/manual-message suppression of pending continuations, and the user Stop acknowledgment gate.
  • make static-check and whole-file runs of the five goal-related test suites (290 tests) are green.

Risks

Behavior-preserving refactor of race-sensitive logic; the main risk is decision/branch-order fidelity. Mitigated by mirroring the branch order exactly (reviewable side by side in the diff), leaving every stateful race guard in the shell untouched, retaining the race-invariant test suite, and live UAT of the continuation lifecycle.


Xum acted on Mike's behalf. Generated with xum • Model: anthropic:claude-fable-5 • Thinking: xhigh • Cost: $37.87

@chatgpt-codex-connector

This comment has been minimized.

@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 43783b0ddb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

This comment has been minimized.

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