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
1 change: 1 addition & 0 deletions .beads/issues.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,4 @@
{"id":"runledger-y1o","title":"Harden lifecycle timeout recovery after 0.11 review","description":"Resolve comprehensive-review findings structurally: centralize queue timeout policy, bound prestart release recovery, type PostgreSQL lock contention for runtime policy, retry transient heartbeat lock waits within one fixed lease-maintenance deadline, and close PostgreSQL 18 regression gaps. Commit each logical slice separately and finish with the full repository suite.","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-08-26T13:03:13.908525Z","created_by":"aa","updated_at":"2026-08-26T13:22:54.908241Z","closed_at":"2026-08-26T13:22:54.907662Z","close_reason":"Implemented and verified structural lifecycle timeout recovery across PostgreSQL and runtime; full workspace tests and Clippy pass on PostgreSQL 18.4.","source_repo":"runledger","source_repo_path":"/Users/aa/Documents/runledger","compaction_level":0,"original_size":0}
{"id":"runledger-ze4","title":"Specify durable capacity policy APIs and rollout compatibility","description":"Use docs/research/distributed-capacity-controls.md to freeze the capacity policy, requirement, and enqueue-options contracts. Specify explicit opt-in bindings versus mandatory bindings, missing/paused policy behavior, unit costs, live limit changes, rolling-window admission-time semantics, no refunds, and immutable windows. Trace direct enqueue, intents and promotion, workflow enqueue/append/release/continuation/recovery, direct replay, and schedule firing. Define old snapshot decoding, canonical idempotency comparison, admission UUIDs despite attempt-number reuse, public struct literal compatibility, old-worker lease guards, schema migration copies, and staged activation/rollback. Deliver a contract with representative old/new fixtures; no production implementation. Independent of the protocol prototype; both block the execution plan.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-09-06T14:11:24.100982Z","created_by":"aa","updated_at":"2026-09-06T15:11:59.909674Z","closed_at":"2026-09-06T15:11:59.909542Z","close_reason":"Specified additive options/token contracts, globally scoped unit policies, durable owner membership, all producer/recovery routes, canonical old/new fixtures, and staged activation/rollback in docs/distributed-capacity-plan.md and capacity-contract-fixtures.json. Full-plan refinement continues under runledger-bva; no feature implementation is claimed.","source_repo":"runledger","source_repo_path":"/Users/aa/Documents/runledger","compaction_level":0,"original_size":0}
{"id":"runledger-zr5","title":"Validate distributed capacity plan against local consumers","description":"Audit current Runledger consumers under ~/Documents, deduplicate checkouts, trace actual concurrency/rate controls and adoption paths, and update the capacity epic with source-backed consumer-fit findings. Source inspection only unless experiments are necessary; preserve consumer worktrees.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-09-06T18:23:32.746890Z","created_by":"aa","updated_at":"2026-09-06T18:41:00.615263Z","closed_at":"2026-09-06T18:41:00.615074Z","close_reason":"Completed source audit of 16 consumer checkouts deduplicated into six products. Recorded findings and exact local source references in docs/research/distributed-capacity-consumer-audit-2026-09-06.md; updated concurrency adoption criteria and ten epic task descriptions, deferred P17 pending a qualifying exact-admission consumer, and verified all dependency edges/readiness. Source inspection only; no downstream compilation, database run, deployment, or measured code deletion is claimed.","source_repo":"runledger","source_repo_path":"/Users/aa/Documents/runledger","compaction_level":0,"original_size":0}
{"id":"runledger-hcf","title":"Validate actual Cargo foundation without adapter-pin cycles","description":"Consume Cargo dependency source metadata; preserve ordinary-build source and migration checks, ignore unrelated adapter pins, test drift and clean Git consumers; retain session-profile release fixes from b83abe4.","status":"in_progress","priority":1,"issue_type":"task","created_at":"2026-09-21T14:37:20.493529Z","created_by":"aa","updated_at":"2026-09-21T14:42:23.522336Z","source_repo":"runledger","source_repo_path":"/Users/aa/Documents/runledger","compaction_level":0,"original_size":0}
58 changes: 57 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 26 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,25 @@ orchestration in `runtime`, and SQL/state-machine logic in `postgres`.
## Installation

This branch is **unpublished coordinated development**. Its Batter dependency
is not a registry release. A sibling checkout is mandatory; from a fresh clone
run `bash scripts/bootstrap-batter.sh`. The pinned revision lives in
`runledger-postgres/batter-revision`; ordinary Cargo builds check the foundation
sources against that pin locally as well as in CI. Do not use the old registry
installation instructions for this branch.
is not a registry release. For workspace development, from a fresh clone run
`bash scripts/bootstrap-batter.sh` to create the paired sibling. The reviewed
revision lives in `runledger-postgres/batter-revision`. Ordinary Cargo builds
verify the actual core and SQLx sources reported by Cargo dependency metadata,
including their inherited workspace manifest settings, against that revision.
Unrelated adapter pins and manifest formatting can change independently. The
bootstrap's `RUNLEDGER_BATTER_SOURCE` selects a clone/check target only; it cannot
override Cargo dependency selection or make a different compiled source pass.
Do not use the old registry installation instructions for this branch.

Git consumers need no sibling: select an immutable Runledger Git revision and
add the following **consumer workspace-root** patch. `BATTER_REV` must contain
the reviewed foundation (or a descendant with identical foundation inputs).
If the consumer also uses Batter directly, select that same Batter revision.
Cargo does not inherit patches from dependencies.

The check requires the reviewed ancestor in the actual source checkout's Git
history; shallow development clones must fetch it. It is a source-consistency
guard, not protection against a deliberately modified Cargo build/configuration.

For a service next to the paired `runledger` and `batter` checkouts:

Expand All @@ -114,6 +128,13 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }
runledger-test-support = { path = "../runledger/runledger-test-support" }
```

For Git consumption instead of the paired paths above, add this root patch:

```toml
[patch."https://github.com/bpcakes/runledger"]
batter-sqlx = { git = "https://github.com/bpcakes/batter", rev = "BATTER_REV" }
```

These sources require **Rust 1.94+** and **PostgreSQL 18+**. Older
PostgreSQL releases are not supported, even when an extension supplies an
equivalent `uuidv7()` function. See [PostgreSQL requirements](#postgresql-requirements).
Expand Down
41 changes: 41 additions & 0 deletions docs/evidence/foundation-integration-2026-09-21.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Foundation integration across parallel streams

Owning Bead: `runledger-hcf`. Review base: `b83abe4`.

Preserves the session-profile release restoration in `b83abe4`. The new paired
Batter foundation combines session profiles and operation-context atomic
completion. Native queue/profile behavior is unchanged by this integration.

`build.rs` now consumes Cargo dependency metadata from the actual SQLx package,
which forwards its actual core package directory. Both must belong to the same
reviewed source tree. Tracked and untracked foundation input drift is rejected.
Inherited workspace dependency requirements, package settings, lints and resolver
remain checked semantically. Adapter dependencies and comments are not foundation
inputs. The immutable pin and migration-copy check remain enforced on ordinary
Cargo builds; a separately selected clean sibling cannot bless patched code.

The check does not freeze the application's third-party lockfile, features or
Cargo configuration. As before, consumers own those inputs and must validate
their final graph. Cargo's foundation `links` identities reject duplicate core
or SQLx implementations. All packages remain unpublished.

Regression coverage includes clean sources, adapter pin changes, inherited
settings drift, tracked and ignored-untracked source drift, split core/SQLx roots,
and independent migration drift. Final executed validation is recorded below.

Executed locally on macOS, Rust 1.94.1, PostgreSQL 18.6 (`postgres:18`):

- Five foundation-pin tests; six live database-profile tests.
- All 374 PostgreSQL package tests/doctests.
- Workspace/all-target compilation and PostgreSQL/all-target Clippy.
- README contract and formatting checks.
- A fresh Git-only consumer compiled the actual dependency graph without a
sibling, with `RUNLEDGER_BATTER_SOURCE` deliberately nonexistent. This used
local Git transport and is distinct from hosted GitHub consumer validation.
- Locked standalone consumer compilation and all nine packaged archive smoke
tests. Native review identified its stale independent lockfile; Cargo
regenerated that lockfile and both locked checks then passed.

The linked-worktree tracker import reported a pre-existing normalization conflict
for `runledger-wtb`. This change preserves that record and includes only the new
owning task's tracker export; no unrelated tracker repair is claimed.
5 changes: 5 additions & 0 deletions runledger-postgres/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ tokio = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
toml = { version = "1.1.6", default-features = false, features = ["std", "parse", "serde"] }
tempfile = "3"
static_assertions = "1.1.0"
runledger-test-support = { workspace = true }
tokio = { workspace = true, features = ["io-util", "net"] }

[build-dependencies]
toml = { version = "1.1.6", default-features = false, features = ["std", "parse", "serde"] }
2 changes: 1 addition & 1 deletion runledger-postgres/batter-revision
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d7728e633b3b767edde8aea40daf358ad4917ea4
497e41e3241e7972d68a61dc2e19a5dd8694ea2e
52 changes: 7 additions & 45 deletions runledger-postgres/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ use std::{
error::Error,
fs,
path::{Path, PathBuf},
process::Command,
};

const PIN: &str = include_str!("batter-revision");
const INPUTS: &[&str] = &["Cargo.toml", "crates/batter-core", "crates/batter-sqlx"];
pub mod foundation_source;

fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed=batter-revision");
println!("cargo:rerun-if-env-changed=RUNLEDGER_BATTER_SOURCE");
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
let vendored_dir = manifest.join("migrations");
let canonical_dir = manifest.join("../migrations");
Expand All @@ -22,42 +19,15 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed={}", canonical_dir.display());
enforce_migration_sync(&canonical_dir, &vendored_dir);
}
let source = env::var_os("RUNLEDGER_BATTER_SOURCE")
.map_or_else(|| manifest.join("../../batter"), PathBuf::from);
let revision = PIN.trim();
if revision.len() != 40 || !revision.bytes().all(|c| c.is_ascii_hexdigit()) {
return Err("invalid immutable Batter source revision".into());
}
for input in INPUTS {
println!("cargo:rerun-if-changed={}", source.join(input).display());
}
// Accept companion-only descendants, but require identical foundation code,
// manifests and untracked-source state. This avoids circular whole-repo pins.
let mut args = vec!["diff", "--quiet", revision, "--"];
args.extend_from_slice(INPUTS);
if !git(&source, &args)?.status.success() {
return Err("Batter foundation differs from the coordinated pin; run scripts/bootstrap-batter.sh or deliberately update the reviewed pin".into());
}
let unknown = git(
&source,
&[
"ls-files",
"--others",
"--exclude-standard",
"--",
"crates/batter-core",
"crates/batter-sqlx",
],
)?;
if !unknown.status.success() || !unknown.stdout.is_empty() {
return Err(
"untracked Batter foundation inputs are not part of the pinned source graph".into(),
);
}
// Cargo's direct dependency metadata describes the code actually compiled.
// An unrelated clean sibling or RUNLEDGER_BATTER_SOURCE cannot bless it.
let sqlx = PathBuf::from(env::var("DEP_BATTER_SQLX_FOUNDATION_SOURCE")?);
let core = PathBuf::from(env::var("DEP_BATTER_SQLX_FOUNDATION_CORE_SOURCE")?);
foundation_source::verify(&sqlx, &core, include_str!("batter-revision").trim())?;
Ok(())
}

fn enforce_migration_sync(canonical_dir: &Path, vendored_dir: &Path) {
pub fn enforce_migration_sync(canonical_dir: &Path, vendored_dir: &Path) {
let canonical = load_sql_files(canonical_dir);
let vendored = load_sql_files(vendored_dir);

Expand Down Expand Up @@ -93,11 +63,3 @@ fn load_sql_files(dir: &Path) -> BTreeMap<String, String> {

files
}

fn git(source: &Path, args: &[&str]) -> Result<std::process::Output, std::io::Error> {
Command::new("git")
.arg("-C")
.arg(source)
.args(args)
.output()
}
104 changes: 104 additions & 0 deletions runledger-postgres/foundation_source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! Build-time checks for the actual unpublished Cargo foundation.
use std::{collections::BTreeSet, error::Error, fs, path::Path, process::Command};

const INPUTS: &[&str] = &["crates/batter-core", "crates/batter-sqlx"];

pub fn verify(sqlx: &Path, core: &Path, revision: &str) -> Result<(), Box<dyn Error>> {
if revision.len() != 40 || !revision.bytes().all(|c| c.is_ascii_hexdigit()) {
return Err("invalid immutable Batter source revision".into());
}
let sqlx = sqlx.canonicalize()?;
let core = core.canonicalize()?;
let root = sqlx
.parent()
.and_then(Path::parent)
.ok_or("missing Batter workspace")?;
if root.join(INPUTS[0]).canonicalize()? != core || root.join(INPUTS[1]).canonicalize()? != sqlx
{
return Err("Cargo selected different Batter foundation source roots".into());
}
for input in INPUTS.iter().copied().chain(["Cargo.toml"]) {
println!("cargo:rerun-if-changed={}", root.join(input).display());
}
let mut args = vec!["diff", "--quiet", revision, "--"];
args.extend_from_slice(INPUTS);
if !git(root, &args)?.status.success() {
return Err("actual Batter foundation differs from the coordinated pin".into());
}
let mut args = vec!["ls-files", "--others", "--"];
args.extend_from_slice(INPUTS);
let unknown = git(root, &args)?;
if !unknown.status.success() || !unknown.stdout.is_empty() {
return Err("untracked actual Batter foundation inputs are not reviewed".into());
}
let expected = git(root, &["show", &format!("{revision}:Cargo.toml")])?;
if !expected.status.success() {
return Err("reviewed Batter revision is unavailable in the actual source checkout".into());
}
let expected: toml::Table = String::from_utf8(expected.stdout)?.parse()?;
let actual: toml::Table = fs::read_to_string(root.join("Cargo.toml"))?.parse()?;
let mut inherited = BTreeSet::new();
for input in INPUTS {
let manifest: toml::Table =
fs::read_to_string(root.join(input).join("Cargo.toml"))?.parse()?;
inherited_dependencies(&manifest, &mut inherited);
}
if projection(&actual, &inherited) != projection(&expected, &inherited) {
return Err(
"inherited Batter foundation manifest inputs differ from the coordinated pin".into(),
);
}
Ok(())
}

// Include dependencies under target-specific and build/dev tables as well.
fn inherited_dependencies(table: &toml::Table, names: &mut BTreeSet<String>) {
for (key, value) in table {
let Some(table) = value.as_table() else {
continue;
};
if matches!(
key.as_str(),
"dependencies" | "build-dependencies" | "dev-dependencies"
) {
for (name, dependency) in table {
if dependency.get("workspace").and_then(toml::Value::as_bool) == Some(true) {
names.insert(name.clone());
}
}
} else {
inherited_dependencies(table, names);
}
}
}

fn projection(root: &toml::Table, inherited: &BTreeSet<String>) -> toml::Table {
let mut result = toml::Table::new();
if let Some(workspace) = root.get("workspace").and_then(toml::Value::as_table) {
for key in ["package", "lints", "resolver"] {
if let Some(value) = workspace.get(key) {
result.insert(key.into(), value.clone());
}
}
if let Some(dependencies) = workspace
.get("dependencies")
.and_then(toml::Value::as_table)
{
let selected = dependencies
.iter()
.filter(|(name, _)| inherited.contains(*name))
.map(|(name, value)| (name.clone(), value.clone()))
.collect();
result.insert("dependencies".into(), toml::Value::Table(selected));
}
}
result
}

fn git(source: &Path, args: &[&str]) -> Result<std::process::Output, std::io::Error> {
Command::new("git")
.arg("-C")
.arg(source)
.args(args)
.output()
}
Loading
Loading