Skip to content

P0: stale HerdR agent states can permanently exhaust local execution capacity #256

Description

@James3014

Problem

A fresh #240 independent-review dispatch on the authoritative M5 DevSpace runtime was blocked by NO_EXECUTION_CAPACITY even though the four capacity holders were hours-old HerdR sessions with no physical candidate/effect in their workspaces.

Observed runtime identity:

  • DevSpace source: 973b507a157ddf16b8db2bc9349f691befee7c83
  • build: devspace-1.0.7-973b507a
  • server instance: 3e3391f1-eae1-46aa-9a97-577d30af9f86
  • convergence: CURRENT
  • configured local capacity: 4

agent_preflight for a clean isolated review checkout at exact HEAD a390c1db8cb22d77450b261ecae682cb41ea84c8 reported:

used=4
max=4
activeInWorkspace=0
activeOtherWorkspaces=4
dispatchState=BLOCKED
blocker=NO_EXECUTION_CAPACITY

Physical reconciliation evidence

The four slot holders were:

  1. agt_2cb0963f

    • durable state: starting
    • task: ISSUE-122-SEMANTIC-CLOSURE-COVERAGE-R2
    • agent_status: fails with HERDR runtime state without a durable handle
    • agent_reconcile: providerState UNKNOWN
    • workspace HEAD c6b36da657d39a1e834a437842d683c2916a5c71
    • clean, candidate absent, no changed paths
    • idle ~12.3M ms
  2. agt_2fa4ef09

    • durable state: starting
    • task: issue242-cline-public
    • agent_status: HerdR unreachable / identity unverified / prompt outcome unknown
    • agent_reconcile: providerState OUTCOME_UNKNOWN
    • workspace HEAD b8f4c965909caad7d3e03cbb941cf62171ae7e1e
    • clean, candidate absent, no changed paths
    • idle ~7.1M ms
  3. agt_2ae532ed

    • durable state: starting
    • task: issue242-public-grok-canary
    • agent_status: fails with HERDR runtime state without a durable handle
    • agent_reconcile: providerState UNKNOWN
    • workspace HEAD 27f69e16a4d9bb5123850c8d4457eb735c4cb868
    • clean, candidate absent, no changed paths
    • idle ~11.8M ms
  4. agt_435a5786

    • durable state: running
    • task: issue242-opencode-public-canary
    • agent_status: HerdR unreachable / identity unverified / prompt outcome unknown
    • agent_reconcile: providerState OUTCOME_UNKNOWN
    • workspace HEAD 27f69e16a4d9bb5123850c8d4457eb735c4cb868
    • clean, candidate absent, no changed paths
    • idle ~11.4M ms

No blind retry or cancellation was performed.

Source seam

Current capacity accounting uses:

this.store.list().filter(occupiesDetachedExecutionSlot)

and:

function occupiesDetachedExecutionSlot(record) {
  if (!isDetachedLifecycle(record.lifecycleState) || record.lifecycleState?.terminationBlocked) return false;
  return isActiveStatus(record.status) || Boolean(record.lifecycleState?.activeTurn) || hasTerminationBlock(record);
}

where isActiveStatus is exactly starting || running.

This means a durable record can continue consuming a slot indefinitely after HerdR live identity is lost unless some other lifecycle path transitions it out of the active state.

Required outcome

  1. Capacity must not remain permanently exhausted by stale HerdR records after a restart/lost-handle/unreachable-runtime condition.
  2. Recovery must remain fail-closed: OUTCOME_UNKNOWN must not become retry permission or be rewritten to “no effect”.
  3. Stale-slot recovery must reconcile the exact durable attempt and physical workspace before releasing capacity.
  4. If the runtime cannot prove terminality, expose an explicit recoverable capacity state/action instead of silently leaking the slot forever.
  5. agent_preflight should distinguish live active capacity from stale/unreconciled capacity.
  6. Regression must cover lost durable handle, unreachable HerdR identity, headless restart, clean/no-candidate case, and a hostile case where physical effects are present/unknown and therefore capacity cannot be released.

This issue is separate from #240 caller/projection continuity. It was discovered because it blocked #240's independent reviewer dispatch.


Reconciliation — 2026-09-25 lifecycle-family consolidation

Fresh source fence:

  • DevSpace main: 80a238da61112cabf18bcb44a912e3f0daceba2d
  • tree: a62dc9b3f74536b7770f9b7ad4b0528685430227

Recent bounded fixes have closed several concrete stale-capacity variants, including:

Those fixes are useful evidence, but they do not establish that the whole stale-lifecycle family is closed. Keep this Issue as the umbrella owner for the remaining lifecycle invariant rather than creating one Issue per newly discovered stale state.

Required lifecycle matrix before closure

Classify and verify at minimum the cross-product of:

durable status:
  starting | running | cancelling/closing | terminal

durable handle:
  present | absent | malformed/stale

HerdR observation:
  present | exact-not-found | unreachable | identity-mismatch | outcome-unknown

workspace/effect evidence:
  clean/no-candidate | candidate/effect-present | unknown

restart boundary:
  same process | DevSpace restart | HerdR restart

For every releasable state, prove why capacity release is safe.
For every ambiguous/unknown-effect state, prove capacity remains fail-closed without minting retry authority.

Closure requirement

Do not close #256 from a list of individually fixed branches. Closure requires one current-main state-transition matrix plus hostile regression coverage showing that:

  • stale records cannot permanently consume capacity when exact terminal/absence evidence exists;
  • OUTCOME_UNKNOWN / unreachable / identity-unverified states are not rewritten into absence;
  • exact attempt/workspace identity remains bound;
  • capacity accounting and agent_preflight distinguish live, safely reclaimable, and unresolved slots.

Architecture class: TEMPORAL_COUPLING + MISSING_CANONICAL_WIRING.

Exact next gate:

HERDR_LIFECYCLE_CAPACITY_STATE_MATRIX_AND_RECONCILIATION_PROOF

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions