Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
625 changes: 625 additions & 0 deletions docs/0.7-planning-brief.md

Large diffs are not rendered by default.

439 changes: 439 additions & 0 deletions docs/0.7-roadmap.md

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions docs/adr/033-per-key-execution-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# ADR-033: Per-key execution control (tiered)

## Status

Proposed — number claimed; full design tracked in [#340](https://github.com/hardbyte/awa/issues/340) and experiment E5 in [`docs/0.7-roadmap.md`](../0.7-roadmap.md).

## Context

Awa controls execution at queue granularity only. Multi-tenant workloads need per-key
concurrency limits ("at most N in-flight per customer") and fairness across keys within a
queue. The binding constraint from #169: no per-key counter family may become a new hot
mutable table under a pinned MVCC horizon.

## Decision (to be developed)

Tiered delivery per roadmap decision D4:

- **Tier 1 (committed):** worker-local per-key rate limiting and concurrency caps via
`InsertOpts::concurrency_key` + per-queue `KeyPolicy` — exact per worker, approximate across
a fleet (documented formula), zero storage footprint.
- **Tier 2 (experiment-gated):** fleet-exact concurrency via claim-time key-window checks,
only if E5 finds a design with zero new hot mutable rows and bounded claim-path cost.

## Relationship to other ADRs

Composes with ADR-005 (priority aging), ADR-010 (rate limiting), ADR-011 (weighted
concurrency), ADR-025 (enqueue shards — `concurrency_key` defaults to `ordering_key`), and
ADR-026 (the delta-ledger discipline any per-key state must follow).
27 changes: 27 additions & 0 deletions docs/adr/034-job-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ADR-034: Job dependencies (single-parent A→B on ADR-029)

## Status

Proposed — number claimed; full design tracked in [#14](https://github.com/hardbyte/awa/issues/14) per roadmap decision D7 in [`docs/0.7-roadmap.md`](../0.7-roadmap.md).

## Context

"Run B after A completes" currently requires the handler to insert the next job manually.
ADR-029 already delivers transactional follow-up enqueues atomically with the parent's guarded
finalization — the mechanism exists; what is missing is a declarative parking state and a
failure policy.

## Decision (to be developed)

- `InsertOpts::after(JobRef)` parks B in the deferred backlog in a `waiting_on` state.
- A's guarded finalization transactionally promotes B (success) or applies B's declared
`on_parent_failure` policy: `Cancel` (default) | `EnqueueWithContext` | `Discard`.
- Exactly one parent. Fan-in, fan-out, DAGs, and workflow state are **non-goals** (the PRD's
"not a workflow engine" boundary; #81 guards it).
- TLA+ witness required for the promote-on-finalize race (parent finalizes concurrently with
child cancel).

## Relationship to other ADRs

Builds directly on ADR-029 (transactional follow-up jobs); composes with ADR-019 deferred
storage; bounded by the ADR/PRD workflow non-goal.
27 changes: 27 additions & 0 deletions docs/adr/035-backpressure-flow-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ADR-035: Backpressure and producer flow control

## Status

Proposed — number claimed; full design tracked in [#341](https://github.com/hardbyte/awa/issues/341) and experiment E6 in [`docs/0.7-roadmap.md`](../0.7-roadmap.md).

## Context

Nothing stops producers from outrunning completion; the COPY path (ADR-008) makes it trivial
(measured: ~9,982/s enqueue vs ~4,016/s completion, depth 1.26M). Rejecting an enqueue inside a
user transaction (ADR-006) converts a queue-health condition into a business-transaction
failure, so hard rejection can never be the silent default.

## Decision (to be developed)

- **Soft-signal default, opt-in hard rejection**: enqueue paths can return a depth signal
(`EnqueueOutcome::pressure`) sourced from lane-head cursors (index-only, no scans);
`InsertOpts::backpressure: Off | Signal | Reject{limit}` with `Reject` returning a typed
error and documented as changing transactional-enqueue semantics.
- `PacedProducer` helpers in Rust and Python (the pattern the benchmark harness already proved
externally).
- Metrics: `awa.enqueue.backpressure.{signaled,rejected}`.

## Relationship to other ADRs

Tensions with ADR-006 (transaction surface) made explicit; reads via the #289/#330 cursor
signals; composes with ADR-025/031 throughput levers rather than replacing them.
24 changes: 24 additions & 0 deletions docs/adr/036-public-surface-stability-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# ADR-036: Public surface stability policy

## Status

Proposed — number claimed; policy text drafted in [`docs/stability.md`](../stability.md) (Draft),
tracked in [#369](https://github.com/hardbyte/awa/issues/369) per roadmap decision D6.

## Context

Awa has at least six consumable surfaces — Rust API, Python API, the SQL enqueue contract
(#342), the HTTP admin API (#143), metric names/attributes, and the CLI — with no written
statement of what is stable. Polyglot producers and API consumers cannot exist without one.

## Decision (to be developed)

Publish and maintain `docs/stability.md`: a surface-by-surface compatibility map, a
deprecation policy (announce in N, warn in N+1, remove in N+2 barring security), and explicit
internal/unstable designations (storage schema internals, `done_entries` physical layout,
undocumented SQL).

## Relationship to other ADRs

Governs the ADR-016 adapter contract and the #342 SQL producer contract; constrains all future
ADRs that touch a listed surface.
25 changes: 25 additions & 0 deletions docs/adr/037-canonical-engine-deprecation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# ADR-037: Canonical engine deprecation and removal

## Status

Proposed — number claimed; tracked in [#370](https://github.com/hardbyte/awa/issues/370) per roadmap decision D2 in [`docs/0.7-roadmap.md`](../0.7-roadmap.md).

## Context

The canonical (row-mutating) engine exists only as the 0.5→0.6 transition source since
queue-storage became the default (ADR-019, 0.6.0). Keeping it alive taxes every feature with
dual-engine implementation, tests (#360), and docs — the tax that shipped the #359 defect.

## Decision (to be developed)

- 0.7 `awa migrate` refuses to run unless storage state is `active` (or the install is fresh),
with a refusal message naming the exact 0.6 finalize steps.
- Canonical formally deprecated in 0.7 (release notes, docs, startup warning).
- Claim/execution/trigger paths removed in 0.8; upgrades step 0.5 → 0.6 (finalize) → 0.7.
- Reversal condition: beta feedback showing a meaningful population stuck mid-transition for
reasons Awa can fix.

## Relationship to other ADRs

Completes the ADR-019 supersession of the pre-0.6 storage model; bounds the #360 dual-engine
test matrix; interacts with the staged-transition tooling decisions recorded on #180.
5 changes: 5 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ Template: `Status / Context / Decision / Consequences (positive, negative) / Alt
| 030 | [Durable batch operations for operator bulk mutation](030-batch-operations.md) | Accepted | Filter-driven async bulk mutation with preview, progress, cancellation, retention, and maintenance-led execution; v0.6 starts with `set_priority` and `move_queue` | Refines ADR-019/025 operator mutation paths; complements ADR-028 |
| 031 | [Partitioned queues](031-partitioned-queues.md) | Accepted | First-class logical queue partitioning over ordinary physical queues, with domain-separated key routing and Python per-job COPY opts | Composes ADR-019/023/026 storage guarantees; refines the ADR-025 sharding interaction |
| 032 | [Failed terminal retention floor](032-failed-terminal-retention.md) | Accepted | Queue-storage prune carries in-floor `failed` terminal rows forward into the live segment as wide synthetic rows so they stay retryable for at least `failed_retention`; rows aged past the floor are folded into `queue_terminal_rollups.pruned_failed_count` and surfaced via `QueueCounts.pruned_failed` | Amends ADR-026's one-retention-unit consequence; refines ADR-019 terminal prune path |
| 033 | [Per-key execution control](033-per-key-execution-control.md) | Proposed | Tiered per-key concurrency limits and fairness: worker-local exact / fleet-approximate first, storage-exact only if it needs zero new hot mutable rows (#340) | Composes ADR-005/010/011/025; bound by ADR-026's ledger discipline |
| 034 | [Job dependencies](034-job-dependencies.md) | Proposed | Single-parent A→B chaining: `waiting_on` parking state promoted transactionally by the parent's guarded finalization, with an `on_parent_failure` policy (#14) | Builds on ADR-029; workflow engine remains a non-goal |
| 035 | [Backpressure and flow control](035-backpressure-flow-control.md) | Proposed | Soft depth signals from lane-head cursors by default, opt-in hard rejection, paced-producer helpers (#341) | Makes the ADR-006 transactional-enqueue tension explicit; composes ADR-025/031 |
| 036 | [Public surface stability policy](036-public-surface-stability-policy.md) | Proposed | Surface-by-surface compatibility map and deprecation policy, published as `docs/stability.md` (#369) | Governs ADR-016 and the #342 SQL producer contract |
| 037 | [Canonical engine deprecation](037-canonical-engine-deprecation.md) | Proposed | 0.7 migrate gate requires a finalized queue-storage transition; canonical paths removed in 0.8 (#370) | Completes ADR-019's supersession of the pre-0.6 model |

## Validation artifacts

Expand Down
56 changes: 56 additions & 0 deletions docs/stability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Public Surface Stability Policy

> **Status: Draft** — introduced by [`0.7-roadmap.md`](0.7-roadmap.md) decision D6, pending
> ADR-036 acceptance. Tracked in [#369](https://github.com/hardbyte/awa/issues/369). Until
> accepted, this document describes intent, not promises.

Awa is consumed through several distinct surfaces. This document states, per surface, what is
covered by a compatibility promise, what is explicitly internal, and what each release type may
change. Anything not listed here is **internal** and may change in any release without notice.

## Release types (pre-1.0)

While Awa is pre-1.0, "minor" releases (0.6 → 0.7) play the semver-major role:

| Release type | May contain |
| --- | --- |
| **Patch** (0.7.0 → 0.7.1) | Bug fixes only. No breaking changes to any listed surface. No new migrations except to fix a defective migration. |
| **Minor** (0.7 → 0.8) | Breaking changes to listed surfaces are allowed **only** with: a changelog entry under "Breaking changes", a migration path in the upgrade guide, and — where feasible — a deprecation period per the policy below. |
| **Beta / RC** | Surfaces may change between pre-release tags of the same line (the 0.6 `QueueFanout` → `PartitionedQueue` rename is the precedent). Pre-release tags promise nothing to each other; the stable tag promises everything below. |

## Deprecation policy

Announce in release N (changelog + doc note), warn at runtime in N+1 where the surface makes a
runtime warning possible, remove in N+2. Security fixes may compress this schedule; the
changelog will say so explicitly.

## Surfaces

| Surface | What is covered | What is not |
| --- | --- | --- |
| **Rust API** (`awa`, `awa-model`, `awa-macros`, `awa-testing`, `awa-seaorm`) | All `pub` items documented on docs.rs. Semver-checked in CI (planned: `cargo-semver-checks`). | `#[doc(hidden)]` items; anything behind an unstable feature flag; `awa-worker`/`awa-ui` internals not re-exported by `awa`. |
| **Python API** (`awa-pg`) | Everything exported by `awa/__init__.py` and typed in the `.pyi` stubs (stub/API drift gated in CI per [#378](https://github.com/hardbyte/awa/issues/378)). Async and `_sync` counterparts per ADR-009. | Underscore-prefixed members; the raw PyO3 module layout. |
| **SQL producer contract** | `awa.insert_job_compat(...)` per [#342](https://github.com/hardbyte/awa/issues/342): signature, semantics, BLAKE3 `unique_key` derivation, `ordering_key` → shard hash. Versioned against `awa.schema_version`; conformance script provided. | Every other function, table, view, and trigger in the `awa.*` schema. Direct DML against storage tables is unsupported. |
| **Terminal read surface** | `{schema}.terminal_jobs` (per ADR-026) and the documented public views. | `done_entries` physical layout and all segment/ring/ledger internals — compact batches mean not every completed job is physically a `done_entries` row. |
| **HTTP admin API** | Versioned response types published by the `awa-api` crate ([#143](https://github.com/hardbyte/awa/issues/143)) once split. | Handler internals; the embedded UI's asset paths; any endpoint not documented in `ui-design.md`. |
| **Callback receiver contract** | The signed callback endpoints (ADR-018/021/027): paths under the configured prefix, signature scheme, payload shapes, error mapping. Identical between embedded router and `awa callbacks serve`. | — |
| **CLI** | Documented commands, their exit codes, and `--json` output schemas (e.g. `awa doctor`, `awa storage status`). | Human-readable (non-`--json`) output formatting. |
| **Metrics** | Metric names, types, and attribute keys listed in the telemetry docs. | Attribute *values* cardinality; bucket boundaries (may be tuned in minors with a changelog note). |
| **Storage schema / migrations** | The migration *path*: `awa migrate` upgrades any supported prior version's schema (support window per [#367](https://github.com/hardbyte/awa/issues/367) and ADR-037's gate). | Schema contents. Tables, indexes, functions, and triggers are internal; migrations may reshape them freely. There is no downgrade path. |
| **Configuration** | Documented `QueueConfig`/builder options, Python `start()` kwargs, and `AWA_*` environment variables in `configuration.md`. | Undocumented env vars; internal tuning defaults (may change in minors with a changelog note). |

## What "supported" means for binary/schema skew

Rolling deploys create windows where an older binary runs against a newer schema. The support
statement (maintained with [#367](https://github.com/hardbyte/awa/issues/367)):

- A binary one minor version behind the schema must either work correctly or fail loudly and
legibly — never silently misbehave.
- A newer binary against an older schema refuses to run and names the migration step.
- The 0.7 boundary additionally requires a finalized queue-storage transition (ADR-037).

## Relationship to release notes

Every stable release's changelog lists breaking changes against this document's surface list.
If a change breaks something *not* listed here, it is not a breaking change — but if that
surprises users repeatedly, the fix is to amend this document, not to argue.
58 changes: 58 additions & 0 deletions docs/test-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,64 @@ Concurrent lifecycle benchmark (1 queue × 128 workers, 20K jobs):

The formal suite includes passing configs and expected-counterexample configs. The expected-counterexample configs keep historical bugs executable: old dispatch claim, old view trigger, naive segment race, old storage-transition gate, shard-ignorant prune, and deliberate lock-order cycles. Trace configs use a `TraceIncomplete` invariant as a positive witness: a valid trace violates that invariant after TLC consumes every event.

## 0.7 Planned Validation

Planned test matrix for the 0.7 cycle, mapped to the roadmap ([`0.7-roadmap.md`](0.7-roadmap.md)) and the release gates on the [#383 tracker](https://github.com/hardbyte/awa/issues/383). Rows move into the matrix above as they are implemented.

### Harness & compatibility

| # | Test | Rust | Py | Ref |
| --- | --- | --- | --- | --- |
| V1 | Broad integration suite green under `AWA_TEST_ENGINE=queue_storage` | ✓ | ✓ | #360 |
| V2 | Engine guard rejects canonical-only raw-SQL helpers under queue_storage | ✓ | | #360 |
| V3 | Pinned 0.6.0 binary: enqueue→claim→complete→cancel against 0.7 schema | ✓ | ✓ | #367 |
| V4 | 0.7 binary against pre-migrate 0.6 schema fails loudly (message + exit code asserted) | ✓ | | #367 |
| V5 | `awa migrate` refuses non-`active` storage state, names finalize steps | ✓ | | #370 |

### Deployment & operations

| # | Test | Rust | Py | Ref |
| --- | --- | --- | --- | --- |
| V6 | `/readyz` flips 503 on DB-down / schema-mismatch / stalled claim loop | ✓ | | #368 |
| V7 | Maintenance-only role: promotes/rescues/rotates, never claims or dispatches | ✓ | ✓ | #282 |
| V8 | Chaos topology with zero general workers (maintenance-only + callback ingress + HttpWorker) | ✓ | | #282, #372 |
| V9 | Callback contract parity: embedded router vs `awa callbacks serve` (shared contract tests) | ✓ | ✓ | #372 |
| V10 | `tick()` bounded steps; scheduler-driven demo promotes/rescues with no resident worker | ✓ | ✓ | #118 |
| V11 | Unauthenticated non-loopback serve → read-only + banner; token auth constant-time; mutation audit line | ✓ | | #343 |
| V12 | `awa doctor` checks cover every troubleshooting.md scenario; `--json` schema asserted | ✓ | | #373 |
| V13 | Integration suite through pgbouncer session mode; transaction mode engages NOTIFY fallback + warning | ✓ | ✓ | #374 |
| V14 | Helm chart kind smoke: four-surface topology installs, probes pass, migration hook runs | ✓ | | #344 |

### Observability

| # | Test | Rust | Py | Ref |
| --- | --- | --- | --- | --- |
| V15 | Trace context: enqueue→claim→finalize one connected trace; retries/callbacks/cron linked | ✓ | | #110 |
| V16 | Trace propagation across the PyO3 boundary (Python handler is a child span) | | ✓ | #110 |
| V17 | Tracing overhead A/B within the E8 gate (<2% sampled enqueue cost) | ✓ | | #110 |
| V18 | Attempt-timeline API assembles ordered events across retries incl. callback park/resume | ✓ | | #375 |
| V19 | Alert pack rules lint/import clean | ✓ | | #376 |

### Flow & tenancy

| # | Test | Rust | Py | Ref |
| --- | --- | --- | --- | --- |
| V20 | Per-key Tier 1: worker-local cap holds exactly; fleet approximation matches documented formula | ✓ | ✓ | #340 |
| V21 | Per-key fairness under Zipf-skewed tenants (Jain index bound, no starvation) | ✓ | | #340 |
| V22 | A→B promotion is transactional with parent finalize; `on_parent_failure` policies (TLA+ witness + integration) | ✓ | ✓ | #14 |
| V23 | Backpressure: `Signal` surfaces pressure, `Reject` returns typed error, transactional enqueue unaffected by default | ✓ | ✓ | #341 |
| V24 | SQL contract conformance script green; BLAKE3 unique-key + shard-hash cross-language vectors | ✓ | ✓ | #342 |

### Storage & performance (gate evidence, benchmark harness)

| # | Test | Ref |
| --- | --- | --- |
| V25 | 0.6 pinned-MVCC long-horizon shape still passes on 0.7 main (798/s through 60-min pin, bounded depth, full reclaim) | #383 Gate 2 |
| V26 | #246 shape: ≤5% rescue-ON overhead at 1×256, or named mechanism + mitigation | #246 / E2 |
| V27 | Ring-state dead tuples reduced to noise on the long-horizon idle phase | #371 |
| V28 | Partitioned-queue preset ≥9k jobs/s e2e on the reference 24-CPU harness | #383 Gate 2 |
| V29 | Gate A evidence: allocator bake-off (E1) + WAL/job decomposition (E3) run ids recorded on #295 | #295 |

## Running Tests

```bash
Expand Down