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

Merged
danii1 merged 3 commits into
mainfrom
feature/dev-105
Aug 29, 2026
Merged

[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 merged 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.

@danii1 danii1 added the devintern-authored Pull request written by DevIntern working its own backlog label Aug 29, 2026
@danii1
danii1 merged commit 8958b9a into main Aug 29, 2026
1 check passed
@danii1
danii1 deleted the feature/dev-105 branch August 29, 2026 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devintern-authored Pull request written by DevIntern working its own backlog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant