• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bedrock-kv / bedrock / ced5317a4db676fa43ff0e5b811ac8332aaec7c0
82%

Build:
DEFAULT BRANCH: develop
Ran 14 Sep 2026 05:56PM UTC
Jobs 1
Files 215
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

14 Sep 2026 05:55PM UTC coverage: 81.425% (+0.2%) from 81.248%
ced5317a4db676fa43ff0e5b811ac8332aaec7c0

push

github

web-flow
Route fresh prior core states to InitializationPhase, not LockingPhase (#321)

## Why

Recovery keeps two different views of "the previous transaction system":
a `CoreState` (durable — just `logs` and `system_materializers`, the
minimum needed to recover from) and a `TransactionSystemLayout`
(transient — pids, wiped every epoch). `TSLValidationPhase` runs first
and type-checks whichever `CoreState` was loaded from the durable
bootstrap before anything downstream trusts it. On success it decided
where to go next with:

```elixir
def execute(%RecoveryAttempt{} = recovery_attempt, %{prior_core_state: %{} = core_state}) do
  case TSLTypeValidator.validate_type_safety(core_state) do
    :ok ->
      {recovery_attempt, Bedrock.ControlPlane.Director.Recovery.LockingPhase}
```

`%{} = core_state` in a function head doesn't mean "an empty map" — in
Elixir it matches *any* map. So this clause fires whether `core_state`
is `%{logs: %{"log_1" => [0, 100]}}` (a real prior epoch) or `%{logs:
%{}}` (a cluster that has never recovered before, and has nothing to
recover from). Both went to `LockingPhase`.

That phase locks the logs named in `prior_core_state` and hands off to
`LogRecoveryPlanningPhase`, which computes a majority quorum over them:

```elixir
if locked_count > total_count / 2 do
  ...
else
  {recovery_attempt, {:stalled, :unable_to_meet_log_quorum}}
```

For a fresh cluster, `total_count` is 0. `0 > 0/2` is `false`. Recovery
stalls waiting for quorum on logs that were never there in the first
place — the bug in #319.

The fix already exists in the codebase and is just unused here:
`CoreState.fresh?/1` correctly treats an absent or empty-logs
`CoreState` as fresh, and `MaterializerBootstrapPhase` already asks it
this exact question for the system shard. `TSLValidationPhase` was the
one phase that skipped the check.

## What changed

`TSLValidationPhase` now asks `CoreState.fresh?/1` after validation
succeeds, and only locks the old system when there's an... (continued)

8 of 8 new or added lines in 2 files covered. (100.0%)

1 existing line in 1 file now uncovered.

7154 of 8786 relevant lines covered (81.42%)

1167.7 hits per line

Coverage Regressions

Lines Coverage ∆ File
1
86.49
-2.7% lib/bedrock/control_plane/director/recovery/locking_phase.ex
Jobs
ID Job ID Ran Files Coverage
1 ced5317a4db676fa43ff0e5b811ac8332aaec7c0.1 14 Sep 2026 05:56PM UTC 215
81.42
GitHub Action Run
Source Files on build ced5317a4db676fa43ff0e5b811ac8332aaec7c0
  • Tree
  • List 215
  • Changed 8
  • Source Changed 0
  • Coverage Changed 8
Coverage ∆ File Lines Relevant Covered Missed Hits/Line
  • Back to Repo
  • ced5317a on github
  • Prev Build on develop (#96683D05...)
  • Next Build on develop (#35AE854A...)
  • Delete
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc