The in-cluster runner posts one State Hub message (custodian-allocation-review -> the-custodian) per newly retained week, records the message id in receipts.jsonl, never reposts, and retries an undelivered week. New weekly_allocation_check.py flags a failed latest receipt or a missing report for the due ISO week (Monday 12:00 Europe/Berlin); security_flow_daily.py notifies once per distinct flag set and stays inactive until a receipts source is configured. Founder decision 2026-10-21 (T05 follow-up answers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9.9 KiB
Retained weekly allocation assessment
scripts/weekly_allocation_report.py implements the offline evidence join for
CUST-WP-0071-T05. It reads the existing cluster collector, Custodian allocation
reconcile, Prometheus query-response capture and resource-control inventory.
It performs no collection, deployment, network calls, task writes or delivery.
It is suitable for an accepted durable executor; it does not install one.
Inputs and retained evidence
The required inputs are:
--cluster:railiance.cluster-resource-observation.v1, produced by railiance-cluster'smake cluster-observe REMOTE=railiance01.--allocation:custodian.allocation-reconcile.v1fromscripts/reconcile_railiance_allocation.py, matching the same capture and workload inventory. Run both against the same retained observation.--telemetry: the existing September 28 query-capture shape:captured_at,window: 7d,step: 5m, andqueriesmapping each metric name to its exactpromqland Prometheusresponse. Preserve original sample evaluation times; do not restamp historical query results. These describe the query window, not independently verified raw scrape completeness.--inventory: resource-control'sdata/resources/reef-railiance-k3s.json. Dated portfolio capacity is retained as portfolio context, never summed with the live cluster or treated as current scheduler evidence.--provenance: exact source collector revisions andsource_observationmatching the cluster capture, as in the September 28 allocation provenance.--as-of: explicit evaluation timestamp; identical retries use the same value.--output: a new retained JSON path. Exact identical retries succeed; changed content at that path fails and requires an explicit revision path. Writes use a complete temporary file and atomic create-without-replacement publication.
Optional --previous selects the previous retained report. Deltas require the
same resource, exact query texts, sample step, seven-day window and consecutive
capture endpoints within one sample step. Other comparisons stay unknown; the
report still records disappeared workloads. Recommendation identity depends on
resource/namespace/workload/review purpose, not the date or recommendation text.
Existing receiving-task links survive retries and subsequent reports.
Metric names are cpu_p95_m, cpu_peak_m, memory_p95_bytes,
memory_peak_bytes, cpu_throttle_ratio, latency_p95_seconds, errors,
request_count, restarts, oom_events, cpu_sample_count and
memory_sample_count. Metrics are nonnegative, finite instant-vector aggregates.
Workload queries must carry exactly namespace and workload identity labels
(an optional Prometheus __name__ is allowed). Extra labels or duplicate series
are not silently aggregated. Namespace-only results are retained separately;
they never become per-workload values, even for a currently single-workload
namespace. Namespace peaks and percentiles are not additive.
Missing series, failed queries and non-finite values remain null with explicit reasons. Observed zero remains zero. Evaluation counts never prove raw scrape coverage. CPU/memory limits and instantaneous observations come from the cluster snapshot; historical latency, request/errors, OOM or throttling are not inferred from that snapshot. Unknown operating margin remains null; reservation residual does not establish processing capacity or release acceptance.
Owner decisions
Without a complete current owner review the result is investigate, with low
confidence and explicit evidence gaps. --reviews accepts a JSON mapping keyed
by the stable recommendation ID. A review provides decision (keep, increase,
decrease or investigate), owner, period_end matching telemetry capture,
reviewed_at, evidence_refs, receiving_task, configuration, rollback_ref,
coverage_ref, service_acceptance_ref, and margin_ref. Optional outcome
records what happened to the preceding recommendation. These references are
owner assertions to be checked during acceptance, not proof generated by this
adapter. Wrong-owner/window reviews, missing workload metrics, zero CPU requests,
unknown owners and stale/future evidence keep the result at investigate and
retain the proposal for review. No idle sample automatically recommends a cut.
Only new observation evidence and verified owner disposition can complete T02–T04. In particular, the historical Vergabe sample does not establish the attended two-user p95/error acceptance target or incremental database attribution.
Disabled execution contract
The owner-source candidate is
activity-core/activity-definitions/weekly-railiance-allocation-review.md.
Its fixed command is:
python3 scripts/weekly_allocation_report.py --request config/weekly-allocation-request.json
The request is intentionally unbound and the command fails until the accepted
executor supplies real input paths, a fixed as_of, and a durable output path.
Paths resolve relative to the request file. The executor must snapshot this
request per run, keep it stable for retries, bind a real previous report, and
retain reports beyond the seven-day raw-metric retention. The committed null
template is not a production storage location or collection implementation.
Activity Core source 4ae00fc selects its existing ADR-007 bounded-operation
executor with fixed owner commands; both definitions remain disabled. The prior
coding profile cannot run Python or reach the Hub. Runtime owners must still
bind accepted source/fleet mounts, separate private retained state and scoped
network access. Activity Core owns the Monday 08:00 Europe/Berlin schedule and
bounded-activity/context/progress-sink evidence, with one Temporal attempt.
The full binding contract is activity-core/docs/custodian-bounded-operations.md.
The adapter's matching recommendation IDs are the downstream upsert keys for
existing owner work records; it does not itself create those records. Delivery,
explicit owner acknowledgment, independent missed/failed-run detection and
recovery remain unbound. A report file or completed bounded activity alone proves none
of them. T05 needs the first unattended schedule receipt and exercised recovery.
Verification
python3 -m unittest discover -s tests -p test_weekly_allocation_report.py -v
The tests cover historical namespace-only input, missing/zero/NaN, invalid aggregation, query failure, compatible/incompatible periods, stable identities and owner-task links, stale/future evidence, owner review, resource/capture mismatch and retained retry/collision behavior.
In-cluster runner (CUST-WP-0071-T05, founder decision 2026-10-21)
docs/decisions/2026-10-21-cust-wp-0071-delivery-interview.md selects an
in-cluster Kubernetes CronJob for T05 and supersedes the Activity Core
placement above. scripts/weekly_allocation_incluster.py is the job entry
point. It is standard-library only and reuses the existing owner code
unchanged: railiance-cluster build_observation, reconcile.join (PyYAML is
now imported only by the reconcile CLI) and this adapter's build_report and
retain.
- Reads: the Kubernetes API through the pod ServiceAccount, with get/list on
nodes, pods, persistentvolumeclaims, persistentvolumes, storageclasses and
metrics.k8s.io nodes/pods only. Prometheus is reached through
PROMETHEUS_URLwithconfig/weekly-allocation-queries.json. - Week identity: the ISO week of (run time - 6h). The telemetry window ends at Monday 06:00 UTC, so consecutive windows are exactly seven days apart in CET and CEST. Prometheus keeps seven days of data, so the run must happen on the Monday. A 2026-10-21 (Wednesday) read-only dry run against railiance01 retained the report, but per-namespace CPU sample counts reached at most 1512 of 2016, because the window start had already expired.
- Retention:
<data>/reports/<YYYY>-W<ww>.json(create-without-replacement), per-attempt inputs under<data>/runs/<week>/<attempt>/, and an append-only<data>/receipts.jsonlwith statusretained,already-retainedorfailed, previous week,missed_weeks, comparability and failed queries. - Idempotency: a retained week is a no-op success. A failed attempt leaves no report, so the Job retry or a manual run collects again.
- Delivery (founder decision 2026-10-21, "Hub message + repo tasks"): with
STATE_HUB_URLset, each newly retained week produces one State Hub message fromcustodian-allocation-reviewtothe-custodian. The message carries a summary, the report path and its sha256, and its id is recorded inreceipts.jsonl. A week that already has a message id is never posted again. If a post fails, the receipt saysdelivery: failed, the Job exits 1, and its retry posts for the already-retained week. The next Custodian session reviews the report and records recommendations as tasks in the owner repositories (ADR-001). The job itself creates no tasks. - Missed/failed-run check:
scripts/weekly_allocation_check.py, whichscripts/security_flow_daily.pycalls. It flagsfailedwhen the latest receipt failed, andmissingwhen the due ISO week has no retained report (the current week falls due on Monday 12:00 Europe/Berlin). The agent is notified once per distinct flag set. It is inactive untilCUSTODIAN_ALLOCATION_RECEIPTS(or--allocation-receipts) is set tohub(delivery messages, where a failure shows as missing) or to a path holding a copy ofreceipts.jsonl. Set it ininfra/security-flow/only when the CronJob is activated. - Not done: owner acknowledgment. Workload rows stay
investigatebecause the queries are namespace-level. kube-state-metrics does not exportkube_pod_labels, so no workload-labelled series exist yet.
Executor manifests (suspended, not registered with ArgoCD) live in
railiance-platform argocd/platform-addons/custodian-allocation-review/, with
the draft Application in argocd/railiance01/drafts/.
python3 -m pytest tests/test_weekly_allocation_incluster.py tests/test_weekly_allocation_report.py -q