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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ cut and that this clone does not carry.

## [Unreleased]

## [0.0.68] - 2026-09-07

Complete native setup preservation captures user additions, installed plugin
state and measured configuration outside portable installation ownership.
Returning to a saved setup first preserves current edits, then restores exact
covered bytes, empty directories and supported permissions. Complete backup
format 2 prevents legacy readers from misinterpreting the coverage base.

The OpenCode provider retains prior setup identity and written ownership.
Prepared recovery restores previous provider metadata even after an interrupted
state write. Complete snapshots remain held against rolling retention and status
reports verified recovery integrity and current native-state comparison.

This release uses consumer kit 0.2.11. Install a compatible released ai-stp CLI
reader before using the new provider declaration.

## [0.0.67] - 2026-09-07

nddev-builder creates complete native tool collections: select and author
Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

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

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ members = [
]

[workspace.package]
version = "0.0.67"
version = "0.0.68"
edition = "2024"
rust-version = "1.89"
license = "AGPL-3.0-or-later"
Expand All @@ -23,9 +23,9 @@ sha2 = "0.11"
# `setup-core::archive`); an inflate loop is not, because its bugs are
# memory-safety bugs and it is not improved by being hand-written here.
miniz_oxide = "0.9"
setup-core = { path = "crates/setup-core", version = "0.0.67" }
provider-v3 = { path = "crates/provider-v3", version = "0.0.67" }
harness-runtime = { path = "crates/harness-runtime", version = "0.0.67" }
setup-core = { path = "crates/setup-core", version = "0.0.68" }
provider-v3 = { path = "crates/provider-v3", version = "0.0.68" }
harness-runtime = { path = "crates/harness-runtime", version = "0.0.68" }

[workspace.lints.rust]
unsafe_code = "forbid"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ release is a convenience, not the authorised copy.

```bash
docker run --rm -v "$HOME/.config:/config" \
ghcr.io/nddev-opennetwork/opencode-setup-system:0.0.67 \
ghcr.io/nddev-opennetwork/opencode-setup-system:0.0.68 \
status --target /config/<dir> --json
```

Expand Down
38 changes: 38 additions & 0 deletions crates/harness-runtime/src/facts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ pub struct Harness {
/// Excluded from backups so a slot never holds credentials, and excluded
/// from target identity so the product's own traffic cannot strand a plan.
pub never_touch: &'static [&'static str],
/// Complete preservation surfaces that differ from installation ownership.
/// These may preserve product-managed plugin bytes without making them
/// writable destinations for portable component installation.
pub preservation_surfaces: &'static [PreservationSurface],
/// What a *neighbour's* configuration home looks like from inside a target.
///
/// Every command here takes an explicit `--target` because a change aimed at
Expand Down Expand Up @@ -336,6 +340,17 @@ pub const BACKUP_SLOTS: usize = 10;
/// The bundle format every setup system reads.
pub const BUNDLE_FORMAT: &str = "ai-stp-bundle/2";

/// A native configuration cover used only for explicit complete preservation.
#[derive(Debug, Clone, Copy)]
pub struct PreservationSurface {
/// The target scope this surface describes.
pub scope: Option<TargetScope>,
/// All covered target-relative configuration roots.
pub roots: &'static [&'static str],
/// Credential and runtime paths never copied or restored.
pub excluded: &'static [&'static str],
}

impl Harness {
/// Whether one relative path falls inside a namespace this harness claims.
///
Expand Down Expand Up @@ -524,6 +539,28 @@ impl Harness {
names
}

/// Complete native coverage is independent of portable installation routes.
#[must_use]
pub fn preservation_surface(
&self,
scope: Option<TargetScope>,
) -> (Vec<&'static str>, Vec<&'static str>) {
let mut roots = self.owned_projection(scope).to_vec();
let mut excluded = self.never_captured();
if let Some(surface) = self
.preservation_surfaces
.iter()
.find(|surface| surface.scope == scope)
{
roots.extend_from_slice(surface.roots);
excluded = vec![self.control_directory];
excluded.extend_from_slice(surface.excluded);
}
roots.sort_unstable();
roots.dedup();
(roots, excluded)
}

/// A digest of this build's own manifest.
///
/// The contract is explicit that the release digest must not come from
Expand Down Expand Up @@ -921,6 +958,7 @@ mod tests {
native_namespaces: &["AGENTS.md", "settings.json", "skills"],
shadowing_names: &[],
custody_namespaces: &[],
preservation_surfaces: &[],
never_touch: &[".credentials.json", "sessions"],
foreign_homes: &[],
permission_profiles: &["default"],
Expand Down
15 changes: 15 additions & 0 deletions crates/harness-runtime/src/human.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,20 @@ fn mutate(
(effect, None)
};

let control = resolved.ensure_control_directory()?;
let pool = Pool::open(&control, facts::BACKUP_SLOTS)?;
let native_capture = wire::plan_native_capture(
harness,
&resolved,
HUMAN_SCOPE,
operation,
None,
match &effect {
Effect::Restore { backup_ref } => backup_ref.as_deref(),
_ => None,
},
&pool,
)?;
let artifact = PlanArtifact::new(PlanInputs {
// No scope: the human surface is a person at a terminal, and a
// scope is something a consumer resolves. Omitted rather than
Expand All @@ -1128,6 +1142,7 @@ fn mutate(
_ => None,
},
restore_target_digest,
native_capture,
permission_profile: None,
expires_at: &expiry::deadline_in(PLAN_WINDOW_SECONDS, SystemTime::now()),
// The human surface drives configuration, never the product's own
Expand Down
5 changes: 4 additions & 1 deletion crates/harness-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ pub use catalog::{Catalog, Setup};
// The software types belong to the kernel, but a setup system declares its
// artifact table and depends only on this crate. Re-exported so that stays
// true rather than widening seven dependency lists to reach past it.
pub use facts::{BACKUP_SLOTS, BUNDLE_FORMAT, Foreign, Harness, LaunchBinding, Scoped, Shadow};
pub use facts::{
BACKUP_SLOTS, BUNDLE_FORMAT, Foreign, Harness, LaunchBinding, PreservationSurface, Scoped,
Shadow,
};
pub use setup_core::software::{Artifact, Delivery, Previous, Shape, Software};

/// The kernel's content digest, re-exported for the seven binaries.
Expand Down
Loading