Skip to content

feat(agent-org): add authoritative team lifecycle - #781

Open
ShiboSheng wants to merge 1 commit into
developfrom
fix/issue-756-authoritative-team-lifecycle
Open

feat(agent-org): add authoritative team lifecycle#781
ShiboSheng wants to merge 1 commit into
developfrom
fix/issue-756-authoritative-team-lifecycle

Conversation

@ShiboSheng

Copy link
Copy Markdown
Collaborator

Problem

Fixes #756.

The existing Agent Org lifecycle does not provide an authoritative, restart-safe boundary for a long-lived Team. Initial member creation can be resumed only through loosely coupled session state, finality is inferred by multiple paths, Run View and background recovery do not have a sufficiently strict read/write boundary, and the frontend retains fallback polling for states that should be quiet.

That model cannot safely support a Team that finishes one batch of work, becomes reusable and idle, and later accepts more work. It also makes identity duplication, stale quiescence decisions, accidental read-side writes, and retained background activity difficult to reject by construction.

Solution

This PR implements the first lifecycle slice from the long-lived Team design:

  • Persist Starting together with canonical member materialization receipts and the initial-input intent. Restart recovery continues the same (member_id, agent_id) identities instead of regenerating a Team.
  • Centralize formal-work quiescence facts and decisions across Turn, Task, Inbox, materialization, final-answer, generation, and work_revision state.
  • Allow the finalizer and the Working Watchdog to perform Working -> Idle only through a generation-and-revision conditional transition. Stale observations become no-ops.
  • Keep Run View bounded and pure-read. It projects the shared quiescence facts but cannot transition lifecycle state, claim Inbox rows, Wake a Member, perform recovery, or update timestamps.
  • Replace the unbounded/mixed watchdog work with one 60-second, running-only scan, LIMIT 100, and one 250 ms cooperative deadline shared by the entire tick.
  • Replace frontend polling of every non-terminal state with an explicit starting/running allowlist. Hidden windows and the last pollable subscriber destroy the shared timer; visibility recovery performs one immediate bounded revalidation.
  • Remove startup's blanket Running-to-Paused mutation. Starting recovery and plan-artifact repair remain separate one-shot owners rather than periodic Watchdog duties.
  • Put the entire redesign behind one fail-closed frontend/backend rollout gate, ORGII_AGENT_ORG_REDESIGN, which remains disabled by default.

The current compatibility wire value for Working remains running.

Potential risks

  • The lifecycle changes are intentionally cross-layer: launch, persistence, Turn finalization, Task/Inbox work revisions, Tauri projection, startup recovery, Watchdog inspection, and frontend subscription ownership must stay aligned. Unit, integration, hook, and packaged-runtime checks cover these boundaries, but future changes must continue using the centralized lifecycle APIs.
  • The redesign is an incomplete internal stack after PR1. If a release pipeline accidentally sets ORGII_AGENT_ORG_REDESIGN=1, users can reach Idle but cannot yet submit a new Root/Group/direct Turn or mutate the Task graph from Idle. The production default must remain disabled until the later stack is complete.
  • The Watchdog intentionally provides no fairness cursor. When more than 100 Working Teams exist, remaining Teams wait for a later tick; correctness continues to belong to event/finalizer owners rather than the Watchdog.
  • Schema changes are additive and initialization is idempotent. Rollback is to disable the rollout gate and revert the code; the additive receipt/progress rows can remain without affecting the gated-off product path. No destructive migration or automatic historical cleanup is included.
  • Running -> Idle uses a serialized generation/work_revision check. A concurrent work mutation wins by changing the revision, so the idle attempt becomes a no-op; later PRs must not introduce a second lifecycle owner or bypass that revision boundary.

Current implementation state

  • Starting owns first materialization and restart recovery. Successful construction ends in running when initial formal work exists or idle when it does not; unrecoverable construction ends in failed with structured diagnostics.
  • Idle means the current formal work is quiescent and the Team is retained. It is not a terminal Completed state.
  • Quiescence fails closed for unknown or inconsistent formal-work facts and validates the exact presented/observed work revision before idling.
  • Run View reads the same canonical facts in one bounded read transaction and has no mutation or Wake authority.
  • The global Watchdog scans only Working (status='running') Teams. Starting recovery is a one-shot launch/startup responsibility.
  • Frontend fallback polling has one shared owner and exists only while a visible subscriber still represents a starting or running Team.
  • The rollout gate is absent from Team settings, prompts, model tools, and persisted Team snapshots. Missing, malformed, 0, or true values remain disabled; only 1 enables the internal slice.

Scope boundaries and next-PR handoff

PR1 does not implement Pause/Resume redesign, Archive/Delete, the final Task FSM, additional Writers, UserDirectedWork, direct Member work, Group multi-mention, peer side quests, or the final Group read surface.

The enabled PR1-only intermediate state deliberately rejects new work from Idle:

  • Root/direct Turn submission returns team_idle.
  • Group Chat persistence rejects idle before writing an Inbox row.
  • Task graph mutation accepts only running and returns agent_org_run_not_mutable for Idle.
  • No Provider, Member Wake, or implicit Idle -> Working transition occurs.

PR7 is expected to add the atomic first Task graph plus Idle -> Working activation. PR8 opens direct Member UserDirectedWork, PR9 opens Group targeting and peer side quests, and PR10 completes the bounded Group read surface and default rollout. Earlier follow-up PRs must extend the frozen launch roster, generation, revision, and lifecycle transition APIs established here rather than creating another state owner.

Verification

Automated checks:

  • cargo test -p agent_core — passed on the frozen PR1 implementation before packaged acceptance.
  • pnpm typecheck — passed before packaged acceptance.
  • cargo clippy --all-targets -- -D warnings — passed again after fast-forwarding to the latest develop.
  • Commit hooks passed: lint-staged, scoped TypeScript checking, scoped Clippy for agent_core, org2, and session_persistence, ESLint 0, circular dependency count 0.
  • git diff --check upstream/develop..HEAD — passed.
  • The final PR diff contains no documentation files, local paths, credentials, temporary harnesses, caches, or build artifacts.

Packaged Tauri acceptance used a temporary packaged .app launched through macOS open, an isolated ORGII_HOME/SQLite database, isolated ports, a mock provider, and the redesign gate enabled in both frontend and backend:

  • Visible Running Team for five minutes: 6 successful Run View requests (one immediate plus five 60-second intervals), with one shared poll owner.
  • Hidden for 5 minutes 15 seconds: 0 Run View requests.
  • Visibility return: exactly 1 immediate revalidation, followed by the normal 60-second cadence.
  • Closing the last pollable Team subscriber and waiting more than 70 seconds: 0 residual Run View requests and no Timer/Provider/Wake activity.
  • RSS changed by 16 KB during the foreground window and by 112 KB during the hidden sample; hidden CPU samples were 0.0%.
  • Product refresh used Command+R. The before/after Run, progress, Task, Inbox, Turn-intent/Wake, recovery, session, and event snapshot was byte-identical; updated_at and work_revision did not change.
  • Watchdog observation covered 20 real ticks at 59,982-60,004 ms intervals. The query visited only Running rows with LIMIT 100; the shared scan used 9-25 ms of its 250 ms budget.
  • The exact temporary App PID was terminated after the test; both isolated listeners were gone.

Performance verdict: pass.

Visual screenshots are not included because this PR's meaningful acceptance evidence is lifecycle persistence, database immutability, API cadence, hidden-window behavior, and background-resource ownership rather than a visual layout change.

Establish durable Starting materialization receipts and a centralized quiescence boundary so Working teams enter Idle only from committed facts. Keep Run View pure-read, bound the global watchdog, and stop frontend polling for hidden or non-pollable teams behind one fail-closed rollout gate.

Verification:
- cargo clippy --all-targets -- -D warnings
- Packaged Tauri Command+5 foreground, hidden, and restore lifecycle passed
- Run View refresh left the isolated database byte-identical

Pre-commit hook ran. Total eslint: 0, total circular: 0
@ShiboSheng
ShiboSheng requested a review from Neonforge98 August 11, 2026 09:48
@ShiboSheng
ShiboSheng marked this pull request as ready for review August 11, 2026 10:35
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.

feat(agent-org): [1/10] add authoritative Team lifecycle, Idle, and a quiet watchdog

1 participant