#1943·astrid

Representation catalogue accepts only one prior format spec; PRE_FLEET_OWNER stores are refused

Author: jvsteinerCreated Sep 15, 2026Updated Sep 15, 2026

Summary

Opening a directory principal-store activates the direct representation catalogue with a compatibility list of exactly one prior format specification, while the format-amendment path beside it recognises thirteen. Any store whose active direct profile was frozen under a prior spec other than PRE_DENSE_RADIX is refused, and the daemon cannot boot:

Error: Failed to boot Kernel: Failed to open principal store: connection error: activate direct representation catalogue: invalid representation state: active direct profile names a different frozen specification

My store was frozen under PRE_FLEET_OWNER_FORMAT_SPEC_ID — a spec the same crate already knows about and explicitly special-cases elsewhere.

Mechanism

open_runtime_principal_store_with_options (crates/astrid-storage/src/principal_state.rs:745) passes a single-element slice:

rust
engine
    .ensure_direct_representation_catalogue_compatible_with(
        format_spec_id,
        &[PRE_DENSE_RADIX_FORMAT_SPEC_ID],
        &bootstrap_objects,
    )

repair_direct_coverage (crates/astrid-storage/src/engine/durable/representation_engine.rs:141) rejects anything not named there:

rust
if active_specification != frozen_specification
    && !compatible_frozen_specifications.contains(&active_specification)
{
    return Err(DurableError::InvalidRepresentationState(
        "active direct profile names a different frozen specification",
    ));
}

But crates/astrid-storage/src/principal_state/format_amendment.rs:80 enumerates thirteen prior specs, with PRE_FLEET_OWNER_FORMAT_SPEC_ID sitting immediately after PRE_DENSE_RADIX_FORMAT_SPEC_ID in the list:

rust
const PRIOR_V1_FORMAT_SPEC_IDS: [ObjectId; 13] = [
    ...
    PRE_DENSE_RADIX_FORMAT_SPEC_ID,     // line 91
    PRE_FLEET_OWNER_FORMAT_SPEC_ID,     // line 92
    PRE_WORKSPACE_BRANCH_FORMAT_SPEC_ID,
];

The same file already special-cases PRE_FLEET_OWNER_FORMAT_SPEC_ID at format_amendment.rs:324, so the store's format is understood — only the representation-catalogue call site was not updated when PRE_FLEET_OWNER and PRE_WORKSPACE_BRANCH were added. The compatibility list looks like it was written once for the dense-radix amendment and never revisited.

Identity confirmation

PRE_FLEET_OWNER_FORMAT_SPEC_ID (format_amendment.rs:64) is:

157, 112, 29, 200, 115, 96, 230, 52, 178, 91, 123, 127, 93, 94, 121, 49,
95, 159, 39, 188, 244, 213, 14, 9, 194, 24, 30, 67, 155, 12, 125, 117

which is hex 9d701dc87360e634b25b7b7f5d5e79315f9f27bcf4d50e09c2181e439b0c7d75, an exact match for format-spec-object in my var/principal-store/store.meta:

format=astrid-principal-store-v1
identity=blake3-object-identity-v1
identity-wire=tagged-identity-v1
format-spec-object=1:1:32:9d701dc87360e634b25b7b7f5d5e79315f9f27bcf4d50e09c2181e439b0c7d75
content-catalog-spec-object=1:1:32:8f3999b066b666396259c4a92f9de7c5b8e67df9d38a69fb4fb824968b56ecdb
representations=authoritative-direct-v1
principal-codec=principal-uid-v1
projection=kv-transition-bplus-v4

So the store is exactly one generation newer than the only value the call site accepts.

Reproduction Steps

  1. Create a ~/.astrid with a release whose store format spec is PRE_FLEET_OWNER (mine: store created 2026-08-27, store.meta format-spec-object 9d701dc8…).
  2. Upgrade to 2026.9.2 via astrid update.
  3. Run astrid start.
  4. Boot aborts in open_runtime_principal_store_with_options before any migration runs.

Workaround that confirms the diagnosis: move var/principal-store/representations/ out of the store. ensure_direct_representation_catalogue_compatible_with takes the inner.representations.is_none() branch (representation_engine.rs:137) and rebuilds the catalogue from objects.arena + objects.index under the current spec. Boot then proceeds past this point. That the catalogue is cheaply rebuildable derived data is a good argument for not hard-failing here at all.

Expected Behavior

  • Pass the full set of prior specifications whose direct-canonical recipe is still valid — PRIOR_V1_FORMAT_SPEC_IDS, or an explicit subset from PRE_PHYSICAL_CATALOGUE onward — rather than a hardcoded single element.
  • Add a test that fails when a new PRE_* spec is added to PRIOR_V1_FORMAT_SPEC_IDS without being reflected at this call site, so the two lists cannot drift again.
  • Consider rebuilding the derived catalogue when the active profile is a recognised prior spec, since the no-catalogue path already does exactly that.

Environment

  • OS: macOS 15.6 (Darwin 24.6.0), arm64
  • Astrid: 2026.9.2, installed via astrid update
  • Source: astrid-runtime/astrid @ 73661c9b (Cargo version 0.10.4)
  • Principal store created 2026-08-27; migration.complete records surrealkv-to-principal-store, flat-content-catalog-to-radix-tree, principal-kv-avl-to-transition-checkpoints
  • Store format spec on disk: PRE_FLEET_OWNER (9d701dc8…)

Logs / Backtrace

i Starting Astrid daemon (persistent mode)...
2026-09-15T06:27:55.164699Z  INFO astrid_config::loader: loaded user config path=/Users/jamie/.astrid/config.toml
✗ error: Daemon exited prematurely (exit status: 1). Check logs: /Users/jamie/.astrid/log

# ~/.astrid/log/daemon-boot.log
Error: Failed to boot Kernel: Failed to open principal store: connection error: activate direct representation catalogue: invalid representation state: active direct profile names a different frozen specification