Skip to content

fix(summary-maintenance): enforce lifecycle legality and raw fallback - #317

Merged
zzylol merged 3 commits into
mainfrom
fix/summary-lifecycle-legality
Sep 2, 2026
Merged

zzylol merged 3 commits into
mainfrom
fix/summary-lifecycle-legality

Conversation

@zzylol

@zzylol zzylol commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Stacked on #316.

Why

#316 enumerates lifecycle alternatives, but enumeration alone is not enough: a lifecycle must be rejected when its bound consumers, timing, data arrival, summary operations, or evidence cannot support the physical guarantee it promises.

This PR makes those checks explicit and fail-closed before lifecycle cost ranking.

Exact mechanism implemented

1. Bind lifecycle demand to the consumers of this target

plan_summary_maintenance_lifecycles now receives WorkloadDemand { workload, entry_indices } instead of treating every entry in the workload as a consumer of every materialized target.

The binding is validated before planning:

  • an empty binding returns EmptyWorkloadDemand;
  • an out-of-range index returns InvalidWorkloadEntry; and
  • a repeated index returns DuplicateWorkloadEntry.

Only the bound entries contribute invocation counts, recurring reads, evaluation rate, preparation eligibility, and time-scope requirements. This prevents unrelated workload entries from manufacturing reuse for a summary.

2. Derive conservative workload facts

For the bound entries, workload_facts computes:

  • total known reads;
  • one-time invocation count;
  • recurring evaluation rate;
  • fresh ingestion/update rate;
  • source-data arrival mode;
  • a preparation window;
  • whether every consumer is eligible for prepared state; and
  • whether the query time scope requires deletion of expired input.

Scheduled recurrence counts only executions inside [now, now + horizon]. Unknown recurrence or stale evidence remains unknown instead of being converted to zero.

3. Enforce prepared-state timing

Prepared state is offered only when every bound consumer is a predictable one-time query with both known_at and execute_at.

For each consumer the planner requires:

known_at < execute_at
now < execute_at

The emitted activation time is:

max(known_at, now)

Across several eligible consumers, the deployment uses the earliest valid activation and latest execution as its preparation window. Consequently, the planner cannot emit a prepared deployment whose activation or retirement is already in the past, and retention/maintenance cost is charged only from the current planning time forward.

If any bound consumer is ad hoc, repeated, unknown, incompletely scheduled, or expired, the prepared alternative is rejected with RequiresPredictableOneTimeQuery.

4. Ask the concrete summary what operations it supports

The CostModel gains:

fn summary_maintenance_capabilities(
    &self,
    summary: &SummaryNode,
) -> SummaryMaintenanceCapabilities

SummaryMaintenanceCapabilities records incremental_update, merge, and delete. Its default is deliberately conservative: all capabilities are false.

In this PR, lifecycle legality consumes the update and deletion flags:

  • prepared, shared, and continuously maintained state over continuously ingesting or mixed data requires incremental_update;
  • a moving real-time or mixed lookback (lookback present, no fixed as_of) additionally requires delete; and
  • missing support produces SummaryDoesNotSupportIncrementalUpdates or SummaryDoesNotSupportDeletion before cost ranking.

The merge capability is part of the capability contract for composed summaries, but this PR does not add a separate merge-legality rule.

Ephemeral state is not subjected to these retained-state update/delete requirements because it is rebuilt for each invocation.

5. Preserve the maintenance mode on rejected alternatives

Every alternative—including rejected ones—retains the mode it would use:

  • ephemeral uses DirectBuild;
  • retained state over at-rest or unknown data uses DirectBuild; and
  • retained state over continuously ingesting or mixed data uses Incremental.

This keeps rejection explanations physically meaningful instead of losing whether the refused plan required a direct build or incremental maintenance.

6. Add summary and raw cost-accounting hooks

The plan now records:

  • expected_reads;
  • summary_total_cost for the selected lifecycle of every deployment;
  • raw_recompute_total_cost; and
  • selected_raw_recompute.

The CostModel also gains raw_query_recompute_cost(target), whose conservative default is None.

This PR establishes the data and extension points needed for raw fallback. It does not perform the final materialization-time summary-vs-raw comparison; #318 wires these fields into global selection/materialization and performs that fallback.

Lifecycle checks by alternative

Alternative Additional legality enforced here
Ephemeral Runtime support and complete cost evidence
Prepared Every bound consumer is a future predictable one-time execution; retained-state update/delete capabilities when data arrives
Shared More than one known read, explicit horizon, and retained-state update/delete capabilities when data arrives
ContinuouslyMaintained Continuous or mixed arrival, fresh ingestion rate, explicit horizon, incremental-update support, and deletion support for moving windows

After these checks, only alternatives with no rejection and a complete total cost are selectable. Missing information never makes a long-lived lifecycle win.

Rejection reasons added

  • SummaryDoesNotSupportIncrementalUpdates
  • SummaryDoesNotSupportDeletion

Existing rejection reasons continue to represent unsupported runtime lifecycle shapes, unsuitable predictability, insufficient reads, missing horizon, incompatible arrival mode, stale ingestion evidence, and missing cost evidence.

Tests added

Coverage verifies that:

  • unrelated workload entries do not create reuse;
  • empty, duplicate, and invalid demand bindings fail explicitly;
  • prepared state requires every bound consumer to qualify;
  • expired prepared executions are rejected;
  • prepared activation is clamped to planning time;
  • scheduled rates count only executions inside the horizon;
  • moving real-time maintenance requires deletion support;
  • stale ingestion evidence cannot enable continuous maintenance; and
  • explicit root-to-workload-entry bindings remain correct when root order differs from normalized workload order.

Verification

  • cargo test -p asap-aware-mapping summary_maintenance_lifecycle --no-fail-fast
  • cargo clippy -p asap-aware-mapping --all-targets -- -D warnings
  • Full stacked workspace tests and clippy pass.

Stack

Base: #316. Next: #318.

@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from fa3781f to 47bc52b Compare August 30, 2026 18:21
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 9806c0a to 495b664 Compare August 30, 2026 18:21
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from 47bc52b to c188ea7 Compare August 30, 2026 18:30
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 495b664 to 4015f26 Compare August 30, 2026 18:30
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from c188ea7 to 26a9fbd Compare August 30, 2026 18:35
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 4015f26 to 944df5d Compare August 30, 2026 18:35
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from 26a9fbd to 65b03da Compare August 30, 2026 18:46
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 944df5d to 621fb5e Compare August 30, 2026 18:46
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from 65b03da to 5749311 Compare August 30, 2026 19:03
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 621fb5e to 5adb5f1 Compare August 30, 2026 19:03
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from 5749311 to cc53386 Compare August 30, 2026 21:22
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 5adb5f1 to 158002a Compare August 30, 2026 21:22
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from cc53386 to d2584ef Compare August 30, 2026 21:27
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 158002a to 3df3599 Compare August 30, 2026 21:27
@zzylol
zzylol force-pushed the feat/summary-lifecycle-alternatives branch from d2584ef to 7a2f232 Compare August 31, 2026 12:04
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch 2 times, most recently from c9334fc to 5e564bd Compare August 31, 2026 12:17
@zzylol zzylol changed the title fix(lifecycle): enforce deployment legality and raw fallback fix(summary-maintenance): enforce lifecycle legality and raw fallback Aug 31, 2026
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 5e564bd to 8db7940 Compare August 31, 2026 12:35
@zzylol
zzylol force-pushed the fix/summary-lifecycle-legality branch from 8db7940 to 27296e7 Compare August 31, 2026 12:45
@zzylol

zzylol commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

@milindsrivastava1997 This relates to what you said about adding constraints to the edges between nodes for their capability and schema checking.

@zzylol
zzylol changed the base branch from feat/summary-lifecycle-alternatives to main September 2, 2026 00:55
@zzylol
zzylol merged commit 722ccd1 into main Sep 2, 2026
1 check passed
@zzylol
zzylol deleted the fix/summary-lifecycle-legality branch September 7, 2026 15:51
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.

1 participant