Skip to content

RFC-64 M1 5/7: activate role-aware adaptive Core capacity - #2014

Open
branarakic wants to merge 12 commits into
codex/rfc64-m1-adaptive-primitivesfrom
codex/rfc64-m1-adaptive-capacity
Open

RFC-64 M1 5/7: activate role-aware adaptive Core capacity#2014
branarakic wants to merge 12 commits into
codex/rfc64-m1-adaptive-primitivesfrom
codex/rfc64-m1-adaptive-capacity

Conversation

@branarakic

@branarakic branarakic commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

M1 stack

This is PR 5 of 7 in the RFC-64 M1 stack.

  1. RFC-64 M1 1/2: make Edge CG sync explicitly on-demand #2011 — explicit Edge synchronization lifetime
  2. RFC-64 M1 2/7: expose verified VM and SWM convergence #2012 — truthful selected-CG VM/SWM convergence
  3. RFC-64 M1 3/7: bound Core public CG coverage #2013 — bounded Core public-CG coverage
  4. RFC-64 M1 4/7: add adaptive capacity primitives #2015 — adaptive-capacity primitives and policy-owned admission
  5. This PR — role-aware adaptive Core activation and status
  6. Bounded operator-only runtime evidence hooks
  7. Fail-closed M1 acceptance verifier and real-runtime release launcher

Exact stack provenance:

  • Base: RFC-64 M1 4/7: add adaptive capacity primitives #2015 at 43768351aee0d4c93e86bddf065197ed6aced496
  • Head: 6992dd36ec23bf298e039ad5fd7a9b517b7a855d
  • Range-diff: all twelve layer commits are patch-identical to the previously pushed stack
  • Test-only follow-up: initializes stopSampling() in the lifecycle test double; no production constructor or runtime behavior changes
  • Review-fix follow-up: closes the environment hard-limit, pure backlog-demand, config-contract, and agent-boundary coverage findings
  • Lifecycle-test follow-up: proves a real Core DKGAgent.start() starts adaptive sampling and supplies the live coverage-demand callback
  • Runtime-boundary follow-up: hides the raw admission policy, centralizes pressure/ceiling observation, proves lifecycle admission uses the live runtime policy, and unifies internal Core planning
  • Single-owner follow-up: resolves the effective Core coverage batch once at the agent boundary and gives the scheduler and adaptive runtime that same immutable value

Summary

This PR activates the adaptive-capacity primitives for Core nodes only and exposes the policy actually enforced at runtime through /api/status.

It adjusts two independent forms of Core synchronization pressure:

  1. requester sync concurrency; and
  2. the automatic public-CG coverage batch added to each peer-sync round.

Edge nodes remain static and continue synchronizing only their explicitly selected CGs. This PR does not turn Edge nodes into all-public-CG replicas.

User and operator impact

For Core nodes:

  • A Core with no explicit global sync limit defaults to adaptive mode.
  • It starts conservatively and grows only under sustained healthy demand.
  • It reduces requester concurrency and automatic coverage breadth under host or store pressure.
  • Explicitly selected CGs remain included even when automatic coverage shrinks.
  • A truncated automatic-coverage batch counts as recovery demand, so healthy Cores recover even when requester work finishes between samples.
  • /api/status.syncCapacity reports the canonical agent-owned mode, state, current/min/max concurrency, current/configured coverage batch, store-telemetry availability, and last decision.

For Edge nodes:

  • Synchronization remains static and selected-only.
  • Edge does not gain automatic public-CG coverage.
  • Even an explicit adaptive enable does not activate adaptation on Edge.

Before this PR

sequenceDiagram
    participant A as DKGAgent
    participant P as Core coverage planner
    participant Q as Global admission
    participant S as Triple store

    A->>A: Resolve one static sync limit
    A->>P: Plan selected CGs plus fixed public batch
    P->>Q: Submit all planned work
    Q->>Q: Apply static inflight limit
    Q->>S: Run admitted work
Loading

The static limit and fixed automatic batch could not react to host, event-loop, heap, or store pressure.

After this PR

sequenceDiagram
    actor O as Operator
    participant A as DKGAgent
    participant R as SyncCapacityRuntime
    participant M as Host and store sampler
    participant C as Adaptive controller
    participant P as Core coverage planner
    participant Q as Global admission policy
    participant S as Triple store

    A->>R: Resolve role, config, hardMax, and queue bound
    alt Edge or statically configured Core
        R->>Q: Install static policy
    else Adaptive Core
        R->>Q: Install policy-owned currentLimit callback
        loop Bounded sampling interval
            R->>Q: Read inflight and queued demand
            R->>P: Check truncated automatic coverage
            R->>M: Sample demand, CPU, heap, event loop, and store queues
            M->>C: Report bounded pressure signals
            C-->>R: Current requester limit and coverage batch
            R->>Q: Notify admission when capacity grows
        end
    end

    A->>P: Plan selected CGs with current automatic batch
    Note over P: Explicit selections are never capped
    P->>Q: Submit planned work
    Q->>Q: Enforce current limit and hardMax-bounded backlog
    Q->>S: Run admitted work
    Note over Q,S: Downshifts drain without cancelling running work
    O->>A: GET /api/status
    A->>R: getStatus()
    R-->>O: Return exact enforced syncCapacity state
Loading

Resolution policy

Node and configuration Result
Edge, with or without adaptive opt-in Static and selected-only
Core, no explicit global limit Adaptive by default
Core, explicit positive global limit Static unless adaptation is explicitly enabled
Core, explicit adaptive enable Adaptive within operator, hardware, store, and absolute ceilings
Any node, explicit global limit 0 Existing unbounded behavior; adaptation disabled
Core, explicit adaptive disable Static

Global-limit precedence remains:

  1. DKG_SYNC_GLOBAL_MAX_INFLIGHT
  2. legacy DKG_SYNC_GLOBAL_LIMIT
  3. syncGlobalMaxInflight
  4. legacy syncGlobalLimit
  5. default

Malformed adaptive min/max values fail fast instead of silently widening load. The public syncAdaptiveCapacity config shape is preserved through CLI-to-agent wiring and remains omitted when the operator does not configure it.

Controller behavior and compatibility

  • Critical ACK/health queue pressure, heap pressure, or event-loop pressure halves capacity immediately.
  • Sustained ordinary pressure reduces capacity by one.
  • Recovery grows one step after sustained healthy demand and cooldown.
  • No demand or ambiguous telemetry holds steady.
  • Missing store telemetry prevents growth above the conservative floor.
  • Automatic coverage never exceeds syncCorePublicBatchSize; 0 remains disabled.
  • The adaptive policy's effective hardMax also bounds its admission backlog; the queue cannot grow to a ceiling the runtime can never drain.
  • Adaptive policy construction treats the derived hardMax as final and cannot reapply a larger global-limit environment value; the independently configured queue limit still retains its normal precedence.
  • Running admissions are not revoked on a downshift.
  • Existing explicit Core limits remain static unless the operator opts in.
  • SyncCapacityRuntime owns admission options, pressure and ceiling observation, demand aggregation, sampling, queue-pump notification, status, and timer cleanup.
  • ACK and health reservations remain outside adaptive requester capacity.
  • Backpressure accounting is process-global; production's one-agent-per-process model is safe. Multi-agent embedders remain a documented follow-up for runtime-scoped accounting.

Review feedback incorporated

  • Core automatic-coverage backlog now contributes recovery demand.
  • Adaptive admission and sampling orchestration now live behind SyncCapacityRuntime.
  • /api/status no longer fabricates a second fallback capacity model.
  • Runtime-level tests prove pressure-driven shrink, healthy recovery, effective coverage changes, and queued-work pumping.
  • Final admission wiring uses RFC-64 M1 4/7: add adaptive capacity primitives #2015's policy-owned resolveSyncGlobalBackpressure(config, currentLimit) boundary.
  • All internal Core planning uses RFC-64 M1 4/7: add adaptive capacity primitives #2015's typed planAutomaticCoverageWithOptions boundary and the runtime-owned effective batch. The existing three-argument planAutomaticCoverage wrapper remains unchanged for outside callers.
  • The Windows/full-lane lifecycle fixture now supplies the runtime-owned stopSampling() method expected during agent shutdown. Production construction was already correct; this is test-double parity only.
  • Coverage recovery demand is computed directly from the current selected CGs and live batch; it no longer depends on whichever peer plan ran most recently.
  • Config-level adaptive opt-out and valid min/max bounds now have positive runtime tests.
  • Agent-boundary tests prove both branches: static Core preserves its configured batch, while adaptive Core honors a constrained live batch without capping explicit selections.
  • A real-agent lifecycle test proves startup invokes adaptive sampling once and that its supplemental-demand callback reads the current effective coverage batch before delegating to the Core coverage scheduler.
  • A discriminating lifecycle test proves sync admission uses the runtime-owned live policy: runtime capacity 1 queues a second request even when raw config would allow 2.
  • Lifecycle logging and ACK diagnostics observe pressure and resolved ceilings through SyncCapacityRuntime; the branded raw policy is private.
  • DKGAgentBase is now the single owner of Core coverage-batch resolution. The scheduler and SyncCapacityRuntime receive the same resolved value, so an environment change during startup cannot make their effective limits diverge.

Validation on final head

  • Focused agent adaptive/runtime/backpressure/scheduler suites: 5 files / 81 tests passed.
  • Focused adaptive/lifecycle/scheduler lane: 5 files / 76 tests passed.
  • Agent-boundary discovery/subscription suite: 17 tests passed.
  • Combined lifecycle, boundary, runtime, scheduler, controller, sampler, and backpressure lane: 7 files / 120 tests passed.
  • Exact Windows-workflow SQLite persistence selection: 14 files / 218 tests passed, 5 skipped.
  • Focused CLI wiring/status suites: 3 files / 12 selected tests passed (7 unrelated tests skipped by the focused status filter).
  • Agent build: TypeScript, public type tests, and package-root test passed.
  • The prior dependency-aware build also passed 17 workspace packages, including CLI TypeScript and runtime-asset copy; this final base movement was test-only.
  • git diff --check: passed.
  • Live GitHub review and CI status remain the final merge-readiness source of truth.

Rollout risk

Moderate but bounded. The default changes only for Core nodes without an explicit global limit. It cannot enable automatic coverage on Edge, exceed the configured Core batch, exceed the lowest applicable capacity ceiling, or queue beyond the effective adaptive hard maximum.

Review focus

  1. Role/config resolution preserves Edge and explicit-Core compatibility.
  2. Pressure causes fast reduction and slow recovery within hard ceilings.
  3. The exact PR RFC-64 M1 3/7: bound Core public CG coverage #2013 peer-round scope remains bounded when batch size changes.
  4. Policy-owned admission, runtime status, and legacy environment precedence describe the same enforced limit.

Comment thread packages/agent/src/dkg-agent-lifecycle.ts Outdated
Comment thread packages/agent/src/dkg-agent-lifecycle.ts Outdated
Comment thread packages/cli/src/daemon/routes/status.ts Outdated
Comment thread packages/agent/src/sync/capacity-runtime.ts
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-primitives branch from 9c848db to c5b9ec1 Compare August 2, 2026 12:10
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-capacity branch from 85ca405 to 69c1dec Compare August 2, 2026 12:19
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-primitives branch from c5b9ec1 to 5685115 Compare August 2, 2026 12:24
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-capacity branch from 69c1dec to 072249e Compare August 2, 2026 12:29
Comment thread packages/agent/src/dkg-agent-base.ts Outdated
Comment thread packages/agent/src/sync/core-public-coverage-scheduler.ts Outdated
Comment thread packages/agent/src/dkg-agent-base.ts Outdated
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-primitives branch from 4b83ea1 to e7bbbac Compare August 2, 2026 12:53
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-capacity branch from 072249e to b166ef8 Compare August 2, 2026 12:59
Comment thread packages/agent/src/dkg-agent-lifecycle.ts
Comment thread packages/agent/src/sync/capacity-runtime.ts Outdated
Comment thread packages/agent/src/sync/capacity-runtime.ts
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-primitives branch from a6fa200 to 264d92d Compare August 2, 2026 14:13
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-capacity branch from 8be9d57 to 13759eb Compare August 2, 2026 14:22
Comment thread packages/agent/src/sync/capacity-runtime.ts
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-primitives branch from 264d92d to aa41669 Compare August 2, 2026 15:16
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-capacity branch from 13759eb to 5793aed Compare August 2, 2026 15:20
@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-primitives branch from aa41669 to 4376835 Compare August 2, 2026 15:46

@otReviewAgent otReviewAgent left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Operational Notice: Review Agent could not complete this review.

Business logic reviewer failed: retry_exhausted

@branarakic
branarakic force-pushed the codex/rfc64-m1-adaptive-capacity branch from 5793aed to 6992dd3 Compare August 2, 2026 15:49

@otReviewAgent otReviewAgent left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Operational Notice: Review Agent could not complete this review.

Business logic reviewer failed: retry_exhausted

diagnosticsAvailable: '/api/diagnostics/backpressure',
},
corePublicSyncCoverage,
syncCapacity,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Public status now exposes detailed adaptive sync pressure

What's wrong
The new status field publishes detailed node-local resource and sync-capacity information on an endpoint that is explicitly public. That creates an information disclosure surface for operational pressure and capacity limits, which can help external callers time load against the node or fingerprint its resource envelope.

Example
An unauthenticated caller can poll GET /api/status and observe syncCapacity.lastDecision.reason === 'critical_heap' or currentInflight dropping from 4 to 1, revealing when the node is under resource pressure and how much sync capacity remains. Previously the public status response kept detailed backpressure diagnostics behind /api/diagnostics/backpressure.

Suggested direction
Return only a coarse public capacity state from /api/status, or require/admin-gate the detailed syncCapacity fields alongside the existing backpressure diagnostics.

Confidence note
This assumes /api/status is intentionally unauthenticated for remote callers, which is supported by the route/auth allowlist in the surrounding code.

For Agents
Look at packages/cli/src/daemon/routes/status.ts where syncCapacity is added to the public status body. Preserve a coarse public health signal if needed, but move detailed capacity numbers and lastDecision to an admin-authenticated diagnostics route or redact them from unauthenticated status. Add a route-level test proving unauthenticated /api/status does not expose pressure reasons or capacity internals, while admin diagnostics can still inspect them.

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.

2 participants