P0 ARDR research: one total StarIntel runtime thread budget #164

Open
opened 2026-08-29 10:28:05 +00:00 by nsaspy · 0 comments
Owner

StarIntel problem solved

Research the open P0 implementation gap in lost-rob0t/starintel-server#34: StarIntel currently configures multiple actor/consumer/task/HTTP/timer execution pools independently, so one nominal concurrency knob can multiply OS threads instead of enforcing one bounded process-wide runtime budget.

Owning issue: lost-rob0t/starintel-server#34.
Current starintel-server/master inspected at e99aadd3f44505bc692708aad5e34ab0c4ab0036.

ARDR state

READY_FOR_DESIGN

Implementation approval remains operator-only.

Why this is selected

This is an actual open P0 server issue and is dependency-ready as a design/research target. It outranks lower-priority OSINT enhancement research for this cycle.

Verified StarIntel-specific failure model

The owning issue documents that current runtime capacity is split across several independent execution sources:

  • Sento shared-dispatcher workers;
  • a custom dispatcher configured under the reserved :pinned dispatcher identifier;
  • multiple Rabbit consumer groups, each creating worker threads;
  • event consumers;
  • a separate lparallel kernel;
  • producer and CouchDB pinned agents;
  • target/GC/timeout/scheduler timers;
  • Hunchentoot worker threads.

The practical defect is not merely “too many threads.” The architecture currently lacks one authority that can answer before startup whether the composed runtime can fit inside the operator's declared thread ceiling.

Research conclusion

StarIntel needs one runtime resource-budget authority owned by the server runtime/component layer, not by individual actors and not by StarLang syntax.

Every runtime component that can create or reserve OS threads must declare its thread demand before activation. Startup computes a closed budget plan, rejects impossible configurations before side effects, then gives components only the allocation they were granted.

Required model

Define a runtime budget contract equivalent to:

RuntimeThreadBudget {
  maxTotal,
  reservedControl,
  fixedOverhead,
  allocations[]
}

ThreadAllocation {
  componentId,
  class,
  requested,
  granted,
  minimum,
  maximum,
  elastic?,
  owner
}

Execution classes should distinguish at least:

  • actor/control dispatcher;
  • actor/data dispatcher;
  • Rabbit owner/reactor/consumer workers;
  • storage workers;
  • CPU task workers;
  • HTTP workers;
  • timer/scheduler threads;
  • transport/runtime fixed overhead;
  • explicitly pinned actors where unavoidable.

Core invariants

  1. One ceiling — total runtime-owned OS threads may never exceed max-process-threads plus explicitly documented non-runtime VM/foreign-library overhead.
  2. Reserve control capacity — health, shutdown, lease renewal, supervision and control traffic retain guaranteed execution capacity during data-plane saturation.
  3. No hidden thread creation — runtime components may not call raw thread constructors outside registered component/runtime adapters.
  4. No multiplicative reuse of one knob — ingest-workers = N cannot silently become N workers in several unrelated pools.
  5. Startup fail-fast — unsatisfiable requested minima fail before long-lived services are started.
  6. Observed-vs-declared check — runtime diagnostics report declared allocations and live owned-thread counts so leaks/drift are visible.
  7. Lifecycle ownership — every owned thread maps to a runtime component and is joined/stopped by that component/runtime, aligning with #37.
  8. Bounded queue coupling — worker allocations must be usable by #36 admission/mailbox/prefetch sizing; adding workers without queue bounds is not a complete fix.

StarLang classification

No new StarLang language syntax is justified.

  • budget declaration and allocation are host/runtime configuration and component lifecycle concerns;
  • StarLang-defined actors/domain servers may expose a resource profile/capability descriptor if needed, but cannot create threads directly or override runtime grants;
  • Common Lisp runtime owns dispatcher/executor construction and enforcement;
  • no Python/external process is justified.

Component registration strategy

Every thread-producing subsystem should register a closed resource profile before startup realization.

Example categories:

registerThreadDemand(:platform/control, min=2, max=4, fixed=false)
registerThreadDemand(:platform/storage, min=2, max=8, fixed=false)
registerThreadDemand(rabbit-owner, min=1, max=1, fixed=true)
registerThreadDemand(http, min=2, max=16, fixed=false)

The planner allocates from the operator ceiling using deterministic policy. Components receive explicit granted counts; they do not re-read global concurrency knobs independently.

Allocation policy research decision

Keep v1 deterministic and boring:

  1. subtract fixed/runtime-overhead declarations;
  2. reserve control minimums;
  3. satisfy every required component minimum;
  4. reject startup if minima exceed the ceiling;
  5. distribute remaining capacity according to explicit configured desired counts/caps;
  6. never auto-scale above declared grants in v1.

Do not add adaptive autoscaling to solve the initial correctness bug.

Interaction with existing P0 issues

  • #35 workload-specific dispatchers consume allocations from this budget; they do not invent a second pool-sizing authority.
  • #36 bounded mailboxes/admission control derives pull/in-flight ceilings from actual granted processing capacity.
  • #37 managed lifecycle owns all allocated thread resources and verifies shutdown cleanup.
  • Rabbit prefetch/consumer worker configuration must be derived from granted Rabbit processing capacity rather than a hard-coded global worker count.

Adversarial findings

Rejected:

  1. Just lower all defaults — does not prevent multiplicative configuration or future hidden pools.
  2. Count threads after startup only — detects the defect after side effects/resources already exist.
  3. Let each actor choose its own dispatcher size — no process-wide authority; recreates oversubscription.
  4. One giant executor for everything — storage/blocking work can starve control/lease/shutdown traffic; #35 needs workload isolation.
  5. Treat timers/HTTP/foreign runtimes as free — systematic undercount.
  6. Reuse reserved dispatcher names such as :pinned for custom pools — semantic collision and misleading configuration.
  7. Dynamic autoscaling in v1 — unnecessary complexity before deterministic budget enforcement exists.
  8. Only test configured counts — must compare live runtime-owned threads against the declared plan.

RED-first research output

The first implementation slice must start with a deterministic configuration fixture that describes multiple thread-producing components whose requested allocations exceed max-process-threads and prove untouched current server startup does not reject the configuration through a single budget validator.

Additional RED target: a fixture where one ingest-workers value is independently consumed by multiple subsystems must demonstrate the computed total exceeds the intended ceiling.

Decision

Research is sufficient to proceed to design. No unresolved architecture question requires human research validation.

Implementation approval: PENDING / AWAITING_OPERATOR_APPROVAL.

## StarIntel problem solved Research the open P0 implementation gap in `lost-rob0t/starintel-server#34`: StarIntel currently configures multiple actor/consumer/task/HTTP/timer execution pools independently, so one nominal concurrency knob can multiply OS threads instead of enforcing one bounded process-wide runtime budget. Owning issue: `lost-rob0t/starintel-server#34`. Current `starintel-server/master` inspected at `e99aadd3f44505bc692708aad5e34ab0c4ab0036`. ## ARDR state `READY_FOR_DESIGN` Implementation approval remains operator-only. ## Why this is selected This is an actual open P0 server issue and is dependency-ready as a design/research target. It outranks lower-priority OSINT enhancement research for this cycle. ## Verified StarIntel-specific failure model The owning issue documents that current runtime capacity is split across several independent execution sources: - Sento shared-dispatcher workers; - a custom dispatcher configured under the reserved `:pinned` dispatcher identifier; - multiple Rabbit consumer groups, each creating worker threads; - event consumers; - a separate lparallel kernel; - producer and CouchDB pinned agents; - target/GC/timeout/scheduler timers; - Hunchentoot worker threads. The practical defect is not merely “too many threads.” The architecture currently lacks one authority that can answer **before startup** whether the composed runtime can fit inside the operator's declared thread ceiling. ## Research conclusion StarIntel needs one **runtime resource-budget authority** owned by the server runtime/component layer, not by individual actors and not by StarLang syntax. Every runtime component that can create or reserve OS threads must declare its thread demand before activation. Startup computes a closed budget plan, rejects impossible configurations before side effects, then gives components only the allocation they were granted. ## Required model Define a runtime budget contract equivalent to: ```text RuntimeThreadBudget { maxTotal, reservedControl, fixedOverhead, allocations[] } ThreadAllocation { componentId, class, requested, granted, minimum, maximum, elastic?, owner } ``` Execution classes should distinguish at least: - actor/control dispatcher; - actor/data dispatcher; - Rabbit owner/reactor/consumer workers; - storage workers; - CPU task workers; - HTTP workers; - timer/scheduler threads; - transport/runtime fixed overhead; - explicitly pinned actors where unavoidable. ## Core invariants 1. **One ceiling** — total runtime-owned OS threads may never exceed `max-process-threads` plus explicitly documented non-runtime VM/foreign-library overhead. 2. **Reserve control capacity** — health, shutdown, lease renewal, supervision and control traffic retain guaranteed execution capacity during data-plane saturation. 3. **No hidden thread creation** — runtime components may not call raw thread constructors outside registered component/runtime adapters. 4. **No multiplicative reuse of one knob** — `ingest-workers = N` cannot silently become N workers in several unrelated pools. 5. **Startup fail-fast** — unsatisfiable requested minima fail before long-lived services are started. 6. **Observed-vs-declared check** — runtime diagnostics report declared allocations and live owned-thread counts so leaks/drift are visible. 7. **Lifecycle ownership** — every owned thread maps to a runtime component and is joined/stopped by that component/runtime, aligning with #37. 8. **Bounded queue coupling** — worker allocations must be usable by #36 admission/mailbox/prefetch sizing; adding workers without queue bounds is not a complete fix. ## StarLang classification No new StarLang language syntax is justified. - budget declaration and allocation are host/runtime configuration and component lifecycle concerns; - StarLang-defined actors/domain servers may expose a resource profile/capability descriptor if needed, but cannot create threads directly or override runtime grants; - Common Lisp runtime owns dispatcher/executor construction and enforcement; - no Python/external process is justified. ## Component registration strategy Every thread-producing subsystem should register a closed resource profile before startup realization. Example categories: ```text registerThreadDemand(:platform/control, min=2, max=4, fixed=false) registerThreadDemand(:platform/storage, min=2, max=8, fixed=false) registerThreadDemand(rabbit-owner, min=1, max=1, fixed=true) registerThreadDemand(http, min=2, max=16, fixed=false) ``` The planner allocates from the operator ceiling using deterministic policy. Components receive explicit granted counts; they do not re-read global concurrency knobs independently. ## Allocation policy research decision Keep v1 deterministic and boring: 1. subtract fixed/runtime-overhead declarations; 2. reserve control minimums; 3. satisfy every required component minimum; 4. reject startup if minima exceed the ceiling; 5. distribute remaining capacity according to explicit configured desired counts/caps; 6. never auto-scale above declared grants in v1. Do not add adaptive autoscaling to solve the initial correctness bug. ## Interaction with existing P0 issues - #35 workload-specific dispatchers consume allocations from this budget; they do not invent a second pool-sizing authority. - #36 bounded mailboxes/admission control derives pull/in-flight ceilings from actual granted processing capacity. - #37 managed lifecycle owns all allocated thread resources and verifies shutdown cleanup. - Rabbit prefetch/consumer worker configuration must be derived from granted Rabbit processing capacity rather than a hard-coded global worker count. ## Adversarial findings Rejected: 1. **Just lower all defaults** — does not prevent multiplicative configuration or future hidden pools. 2. **Count threads after startup only** — detects the defect after side effects/resources already exist. 3. **Let each actor choose its own dispatcher size** — no process-wide authority; recreates oversubscription. 4. **One giant executor for everything** — storage/blocking work can starve control/lease/shutdown traffic; #35 needs workload isolation. 5. **Treat timers/HTTP/foreign runtimes as free** — systematic undercount. 6. **Reuse reserved dispatcher names such as `:pinned` for custom pools** — semantic collision and misleading configuration. 7. **Dynamic autoscaling in v1** — unnecessary complexity before deterministic budget enforcement exists. 8. **Only test configured counts** — must compare live runtime-owned threads against the declared plan. ## RED-first research output The first implementation slice must start with a deterministic configuration fixture that describes multiple thread-producing components whose requested allocations exceed `max-process-threads` and prove untouched current server startup does **not** reject the configuration through a single budget validator. Additional RED target: a fixture where one `ingest-workers` value is independently consumed by multiple subsystems must demonstrate the computed total exceeds the intended ceiling. ## Decision Research is sufficient to proceed to design. No unresolved architecture question requires human research validation. Implementation approval: `PENDING / AWAITING_OPERATOR_APPROVAL`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/starintel-auto-research#164
No description provided.