Skip to content

[DEV-105] Make automatic conflict resolution in workspace mode configurable: run immediately or on a schedule (e.g. nightly) to reduce AI token spend - #96

Open
danii1 wants to merge 3 commits into
mainfrom
feature/dev-105
Open

[DEV-105] Make automatic conflict resolution in workspace mode configurable: run immediately or on a schedule (e.g. nightly) to reduce AI token spend#96
danii1 wants to merge 3 commits into
mainfrom
feature/dev-105

Conversation

@danii1

@danii1 danii1 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Task: DEV-105

Summary: Make automatic conflict resolution in workspace mode configurable: run immediately or on a schedule (e.g. nightly) to reduce AI token spend

Implementation Details

I'll start by exploring the codebase to understand the existing conflict-resolution flow and scheduling patterns.
Now let me look at the supporting pieces: worker-state cursors, the webhook queue base-sync API, docs, and existing config tests.
I have a good picture now. Let me check a few remaining details: the automation-config tests, exhaustBaseSyncEvent/hasProcessed, and parseEnvInteger.
I now have the full picture. Let me plan the work:
Starting with the shared schedule parser in automation-config.ts:
Now add the shared validation helper and occurrence helper, and refactor parseAutomationEntries to use them:
I introduced a duplicate-error issue: stringValue("cron") and the helper both validate the raw values. Since the locals are no longer used, remove them:
Now refactor nextAutomationDue to delegate to the shared helper:
It's in automation-acquirer.ts:
Now the workspace config parsing:
Now the parsing logic inside parseWorkspaceConfig:
Now the poller — the core of this task. First the imports and options:
Now the module-level constants and window-state type:
Now the class changes — state members, start() logging, tick() sync, and the gate:
Now add the window-management private methods at the end of the class:
Now wire it into the workspace worker:
Now the workspace init template:
Now the tests. First, extend makeAcquirer in the poller test file:
Now add the scheduled-mode tests to the poller test file:
Now the workspace config tests:
Now add nextScheduleOccurrence / parseCronOrIntervalSchedule tests to the automation-config test file:
Now the docs. First workspaces.md — the sample config and a dedicated section:
Now worker.md — extend the "Merge conflicts on the agent's PRs" section:
Now verify — typecheck and the relevant tests:
Typecheck passes. Run the tests directly with bun:
All 63 pass. Now the full suite plus lint and format:
Let me verify none of the lint warnings come from my changes:
One new warning from my refactor — the now-unused CronExpressionParser import in automation-acquirer.ts:
Now a final review of the full diff:
One comment in the gate is slightly inaccurate about what happens after a manual fix — the pending event isn't completed by polling, it's simply never executed because GitHub stops reporting a conflict:
Final verification — full typecheck, lint, format, and test run:
DEV-105 is implemented. All checks pass: typecheck 11/11, lint 0 errors, 1028 tests green.

What was built

Config (workspace.toml, [workspace]config.ts:63, config.ts:250):

conflict_resolution = "scheduled"        # default "auto" — no upgrade behavior change
conflict_resolution_cron = "0 3 * * *"   # or conflict_resolution_interval = "1d"; exactly one

Validation reuses the [[automations]] format via a new shared helper parseCronOrIntervalSchedule / nextScheduleOccurrence (automation-config.ts:15, automation-config.ts:109); parseAutomationEntries was refactored onto the same helper (identical error messages, multi-error collection preserved). Strict validation: invalid mode, missing/duplicate/invalid schedule keys, or schedule keys without scheduled mode all fail config load.

Poller gate (review-polling-acquirer.ts:630, syncConflictWindow at :743): the existing resolveConflicts seam is now gated on a durable window state (persisted as a worker:conflict-window cursor). Outside the window, conflicts are still detected and queued as pending base-sync events — the agent is never invoked. When the scheduled occurrence arrives, a grace window (WORKER_RESOLVE_WINDOW_GRACE_MINUTES, default 60) opens and all queued conflicts resolve through the existing backoff/quiet-period/revalidation machinery. Windows missed while the worker was down catch up on the first tick after restart; each window gets a fresh defer budget; stale/merged PRs are skipped by the existing mergeability checks.

On demand: devintern resolve-conflicts <pr-url> is untouched — a manual fix means GitHub stops reporting dirty, so the queued event never triggers an agent run.

Startup surfacing: the worker logs the active mode, e.g. ⏰ [poll:reviews] conflict resolution: scheduled (cron "0 3 * * *"); next window … or conflict resolution: auto (review-polling-acquirer.ts:820).

Edge cases covered: human mid-review pushes → quiet period + never-force-push unchanged; shutdown mid-run → cursor + pending events survive restart; review feedback is never delayed by scheduled mode (only base-sync is gated).

Tests (+15): config parsing/validation (7), schedule helper (3), poller scheduled-mode behavior — queue-before-window, resolve-in-window, re-queue after grace, restart catch-up, manual-resolve interplay, startup mode logging (5). Docs: both docs/code/workspaces.md (new "Automatic conflict resolution: auto vs scheduled" section incl. token-cost tradeoff) and docs/code/worker.md (new "Scheduled conflict resolution" subsection), plus the workspace init template.


This PR was automatically created by @devintern/code

danii1 added 3 commits August 28, 2026 15:23
…pace mode configurable: run immediately or on a schedule (e.g. nightly) to reduce AI token spend
…lict resolution off entirely

[workspace].conflict_resolution = "disabled" now opts a workspace out of
automatic base-sync on the agent's PRs: no detection, no queuing, no agent
runs. Conflicted PRs stay conflicted until resolved by hand or via
`devintern resolve-conflicts <pr-url>`. Review feedback and @mentions are
unaffected, and the worker logs the disabled mode at startup.
# Conflicts:
#	packages/code/tests/workspace-config.test.ts
@danii1

danii1 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

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