Skip to content
Merged
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
4 changes: 3 additions & 1 deletion src/api/router/snapshot_request_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ impl Fixture {
};
let view = SnapshotView::from_commit(&"1".repeat(40), &"2".repeat(40));
let built = build(&state.storage.config().mst2, &view, "/", [3; 32]).unwrap();
let ctx = runtime().insert_context(built, &view.commit_oid, &view.root_tree_oid, 60);
let ctx = runtime()
.insert_context(built, &view.commit_oid, &view.root_tree_oid, 60)
.unwrap();
// Reproduce the server's nest-after-layer order: MST must establish
// its own request context even when the earlier layer does not run.
let app = Router::new()
Expand Down
1 change: 1 addition & 0 deletions src/callisto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub mod mega_webhook_delivery;
pub mod mega_webhook_event_type;
pub mod mst2_publication;
pub mod mst2_publication_outbox;
pub mod mst2_queue_noop_receipt;
pub mod mst2_retention_edge;
pub mod mst2_retention_gc_op;
pub mod mst2_retention_node;
Expand Down
6 changes: 5 additions & 1 deletion src/callisto/mst2_publication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
pub struct Model {
#[sea_orm(primary_key, auto_increment = true)]
pub id: i64,
/// Deterministic writer-side operation id (e.g. push old→new).
/// Server-assigned writer identity (e.g. `mst2:trunk-queue:<row id>`).
pub operation_id: String,
/// Namespace path this publication advances (e.g. "/").
pub namespace: String,
Expand All @@ -29,6 +29,10 @@ pub struct Model {
pub writer_epoch: i64,
/// `trunk_push` | `web_edit` | `import` | … (spec 09 §5 writer matrix).
pub writer_kind: String,
/// Missing on legacy receipts; never reconstructed from current refs.
#[sea_orm(column_type = "Text", nullable)]
pub request_digest: Option<String>,
pub request_digest_version: Option<i32>,
pub created_at: DateTimeWithTimeZone,
}

Expand Down
34 changes: 34 additions & 0 deletions src/callisto/mst2_queue_noop_receipt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Committed trunk-queue no-op results, separate from visible publications.

use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "mst2_queue_noop_receipt")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = true)]
pub id: i64,
#[sea_orm(column_type = "Text")]
pub operation_id: String,
#[sea_orm(column_type = "Text")]
pub namespace: String,
#[sea_orm(column_type = "Text")]
pub request_digest: String,
pub request_digest_version: i32,
pub writer_epoch: i64,
#[sea_orm(column_type = "Text")]
pub writer_kind: String,
pub observed_sequence: i64,
#[sea_orm(column_type = "Text")]
pub observed_root_commit: String,
#[sea_orm(column_type = "Text")]
pub observed_root_tree: String,
#[sea_orm(column_type = "Text")]
pub landed_commit_id: String,
pub created_at: DateTimeWithTimeZone,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use sea_orm_migration::prelude::*;

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.get_connection()
.execute_unprepared(
r#"ALTER TABLE mst2_publication
ADD COLUMN IF NOT EXISTS request_digest text,
ADD COLUMN IF NOT EXISTS request_digest_version integer;
DO $$ BEGIN
ALTER TABLE mst2_publication
ADD CONSTRAINT mst2_publication_request_digest_valid CHECK (
(request_digest IS NULL AND request_digest_version IS NULL) OR
(request_digest IS NOT NULL AND request_digest_version IS NOT NULL
AND request_digest_version > 0
AND request_digest ~ '^sha256:[0-9a-f]{64}$')
);
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
CREATE TABLE IF NOT EXISTS mst2_queue_noop_receipt (
id bigserial PRIMARY KEY,
operation_id text NOT NULL UNIQUE,
namespace text NOT NULL,
request_digest text NOT NULL CHECK (request_digest ~ '^sha256:[0-9a-f]{64}$'),
request_digest_version integer NOT NULL CHECK (request_digest_version > 0),
writer_epoch bigint NOT NULL,
writer_kind text NOT NULL,
observed_sequence bigint NOT NULL CHECK (observed_sequence >= 0),
observed_root_commit text NOT NULL,
observed_root_tree text NOT NULL,
landed_commit_id text NOT NULL,
created_at timestamptz NOT NULL
);"#,
)
.await?;
Ok(())
}

async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
// Receipts remain immutable, including the absence of legacy digests.
Ok(())
}
}
7 changes: 5 additions & 2 deletions src/jupiter/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ mod m20260921_000100_fix_git_tag_unique;
mod m20260923_000100_import_repo_cleanups;
mod m20260923_000200_canonicalize_import_repo_paths;
mod m20260925_000100_media_paging;
mod m20261005_000100_add_mst2_publication_request_digest;
mod m20261005_000100_add_mst2_retention_durability;
mod m20261005_000200_harden_mst2_retention_graph;
mod runner;
Expand Down Expand Up @@ -268,6 +269,7 @@ impl MigratorTrait for Migrator {
Box::new(m20260923_000100_import_repo_cleanups::Migration),
Box::new(m20260923_000200_canonicalize_import_repo_paths::Migration),
Box::new(m20260925_000100_media_paging::Migration),
Box::new(m20261005_000100_add_mst2_publication_request_digest::Migration),
Box::new(m20261005_000100_add_mst2_retention_durability::Migration),
Box::new(m20261005_000200_harden_mst2_retention_graph::Migration),
]
Expand Down Expand Up @@ -479,15 +481,16 @@ mod tests {
async fn import_repo_alias_rows_canonicalized() {
let names = migration_names();
assert_eq!(
&names[names.len() - 5..],
&names[names.len() - 6..],
&[
"m20260923_000100_import_repo_cleanups".to_string(),
"m20260923_000200_canonicalize_import_repo_paths".to_string(),
"m20260925_000100_media_paging".to_string(),
"m20261005_000100_add_mst2_publication_request_digest".to_string(),
"m20261005_000100_add_mst2_retention_durability".to_string(),
"m20261005_000200_harden_mst2_retention_graph".to_string(),
],
"retention durability registered last, after media paging"
"publication digest and retention durability follow the FU-14/16 migrations"
);

let db = alias_db().await;
Expand Down
Loading
Loading