Task · SKT-0015.01

Make the DPM floor a per-blueprint opt-in override with a configurable ceiling

Description

Today runner.Options.MinMetricInterval is a single process-wide 60s value, defaulted in Options.defaults() (internal/runner/runner.go:97) and never set from internal/config. Runner.clampInterval (:499) raises any construct or workload interval below it and logs the clamp. That has to become per-blueprint and opt-in.

Shape to build:

The budget-window trap, which is the reason this subtask is not a two-line change. blueprintLoop builds budgetReset := time.NewTicker(r.opts.MinMetricInterval) (internal/runner/runner.go:698) and resets bp.budget on it. res.SeriesBudget is therefore a per-DPM-floor-window budget. If a blueprint’s floor drops to 10s and the budget ticker follows it, that blueprint’s effective per-minute series allowance multiplies by six with nothing in the logs saying so. Decide the semantics deliberately and write the decision into the code comment: either pin the budget window to a fixed 60s independent of the floor, or keep it tied to the floor and rescale SeriesBudget so the per-minute allowance is unchanged. Do not leave it implicit. RunOnce (:591) also resets the budget once per cycle and must stay consistent with whichever is chosen.

Also check the scheduler can actually deliver the cadence. MasterTick defaults to 5s, so a 10s interval has two master fires per window and works; a floor below MasterTick cannot be honoured at all and must be rejected at load with a message naming TICK_DEFAULT. The dropped-tick detection in blueprintLoop and phaseOffset (:507) both assume instances spread across an interval — verify a short interval does not resynchronise them onto one master tick.

Correct the documentation that states the floor as absolute: ARCHITECTURE.md (§ the Interval contract, and I10), docs/architecture.md, docs/RUNBOOK.md, internal/core/core.go:174, internal/workload/app/app.go:12, internal/construct/host/host.go:34. State the override and its ceiling; do not delete the rationale for the floor existing.

Acceptance Criteria

Definition of Done

Implementation Plan

TDD an explicit per-blueprint high_dpm metric interval, validate it against the configurable default-10s ceiling and TICK_DEFAULT, keep each blueprint series budget defined per fixed 60s window in live and RunOnce paths, wire config/docs/schema, and prove two simultaneous floors.

Implementation Notes

Implementation decision: high_dpm.metric_interval is the effective cadence for every metric-bearing instance in that blueprint, not merely a lower clamp bound; otherwise existing 60s catalog intervals would never speed up. SeriesBudget is defined as a fixed 60s per-blueprint window independent of cadence. RunOnce retains the same window boundary across calls. Runtime load rejects intervals below TICK_DEFAULT first, then intervals exceeding MAX_DPM_PER_SERIES (default 6). Focused config/blueprint/bpsource tests are green; runner verification is pending Lane B reaching a stable fenced tree.

Clarification after review: the ceiling is rate-based. Validation derives DPM as 60s / high_dpm.metric_interval and rejects it when that rate exceeds MAX_DPM_PER_SERIES; the TICK_DEFAULT lower-bound check remains separate and runs first.

Implemented high_dpm.metric_interval as an explicit per-blueprint override for metric-bearing instances, MAX_DPM_PER_SERIES default 6, separate TICK_DEFAULT validation, fixed-minute SeriesBudget semantics shared by live and RunOnce paths, and preserved log-only cadences. Generated schema and focused config/blueprint/bpsource/runner tests pass; go build ./…, go vet ./…, and go test ./… pass.

Final evidence: explicit high_dpm.metric_interval applies per blueprint, MAX_DPM_PER_SERIES defaults to 6, intervals below TICK_DEFAULT or above the ceiling fail loudly, log-only cadence is preserved, series budgets reset on a fixed minute, phase spreading remains effective, schema generation passed, and the integrated make gate passed.

Final Summary

Added the explicit per-blueprint high-DPM cadence override with a configurable default-6-DPM ceiling, fixed-minute budget semantics, RunOnce parity, scheduler validation, and corrected architecture/configuration documentation.

View the source file on GitHub