Skip to content

Commit 7f3e8e4

Browse files
authored
Merge pull request #92 from MB3R-Lab/fixed-k-replica-slots
Add fixed replica slot sampling
2 parents b1f0545 + 25af882 commit 7f3e8e4

16 files changed

Lines changed: 301 additions & 14 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## Unreleased
44

5+
## v1.1.0 - 2026-07-02
6+
7+
- added `fixed_k_replica_slots` sampling for fixed-fraction experiment reproduction; when `fixed_k_failures` is omitted, Sheaft derives `k = ceil(failure_probability * total_replica_slots)`
8+
- added schema, methodology, configuration example, and simulation coverage for fixed replica-slot sampling
9+
- kept Bering contract compatibility unchanged on the strict `io.mb3r.bering.model@1.3.0` and `io.mb3r.bering.snapshot@1.3.0` line
10+
11+
## v1.0.0 - 2026-07-02
12+
513
- added v1 major semantics documentation for the stochastic connectivity baseline, migration notes, and explicit out-of-scope release boundaries
614
- added release dry-run validation for v1 docs/schema/example consistency
715
- recorded app-level sync with Bering `v1.0.0` in `compatibility-manifest.json`

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Sheaft
22

3-
[![release](https://img.shields.io/badge/release-v1.0.0-blue)](https://github.com/MB3R-Lab/Sheaft/releases/tag/v1.0.0)
3+
[![release](https://img.shields.io/badge/release-v1.1.0-blue)](https://github.com/MB3R-Lab/Sheaft/releases/tag/v1.1.0)
44
[![checks](https://img.shields.io/github/actions/workflow/status/MB3R-Lab/Sheaft/release-dry-run.yml?branch=main&label=checks)](https://github.com/MB3R-Lab/Sheaft/actions/workflows/release-dry-run.yml)
55
[![bering schema](https://img.shields.io/badge/bering%20schema-1.3.0-blue)](https://github.com/MB3R-Lab/Sheaft/blob/main/docs/compatibility-matrix.md)
66

@@ -21,20 +21,21 @@ It stays downstream of topology discovery. The public surface in this repository
2121

2222
## Stability / Release Status
2323

24-
The current public release line is `v1.0.0`. It is the first major Sheaft line for the stochastic-connectivity baseline over Bering `1.3.0` model and snapshot contracts.
24+
The current public release line is `v1.1.0`. It is the current stable Sheaft line for the stochastic-connectivity baseline over Bering `1.3.0` model and snapshot contracts.
2525

26-
Stable in `v1.0.0`:
26+
Stable in `v1.1.0`:
2727

2828
- strict acceptance of the Bering v1 contract line: `io.mb3r.bering.model@1.3.0` and `io.mb3r.bering.snapshot@1.3.0`
2929
- batch CLI command names and core flow: `simulate`, `gate`, `run`
3030
- deterministic batch execution for a fixed seed and config
31+
- fixed replica-slot sampling through `sampling_mode: fixed_k_replica_slots` for reproducing fixed-fraction experiment protocols
3132
- baseline comparison through `analysis.baselines` for supported `1.3.0` artifacts
3233
- additive advanced analysis when `1.3.0` metadata exists
3334
- gate decision reasons in `report.json`, `summary.md`, and `sheaft gate/run --why`
3435
- fixed benchmark slice and release-quality `quality-report.json` generation
3536
- release archives for Linux and macOS on `amd64` and `arm64`
3637

37-
Outside the stable `v1.0.0` release claim:
38+
Outside the stable `v1.1.0` release claim:
3839

3940
- long-running `serve` posture service as a long-term operations contract
4041
- richer analysis configuration ergonomics beyond the shipped examples

api/schema/analysis.schema.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"enum": [
2626
"independent_replica",
2727
"independent_service",
28-
"fixed_k_service_set"
28+
"fixed_k_service_set",
29+
"fixed_k_replica_slots"
2930
]
3031
},
3132
"failure_probability": {
@@ -91,7 +92,8 @@
9192
"enum": [
9293
"independent_replica",
9394
"independent_service",
94-
"fixed_k_service_set"
95+
"fixed_k_service_set",
96+
"fixed_k_replica_slots"
9597
]
9698
},
9799
"failure_probability": {

configs/analysis.example.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ profiles:
2424
- name: fixed-blast-radius
2525
sampling_mode: fixed_k_service_set
2626
fixed_k_failures: 1
27+
- name: experiment-fixed-fraction
28+
sampling_mode: fixed_k_replica_slots
29+
failure_probability: 0.30
2730

2831
gate:
2932
mode: warn

docs/configuration.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ Profile-level `reliability` values inherit the top-level block and can override
4141

4242
For artifact baseline comparisons, prefer homogeneous `reliability.edge_live_probability` unless every compared artifact exposes the same edge IDs. Per-edge `reliability.edges` entries are validated against each artifact under analysis.
4343

44+
Sampling modes:
45+
46+
- `independent_replica`: replicas fail independently; a service stays live while any replica survives
47+
- `independent_service`: each service is sampled once per trial regardless of replica count
48+
- `fixed_k_service_set`: exactly `fixed_k_failures` services fail per trial
49+
- `fixed_k_replica_slots`: exactly `k` replica slots fail per trial; when `fixed_k_failures` is omitted, `k = ceil(failure_probability * total_replica_slots)`
50+
4451
## Serve Config
4552

4653
Use the versioned serve config for long-running posture mode:

docs/consumer-semantics-v1.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,22 @@ Expected outcome:
332332
- exactly one service fails each trial;
333333
- a single-path endpoint that depends on all three services has availability `0`.
334334

335-
### 14. Gate threshold precedence is profile-specific first
335+
### 14. `fixed_k_replica_slots` fails a fixed number of replica slots
336+
337+
Input:
338+
339+
- one service with `replicas=2`;
340+
- `sampling_mode: fixed_k_replica_slots`;
341+
- `failure_probability: 0.5`;
342+
- `fixed_k_failures` omitted.
343+
344+
Expected outcome:
345+
346+
- Sheaft derives `fixed_k_failures = ceil(0.5 * 2) = 1`;
347+
- exactly one replica slot fails each trial;
348+
- the service remains available because one replica slot survives.
349+
350+
### 15. Gate threshold precedence is profile-specific first
336351

337352
Input:
338353

@@ -343,7 +358,7 @@ Expected outcome:
343358
- the profile-specific endpoint threshold is applied for that profile;
344359
- otherwise endpoint-specific threshold wins over global threshold.
345360

346-
### 15. `evaluation_rule=all_profiles` differs from `evaluation_rule=any_profile`
361+
### 16. `evaluation_rule=all_profiles` differs from `evaluation_rule=any_profile`
347362

348363
Input:
349364

docs/methodology.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ For each configured profile Sheaft:
2727
- `independent_replica`: replicas fail independently and a service stays available while any replica survives
2828
- `independent_service`: each service is sampled once per trial regardless of replica count
2929
- `fixed_k_service_set`: exactly `k` services fail per trial
30+
- `fixed_k_replica_slots`: exactly `k` replica slots fail per trial; when `fixed_k_failures` is omitted, `k = ceil(failure_probability * total_replica_slots)`
3031

31-
When `1.3.0` placement buckets exist, `independent_replica` samples those buckets explicitly. A service remains effectively alive while at least one bucket still has a live replica.
32+
When `1.3.0` placement buckets exist, replica-based modes sample those buckets explicitly. A service remains effectively alive while at least one bucket still has a live replica.
3233

3334
## Stochastic Connectivity Parameters
3435

docs/roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ The published `v0.2.4` release payload is the previous preview baseline:
7272
| Issue | GitHub state | Repo reality | Notes |
7373
| --- | --- | --- | --- |
7474
| R1.1 | closed | done | "Consumer Semantics v1" is documented in-repo with version scope, precedence rules, and 15 expected behavior examples. |
75-
| R1.2 | closed | done | Fail-stop baseline semantics, three sampling modes, timeout/partial degradation handling, and the external Sheaft fault contract are implemented and tested. |
75+
| R1.2 | closed | done | Fail-stop baseline semantics, four sampling modes, timeout/partial degradation handling, and the external Sheaft fault contract are implemented and tested. |
7676
| R1.3 | open | partial | Retry/timeout/circuit-breaker inputs from Bering `1.3.0` and the Sheaft fault contract are now handled; fallback/rate-limit annotations still remain outside the implemented surface. |
7777

7878
### R2. Model discovery from artifacts

docs/v1-major-semantics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The implementation is deterministic for a fixed artifact, analysis config, and s
2525
| Formal element | Sheaft v1 implementation | Evidence | Boundary |
2626
| --- | --- | --- | --- |
2727
| `G=(V,E,tau)` | Bering services become `V`; Bering dependencies become `E`; edge type `tau` is represented by `kind`, `blocking`, and optional operation-aware `identity`. | `io.mb3r.bering.model@1.3.0`, `io.mb3r.bering.snapshot@1.3.0`, [examples/outputs/model-v1.3.0.sample.json](../examples/outputs/model-v1.3.0.sample.json), [examples/outputs/snapshot-v1.3.0.sample.json](../examples/outputs/snapshot-v1.3.0.sample.json) | Sheaft consumes topology; discovery ownership remains upstream in Bering. |
28-
| `R` | Service `replicas` and `metadata.placements[].replicas` define the replication map. `independent_replica` samples replicas or placement buckets; a service is live while at least one sampled replica bucket survives. | [docs/methodology.md](methodology.md), [configs/analysis.v1.1.example.yaml](../configs/analysis.v1.1.example.yaml) | Placement metadata is used when present; otherwise Sheaft falls back to coarse service replicas. |
28+
| `R` | Service `replicas` and `metadata.placements[].replicas` define the replication map. `independent_replica` samples replicas or placement buckets independently. `fixed_k_replica_slots` samples a fixed number of replica slots for experiment reproduction. A service is live while at least one sampled replica bucket survives. | [docs/methodology.md](methodology.md), [configs/analysis.example.yaml](../configs/analysis.example.yaml) | Placement metadata is used when present; otherwise Sheaft falls back to coarse service replicas. |
2929
| `P` | The v1 baseline is `P_Node * P_Edge`: node/service live events and edge live events are sampled independently before optional reviewed fault overlays. | [docs/oracle-suite.md](oracle-suite.md), `make oracle-suite` | Arbitrary non-product `P` is out of scope. Correlated failures are explicit fault overlays, not inferred probability distributions. |
3030
| `theta` | `analysis.reliability.node_live_probability`, `profiles[].reliability.node_live_probability`, per-service overrides, and Bering reliability evidence resolve node live probabilities. Legacy `failure_probability` maps to `1 - theta` only when explicit node reliability is absent. | [docs/configuration.md](configuration.md), [api/schema/analysis.schema.json](../api/schema/analysis.schema.json) | Sheaft does not do automatic probability calibration from telemetry. Inputs must be configured or provided as upstream evidence. |
3131
| `rho` | `analysis.reliability.edge_live_probability`, `profiles[].reliability.edge_live_probability`, per-edge overrides, and Bering edge reliability evidence resolve edge live probabilities. | [docs/configuration.md](configuration.md), [configs/analysis.v1.1.example.yaml](../configs/analysis.v1.1.example.yaml) | Per-edge overrides must use edge IDs present in the artifact being analyzed. |

internal/config/analysis.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const (
1919
SamplingModeIndependentReplica = "independent_replica"
2020
SamplingModeIndependentService = "independent_service"
2121
SamplingModeFixedKServiceSet = "fixed_k_service_set"
22+
SamplingModeFixedKReplicaSlots = "fixed_k_replica_slots"
2223
)
2324

2425
type GateEvaluationRule string
@@ -273,10 +274,13 @@ func (c AnalysisConfig) Validate() error {
273274
return fmt.Errorf("profile %q has unsupported sampling_mode %q", profile.Name, profile.SamplingMode)
274275
}
275276
switch profile.SamplingMode {
276-
case SamplingModeIndependentReplica, SamplingModeIndependentService:
277+
case SamplingModeIndependentReplica, SamplingModeIndependentService, SamplingModeFixedKReplicaSlots:
277278
if profile.FailureProbability < 0 || profile.FailureProbability > 1 {
278279
return fmt.Errorf("profile %q failure_probability must be in range [0,1]", profile.Name)
279280
}
281+
if profile.SamplingMode == SamplingModeFixedKReplicaSlots && profile.FixedKFailures < 0 {
282+
return fmt.Errorf("profile %q fixed_k_failures must be >= 0", profile.Name)
283+
}
280284
case SamplingModeFixedKServiceSet:
281285
if profile.FixedKFailures < 0 {
282286
return fmt.Errorf("profile %q fixed_k_failures must be >= 0", profile.Name)
@@ -479,7 +483,7 @@ func resolveRelative(baseDir, target string) string {
479483

480484
func isValidSamplingMode(mode string) bool {
481485
switch mode {
482-
case SamplingModeIndependentReplica, SamplingModeIndependentService, SamplingModeFixedKServiceSet:
486+
case SamplingModeIndependentReplica, SamplingModeIndependentService, SamplingModeFixedKServiceSet, SamplingModeFixedKReplicaSlots:
483487
return true
484488
default:
485489
return false

0 commit comments

Comments
 (0)