hive-sh4re: split inbox, container, journal, and schedule wire shapes into their own modules
Closes the #3110 split — lib.rs is now just the crate doc comment and the pub mod list. journal.rs's new doc comment fixes a pre-existing bug: the old JournalPriority doc text in lib.rs was actually half Capability's doc (a leftover from an earlier reorder that moved the code but not the comment above it).
This commit is contained in:
parent
b785f96d30
commit
80f16094f1
30 changed files with 513 additions and 486 deletions
|
|
@ -222,7 +222,7 @@ struct TurnControl {
|
|||
/// set when this is the last todo wake before the miss-streak would hit
|
||||
/// `TODO_MISS_PAUSE_THRESHOLD`, so the agent gets one unambiguous chance to
|
||||
/// avoid being auto-paused.
|
||||
fn synthetic_todo_message(stern: bool) -> hive_sh4re::DeliveredMessage {
|
||||
fn synthetic_todo_message(stern: bool) -> hive_sh4re::inbox::DeliveredMessage {
|
||||
let body = if stern {
|
||||
"you have todos — call get_loose_ends NOW. you've skipped it on recent todo \
|
||||
wakes in a row; if this turn doesn't call it, the harness will pause your \
|
||||
|
|
@ -231,7 +231,7 @@ fn synthetic_todo_message(stern: bool) -> hive_sh4re::DeliveredMessage {
|
|||
} else {
|
||||
"you have todos — call get_loose_ends to see them".to_owned()
|
||||
};
|
||||
hive_sh4re::DeliveredMessage {
|
||||
hive_sh4re::inbox::DeliveredMessage {
|
||||
from: "todo".into(),
|
||||
body,
|
||||
id: 0,
|
||||
|
|
@ -243,8 +243,8 @@ fn synthetic_todo_message(stern: bool) -> hive_sh4re::DeliveredMessage {
|
|||
/// Synthetic message that drives the single stop-checkpoint turn when c0re
|
||||
/// signals a graceful stop. The agent gets one final turn to flush durable
|
||||
/// `/state` before the container is stopped; new inbound is already fenced.
|
||||
fn graceful_stop_message() -> hive_sh4re::DeliveredMessage {
|
||||
hive_sh4re::DeliveredMessage {
|
||||
fn graceful_stop_message() -> hive_sh4re::inbox::DeliveredMessage {
|
||||
hive_sh4re::inbox::DeliveredMessage {
|
||||
from: "graceful-stop".into(),
|
||||
body: "You are being gracefully stopped — the container will shut down after this turn, \
|
||||
and new inbound messages are already fenced. This is your one checkpoint turn: \
|
||||
|
|
@ -272,7 +272,7 @@ enum RecvOutcome {
|
|||
/// body/id is per-row data the producer already resolved, so the
|
||||
/// select arm wraps it straight into this variant — no dedicated
|
||||
/// `LocalReminder` variant needed.
|
||||
Message(hive_sh4re::DeliveredMessage),
|
||||
Message(hive_sh4re::inbox::DeliveredMessage),
|
||||
/// Long-poll timed out cleanly (empty `Messages` response). Caller
|
||||
/// sleeps then retries.
|
||||
Empty,
|
||||
|
|
@ -529,7 +529,7 @@ async fn serve_main<S: Surface>(socket: &Path, poll_ms: u64) -> Result<()> {
|
|||
let bus = Bus::new();
|
||||
// Set by the web UI's `/api/cancel` on a successful SIGINT, read-and-
|
||||
// cleared by `handle_turn` before building the next wake prompt — see
|
||||
// `hive_sh4re::INTERRUPTED_HINT`. Shared between the web server task and
|
||||
// `hive_sh4re::inbox::INTERRUPTED_HINT`. Shared between the web server task and
|
||||
// the serve loop the same way `bus`/`todo_wake` are.
|
||||
let interrupted = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
let stats = TurnStats::open_default();
|
||||
|
|
@ -654,7 +654,7 @@ async fn serve_loop<S: Surface>(
|
|||
files: &turn::TurnFiles,
|
||||
todo_wake: Arc<tokio::sync::Notify>,
|
||||
todos_store: Option<Arc<todos::Todos>>,
|
||||
mut reminder_rx: tokio::sync::mpsc::UnboundedReceiver<hive_sh4re::DeliveredMessage>,
|
||||
mut reminder_rx: tokio::sync::mpsc::UnboundedReceiver<hive_sh4re::inbox::DeliveredMessage>,
|
||||
interrupted: Arc<std::sync::atomic::AtomicBool>,
|
||||
) -> Result<()> {
|
||||
tracing::info!(socket = %socket.display(), "harness serve");
|
||||
|
|
@ -849,7 +849,7 @@ async fn handle_turn<S: Surface>(
|
|||
stats: Option<&TurnStats>,
|
||||
files: &turn::TurnFiles,
|
||||
session: &turn::AgentSession,
|
||||
first: hive_sh4re::DeliveredMessage,
|
||||
first: hive_sh4re::inbox::DeliveredMessage,
|
||||
interrupted: &std::sync::atomic::AtomicBool,
|
||||
) -> TurnControl {
|
||||
let from = first.from;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Delivery half of the harness-local reminders store. Polls [`Reminders`]
|
||||
//! for due rows and pushes each as a
|
||||
//! [`hive_sh4re::DeliveredMessage`] down an mpsc channel the serve loop
|
||||
//! [`hive_sh4re::inbox::DeliveredMessage`] down an mpsc channel the serve loop
|
||||
//! races against the broker long-poll — mirrors `todo_server`'s `Notify`
|
||||
//! wake, but a reminder fire carries real per-row data (message/id), so a
|
||||
//! bare `Notify` doesn't fit; the channel carries the finished message
|
||||
|
|
@ -60,7 +60,7 @@ fn remind_max_pending() -> u64 {
|
|||
/// select), while cleanly disabling delivery.
|
||||
pub async fn run(
|
||||
store: Option<Arc<Reminders>>,
|
||||
tx: mpsc::UnboundedSender<hive_sh4re::DeliveredMessage>,
|
||||
tx: mpsc::UnboundedSender<hive_sh4re::inbox::DeliveredMessage>,
|
||||
) {
|
||||
let Some(store) = store else {
|
||||
tracing::error!("reminders db unavailable — reminder delivery disabled");
|
||||
|
|
@ -73,7 +73,7 @@ pub async fn run(
|
|||
}
|
||||
}
|
||||
|
||||
fn tick(store: &Reminders, tx: &mpsc::UnboundedSender<hive_sh4re::DeliveredMessage>) {
|
||||
fn tick(store: &Reminders, tx: &mpsc::UnboundedSender<hive_sh4re::inbox::DeliveredMessage>) {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
let due = match store.due(now, REMINDER_BATCH_LIMIT) {
|
||||
Ok(rows) => rows,
|
||||
|
|
@ -84,7 +84,7 @@ fn tick(store: &Reminders, tx: &mpsc::UnboundedSender<hive_sh4re::DeliveredMessa
|
|||
};
|
||||
for r in due {
|
||||
let body = prepare_body(&r.message, r.file_path.as_deref());
|
||||
let dm = hive_sh4re::DeliveredMessage {
|
||||
let dm = hive_sh4re::inbox::DeliveredMessage {
|
||||
from: "reminder".into(),
|
||||
body,
|
||||
id: 0,
|
||||
|
|
@ -109,7 +109,7 @@ fn tick(store: &Reminders, tx: &mpsc::UnboundedSender<hive_sh4re::DeliveredMessa
|
|||
pub fn store(
|
||||
store: &Reminders,
|
||||
message: &str,
|
||||
timing: &hive_sh4re::ReminderTiming,
|
||||
timing: &hive_sh4re::inbox::ReminderTiming,
|
||||
file_path: Option<&str>,
|
||||
) -> Result<i64, String> {
|
||||
let max = remind_max_pending();
|
||||
|
|
@ -237,8 +237,8 @@ fn write_payload(path: &Path, message: &str) -> Result<(), String> {
|
|||
}
|
||||
|
||||
/// Resolve the `due_at` unix timestamp for a `StoreReminder` request.
|
||||
fn resolve_due_at(timing: &hive_sh4re::ReminderTiming) -> anyhow::Result<i64> {
|
||||
use hive_sh4re::ReminderTiming;
|
||||
fn resolve_due_at(timing: &hive_sh4re::inbox::ReminderTiming) -> anyhow::Result<i64> {
|
||||
use hive_sh4re::inbox::ReminderTiming;
|
||||
match timing {
|
||||
ReminderTiming::InSeconds { seconds } => {
|
||||
let now = std::time::SystemTime::now();
|
||||
|
|
@ -268,14 +268,15 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn resolve_due_at_in_seconds_is_close_to_now_plus_n() {
|
||||
let due = resolve_due_at(&hive_sh4re::ReminderTiming::InSeconds { seconds: 60 }).unwrap();
|
||||
let due =
|
||||
resolve_due_at(&hive_sh4re::inbox::ReminderTiming::InSeconds { seconds: 60 }).unwrap();
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
assert!((due - now - 60).abs() <= 2, "due={due} now={now}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_due_at_at_passes_through() {
|
||||
let due = resolve_due_at(&hive_sh4re::ReminderTiming::At {
|
||||
let due = resolve_due_at(&hive_sh4re::inbox::ReminderTiming::At {
|
||||
unix_timestamp: 123_456,
|
||||
})
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ pub fn format_wake_prompt(
|
|||
interrupted: bool,
|
||||
) -> String {
|
||||
let banner = if redelivered {
|
||||
hive_sh4re::REDELIVERY_HINT
|
||||
hive_sh4re::inbox::REDELIVERY_HINT
|
||||
} else if interrupted {
|
||||
hive_sh4re::INTERRUPTED_HINT
|
||||
hive_sh4re::inbox::INTERRUPTED_HINT
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
|
@ -38,7 +38,7 @@ pub fn format_wake_prompt(
|
|||
} else {
|
||||
String::new()
|
||||
};
|
||||
let pending = hive_sh4re::pending_hint(unread);
|
||||
let pending = hive_sh4re::inbox::pending_hint(unread);
|
||||
format!("{banner}{tag}Incoming message from `{from}`:\n---\n{body}\n---{pending}")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use std::sync::Arc;
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use hive_agent_sock::{Request, Response};
|
||||
use hive_sh4re::LooseEnd;
|
||||
use hive_sh4re::inbox::LooseEnd;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::net::{UnixListener, UnixStream};
|
||||
use tokio::sync::Notify;
|
||||
|
|
@ -248,7 +248,7 @@ fn dispatch(
|
|||
fn store_reminder(
|
||||
reminders: Option<&Reminders>,
|
||||
message: &str,
|
||||
timing: &hive_sh4re::ReminderTiming,
|
||||
timing: &hive_sh4re::inbox::ReminderTiming,
|
||||
file_path: Option<&str>,
|
||||
) -> Response {
|
||||
let Some(r) = reminders else {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ struct AppState {
|
|||
gui_vnc_port: Option<u16>,
|
||||
/// Set by `post_cancel_turn` on a successful SIGINT; read-and-cleared
|
||||
/// by the serve loop's next `handle_turn` to prepend
|
||||
/// `hive_sh4re::INTERRUPTED_HINT` to that turn's wake prompt. Shared
|
||||
/// `hive_sh4re::inbox::INTERRUPTED_HINT` to that turn's wake prompt. Shared
|
||||
/// with the serve loop via the same `Arc` (see `serve_main`) — an
|
||||
/// in-memory flag, not a marker file, since a `/cancel` from a prior
|
||||
/// process lifetime isn't meaningful once the harness restarts.
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ pub(super) struct StateSnapshot {
|
|||
/// Last N messages addressed to this agent, newest-first. Pulled
|
||||
/// from the broker via the per-agent socket on each render.
|
||||
/// Empty on transport failure.
|
||||
inbox: Vec<hive_sh4re::InboxRow>,
|
||||
inbox: Vec<hive_sh4re::inbox::InboxRow>,
|
||||
/// Authoritative turn-loop state from the harness and the unix
|
||||
/// timestamp the state was entered. The JS computes the age
|
||||
/// client-side off this rather than tracking it from SSE events.
|
||||
|
|
@ -363,7 +363,7 @@ struct ExtraLink {
|
|||
/// Best-effort: pull the last 30 messages addressed to us via the
|
||||
/// per-agent / manager socket. Empty list on any transport / decode
|
||||
/// failure — the inbox section is decorative, not authoritative.
|
||||
async fn recent_inbox(socket: &std::path::Path) -> Vec<hive_sh4re::InboxRow> {
|
||||
async fn recent_inbox(socket: &std::path::Path) -> Vec<hive_sh4re::inbox::InboxRow> {
|
||||
const LIMIT: u64 = 30;
|
||||
// Deadline-bounded (via `broker_request`): `/api/state` must render even
|
||||
// when hive-c0re is busy — an empty inbox section beats a hung snapshot.
|
||||
|
|
|
|||
Loading…
Reference in a new issue