feat: izba.yml manifest + diff/promote/export workflow#119
Merged
Conversation
Owner
Author
|
@greptile review |
Owner
Author
|
@greptile review |
Owner
Author
|
@greptile review |
Owner
Author
|
@greptile review |
Owner
Author
|
@greptile review |
5818d2b to
3ef8320
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s + 3-way state Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….yaml) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wires izba_core::manifest into the CLI:
- commands/mod.rs: shared helpers load_repo_manifest, workspace_default_name,
managed_normalized (reusable by promote/export tasks)
- commands/diff.rs: run() + pure render_deltas(); TDD (RED→GREEN on render tests)
- main.rs: Cmd::Diff { dir, name } + dispatch arm
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`izba diff` with no args defaults dir to ".", and Path::new(".").file_name()
is None, so workspace_default_name bailed with "has no basename". Canonicalize
the dir first so "." resolves to the current directory's basename.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `izba promote` command: the review-gated apply of an izba.yml to the managed sandbox truth. Pure `gate()` function (with 6 outcomes) guards the path — NeverReviewed and Stale bail unless `--force`, Forced* variants warn. Live effects (ReloadPolicy, PortPublish/Unpublish, VolumeAttach/Detach) apply immediately; restart-class fields (cpus/mem/image) apply on `--restart` or are printed as pending. On an image change with `--restart --reset-scratch` (default), `reset_rw_scratch` in sandbox.rs recreates the rw overlay blank at the same apparent size before the new Start, so the guest boots cleanly on the new base. Advances `manifest.base.yaml` and clears `manifest.review` on success. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
promote::run wrote config.json (via write_managed) BEFORE the live daemon RPCs. A mid-apply RPC failure left config.json at the new state; on retry the recomputed diff was empty so the live effects were skipped, yet base+review still advanced — silently diverging live state from managed truth. Reorder so the durable config.json commit lands AFTER all live effects succeed: split apply::write_policy out of write_managed (policy.yaml lands before its ReloadPolicy RPC, which reads it from disk; write_managed reuses it), run the port/volume RPCs, THEN write_managed (config.json), then the Stop->Start restart branch (reads config.json from disk), then write_base + clear_review last. A failure now leaves config.json at the OLD state so a retry recomputes the correct deltas. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… create Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… CLI+app reuse Move load_repo_manifest, managed_normalized, compute_diff, export, and manifest_with_header into izba_core::manifest::ops — a daemon-free module reachable by both the CLI and the Tauri desktop app without pulling in CLI-only crates. CLI commands become thin wrappers that handle name resolution (which depends on name::sanitize) then delegate to ops. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `DiffView`/`DeltaView` serializable view structs in `views.rs` that map
`izba_core::manifest::{DriftState, diff::FieldDelta}` to frontend-safe
strings (state as snake_case, class as "live"/"restart"/"image").
Add two pure-filesystem core functions in `commands.rs` that construct
`Paths::from_env_or_default(None)` directly (no DaemonApi) and delegate to
`izba_core::manifest::ops::{compute_diff, export}`. The diff review token is
discarded — the app diff is a read-only preview; promote is deferred.
Wire two `#[tauri::command]` async wrappers in `lib.rs` (`manifest_diff`,
`manifest_export`) via `spawn_blocking` and register them in
`generate_handler\![]`. No frontend/.tsx changes — UI is a follow-up task.
TDD: `diff_view_maps_state_and_deltas` test in `views.rs` was written first
(RED: E0433 × 5 on `DiffView`), then the structs were added (GREEN). All 43
app tests pass; fmt/clippy/npm-build green.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a 'Project manifest (izba.yml)' section to README.md covering the k8s-style schema example, the two-store trust model (untrusted proposal in /workspace vs host-only managed truth), the diff→promote→export review loop, field blast-radius classes (live/restart/image), the TOCTOU review gate, --force/--restart/--reset-scratch semantics, and the ⚠ weakens-egress flag. Also extends the Commands block with izba diff/promote/export signatures. Add one load-bearing-contracts bullet to CLAUDE.md describing the trust boundary: izba.yml is an untrusted proposal, managed truth is host-only authority, promote is the human-gated bridge, manifest.review + manifest.base.yaml are host-only, and no DAEMON_PROTO_VERSION bump is required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-key allow_index from host → (host, port), expanding each allow entry into per-port rows with max-access for duplicate (host, port) pairs. egress_weakens now correctly flags a verb widening on one port of a duplicate-host entry even when another port for the same host tightens — the previous host-keyed last-wins collapse missed this case entirely. Tests added: - duplicate_host_verb_widening_weakens_egress: read→read-write on one of two same-host entries must flag weakens_egress=true - duplicate_host_pure_tightening_does_not_weaken: read-write→read on one entry must not flag weakens_egress Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ent on restart Fix 2 (promote): bail early when plan.image_changed && !restart — writing the new image_digest to config.json while the old rw scratch overlay persists is a latent boot-failure; the caller must acknowledge the risk by passing --restart (or --restart --reset-scratch=false for the overlay preservation path). Fix 3a (promote): read state.json BEFORE the Stop call in the restart branch so the confinement mode (allow_unconfined) is captured before the VMM teardown clears it. Defaults to false (confined, safe) when state.json is absent or unreadable. Fix 3b (promote): wrap the post-Stop Start call with a helpful retry hint: "config already committed; run izba start <name> to retry". Fix 4 (promote): print an egress-weakening WARNING to stderr before applying any change (even under --force), by calling diff_normalized on managed→repo and checking weakens_egress on each delta. Fix 5 (promote): inspect sandbox liveness before live RPCs (ReloadPolicy / PortPublish / PortUnpublish / VolumeAttach / VolumeDetach); skip them with "sandbox not running — changes apply on next start" when the status is "stopped". write_managed + write_base + clear_review still run unconditionally. Fix 6 (quantity): add parses_ti_round_trips unit test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`Normalized::from_managed` set `rw_size_gb: 0` because `SandboxConfig`
does not persist the scratch size after create. This caused `to_manifest()`
to emit `rootDisk: { size: "0" }`, which then fails to parse back through
`quantity::parse_gib` (no unit suffix). Re-read the real size from the
actual `rw.img` file length in `managed_normalized` so that `izba export`
always produces a valid, re-parseable manifest.
Test: `managed_normalized_recovers_rw_size_from_rw_img` seeds a 8 GiB
sparse rw.img, asserts `rw_size_gb == 8`, and verifies the exported YAML
round-trips through `Manifest::load_str` and `quantity::parse_gib`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…messages Fix 1: `merge_manifest_into_opts` now mirrors the ports logic for volumes: when the user passes no `--volume` flags, volumes declared in `izba.yml` are serialised back into the `[NAME:]GUEST_PATH:SIZEg` flag strings the parser expects and adopted into `opts.volumes`. Explicit flags always win. Two tests cover the happy path (volumes adopted) and the guard (explicit flag not overridden). Fix 2/3: Two `bail!` strings in `promote.rs` had literal runs of spaces from multi-line string indentation (`"...reset on the new..."`). Replaced with `\` line-continuation so words join with a single space. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ncation
A manifest volume with size < 1 GiB (e.g. 512Mi) was formatted as
`{n}g` with n = size_bytes >> 30 = 0, producing an invalid `0g` flag
that parse_size rejected. Now chooses GiB when the size is an exact
GiB multiple, MiB otherwise — so 512Mi → `512m` and 8Gi → `8g`.
Adds a TDD test covering both cases via parse_volume_flag round-trip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rough promote/diff/export Add `build: Option<BuildSpec>` (serde default=None) to SandboxConfig so write_managed records build provenance for Build-spec sandboxes. from_managed now reconstructs ImageSource::Build from cfg.build instead of always emitting ImageSource::Ref, eliminating the perpetual image-delta drift and the silent clobbering of build: blocks during izba export. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix A: Stop is now only sent when the sandbox is_running; --restart on a stopped sandbox simply resets scratch (if needed) and Starts without an unconditional Stop that would error on a non-running daemon. The "changes apply on next start" warning is suppressed when --restart will Start the sandbox. Fix B: build_opts_from now returns anyhow::Result and propagates a parse_mib failure on build.resources.memory with context instead of silently falling back to 4096. Three unit tests added: 4Gi→4096, 4GB→Err with context message, None→4096 default. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…space (path traversal) Two Greptile-flagged path-traversal vulnerabilities fixed: 1. Sandbox name from manifest metadata was never validated before being joined onto the sandboxes dir. A hostile izba.yml with `metadata.name: "../../tmp/evil"` escaped ~/.local/share/izba/sandboxes/. Fix: call `crate::sandbox::validate_name(name)?` at the top of `managed_normalized`, `compute_diff`, and `export` in ops.rs. 2. Agent-controlled `context`/`dockerfile` fields in the build: spec were joined onto the workspace dir and read without any containment check. A manifest with `context: "../../../../"` + `dockerfile: "etc/shadow"` caused `izba diff` / `izba promote` to read arbitrary host files. Fix: add `pub fn ensure_within(base, candidate) -> Result<PathBuf>` that canonicalizes existing paths and rejects any `..` component for non-existent ones; apply it in `load_repo_manifest` (ops.rs) and `build_opts_from` (promote.rs). Error messages deliberately omit the escaped absolute path. Tests: 7 new tests (3 name-validation + 4 ensure_within/load_repo_manifest). All 6 CI gates pass: core 678/cli 119/clippy clean/fmt clean/win-cross/app. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p) for Windows CI
Replace PathBuf::from("/tmp") with tempfile::tempdir() + a real Dockerfile
so ensure_within's canonicalize() succeeds on Windows (where /tmp doesn't
exist), allowing each test to reach its intended assertion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dows) The non-existent-path branch built a lexical PathBuf from candidate.components() and compared it against canon_base (from base.canonicalize()). On Windows, canonicalize() returns a verbatim extended path (\\?\C:\...) while the plain candidate is C:\..., so starts_with always returned false and any non-existent child (e.g. tmp/subdir/Dockerfile) was wrongly rejected as "escapes the workspace". Fix: walk up to the longest existing ancestor, canonicalize that (giving a verbatim path on Windows), verify it starts_with(canon_base), then re-append the non-existent tail. Both sides of the comparison are now canonical so the check is consistent across platforms. The .. rejection is preserved as-is (dotdot test unchanged). New test: ensure_within_accepts_nonexistent_nested_child (a/b/c.txt where a does not exist) validates the ancestor-walk path. Windows host-path audit: all other /data /cache /workspace assertions in manifest and command tests are logical guest paths or flag-string values — no host-path portability issues found. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…le image-pending note
Hoist validate_name before the first paths.sandbox_dir(&name) call so a
traversal name (e.g. "../../etc") is rejected before any path construction.
Add sentinel test validate_name_rejects_traversal.
Remove the dead image-change pending note in the \!restart branch (lines
251-257): the earlier `if p.image_changed && \!restart { bail\! }` guard
ensures image_changed is always false when reaching that branch, making
the println unreachable. cpus/mem pending-restart messaging is unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add KVM-gated integration test `manifest_diff_promote_live_path` that exercises the full manifest live-apply loop against a running sandbox: boot with an initial enforcing policy, write izba.yml adding a second egress host + a port relay, run `izba diff` (assert both deltas appear), `izba promote` (no --restart), then assert the live policy reloaded and the port relay is reachable via http_get. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e errors in export reset_rw_scratch now writes to rw.img.tmp in the same directory, runs set_len/mark_sparse/best_effort_mkfs on the tmp file, then atomically renames it over rw.img. If any step before the rename fails the original rw.img is left untouched and the temp file is cleaned up. Extended the existing test to also assert no .tmp debris after a successful reset. export.rs name-resolution now only falls back to the directory-basename default when izba.yml does NOT exist; when the file exists but is malformed the parse error is propagated (previously Err(_) swallowed both cases, silently exporting the wrong sandbox on a broken manifest). Added two unit tests: malformed-exists → Err, missing → no error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ix(cli): skip Dockerfile read during name resolution Fix 1 (CLI): merge_manifest_into_opts now reads only the YAML without calling load_repo_manifest, which previously read the Dockerfile for build: specs. This prevents "reading Dockerfile: No such file" errors on healthy existing sandboxes whose Dockerfile was deleted/cleaned — izba run . on a build-spec sandbox now correctly reaches reconcile_existing without erroring on missing Dockerfile bytes. Fix 2 (core): add rw_size_gb: u64 (#[serde(default)]) to SandboxConfig, set it from opts.rw_size_gb at create time (sandbox.rs), and use it in managed_normalized (ops.rs) as the primary source with rw.img file-length as a back-compat fallback for pre-existing sandboxes. Sub-GiB fallback rounds up to 1 GiB so to_manifest() never emits the un-parseable bare "0" in rootDisk.size. write_managed preserves the existing rw_size_gb since it is immutable post-create. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The incremental mutation gate failed two ways on the manifest PR:
1. Real caught-nowhere survivors on the new code:
- core (host-testable) gaps now covered by killing tests:
- normalize::from_manifest build-spec arm (+ both-set guard)
- diff::image_str ref/build rendering; egress_weakens git-rule path
(new rule, read->read-write widening, tightening/identity negatives)
- apply::plan removed-volume filter + image-as-restart-field
- merge_manifest_into_opts mem / rw_size_gb adoption guards
- CLI orchestration entry points (live daemon+VM, e2e-only via daemon_e2e)
get #[mutants::skip] with a justification, matching the established
run.rs/build.rs convention. The pure logic they compose stays under test.
2. The windows gate timed out: this PR's large changed-line set is ~196
mutants, and each izba-core rebuild is ~4x slower on windows, pushing a
single job past the 60-min cap. Shard the windows incremental gate 4 ways
(mirrors the scheduled full run): cargo-mutants assigns mutant i to shard
i%4 after the stable --no-shuffle order, spreading the slow core rebuilds
round-robin. The aggregator already merges N dirs with the caught-nowhere
rule, so the partition is invisible to the verdict.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first round skip/test pass missed survivors in files the timed-out
windows gate never reached; the now-sharded gate ran to completion and
the aggregator surfaced 7 caught-nowhere mutants. Add precise killing
tests:
- diff::egress_weakens git guard `&&` (95:43): an UNCHANGED Read git rule
paired with an unrelated tightening (removed allow host) — isolates
`from==Read && to==ReadWrite` (true && false) from a `||` that would
wrongly fire.
- ops::managed_normalized rw.img guard `> 0` (139:41): a sub-GiB rw.img
(len>>30 == 0) must round UP to 1 GiB, not pass 0 through.
- store::{read_base,read_review,clear_review} NotFound match guards
(44/57/65): a directory at the path forces a non-NotFound I/O error
that must propagate (not be swallowed as Ok(None)/Ok(())); plus
clear_review idempotency on an absent token.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The unsharded Linux gate hit its 45-min cap on this PR's changed-line set (run 28436162656: "The operation was canceled" at exactly 45m), which made the aggregator fail fast on linux=cancelled before ever reconciling — so the mutation gate could never go green regardless of coverage. Shard gate-linux 2x the same way gate-windows is sharded (i%n round-robin after the stable --no-shuffle order); the aggregator already merges any number of shard dirs per platform via the caught-nowhere rule, so the partition stays invisible to the verdict. Run the exclude-pin guard only on shard 0. Aggregator now downloads gate-linux-* by glob like gate-windows-*. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
81e326e to
1375117
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
Adds a Kubernetes-style project manifest (
izba.yml) plus anizba diff/izba promote/izba exportreconciliation workflow, so a project's sandbox configuration (image/build, resources, volumes, ports, egress policy) can live in the repo and be version-controlled — while keeping the in-guest agent unable to silently change its own jail.Design:
docs/superpowers/specs/2026-06-28-izba-manifest-diff-promote-design.md· Plan:docs/superpowers/plans/2026-06-28-izba-manifest-diff-promote.mdTrust model (the spine)
izba.ymllives in the workspace, which is mounted into the guest at/workspace— so the in-guest agent can edit it. It is therefore an untrusted proposal. The managed truth (config.json+policy.yamlunder~/.local/share/izba/sandboxes/<name>/, host-only, outside the guest overlay) is authority.izba promoteis the human-gated bridge:izba diffrecords a host-only review token (manifest.review) over the exact manifest and referenced Dockerfile bytes.izba promoterequires that token to match: no token → fail (run diff first); stale token → fail (TOCTOU guard — manifest changed after review);--forceoverrides both, loudly.manifest.review/manifest.base.yamlare host-only and never enter the overlay, so the guest cannot read or forge a reviewed state.Surface
izba_core::manifest):apiVersion: izba.dev/v1alpha1/kind: Sandbox/metadata/spec(image xor build recipe,resources,rootDisk,volumes,ports,egress), k8s quantity strings (4Gi),kind-extensible to a futureProject. Theegressblock reuses the existing policy type verbatim.izba diff— structural 3-way drift (base/repo/managed), per-field blast-radius class (live / restart / image),⚠ weakens egressflag, records the review token.izba promote— gated apply: live fields (policy/ports/volumes) apply immediately; cpus/mem/image are restart-class (--restart); image changes reset the rw scratch overlay (--reset-scratch, default yes) with a loud expert-only warning when kept; image changes require--restart; confinement posture is replayed fromstate.jsonon restart; live RPCs are skipped on a stopped sandbox.izba export— write the managed truth back toizba.yml(declarative only — no secrets), for the app-edits-then-commit flow.izba create/izba runhonor anizba.ymlwhen present (flags still win) and seed the manifest base.manifest_diff/manifest_exportcommands +DiffView(drift badge / preview / save-to-repo).No
DAEMON_PROTO_VERSIONbump — diff/promote/export are host-side over existing daemon RPCs + host-callable image resolution/build.Deferred (follow-up)
rootDisksize inSandboxConfig(diff currently ignores rw size, documented).build-arg/secret/no-cache/target).Testing
Built TDD, subagent-driven, with per-task spec+quality review and a final whole-branch review (all findings fixed, incl. duplicate-host egress-weakening detection and the non-restart image-promote scratch-reset safety gap). All six workspace gates + the App gate verified green locally:
cargo test --workspace,clippy --workspace -D warnings,fmt --check,izba-initmusl build,x86_64-pc-windows-gnucheck + clippy, andapp(npm build + src-tauri fmt/clippy/test).🤖 Generated with Claude Code
Greptile Summary
This PR introduces the
izba.ymlmanifest system — a Kubernetes-style YAML config (apiVersion: izba.dev/v1alpha1,kind: Sandbox) enabling version-controlled sandbox configuration with a TOCTOU-safe diff/promote/export workflow.izba diff,izba promote, andizba exportCLI subcommands backed by newmanifest/modules (schema,normalize,diff,ops,apply,store,quantity) inizba-corediffand verified bypromoteto prevent TOCTOU races; path/name traversal guards (ensure_within,validate_name) protect agent-controlled fieldsSandboxConfigwithbuild: Option<BuildSpec>andrw_size_gb: u64(bothserde(default)) for backward-compatible persistence, and makesreset_rw_scratchatomic via a tmp-file +fs::renamepatternConfidence Score: 5/5
Safe to merge; no blocking issues found beyond minor P2 observations
All previously-raised issues are addressed. The three new observations are P2 quality/robustness notes (double manifest read, non-total sort order, noisy egress emit) with no correctness impact on the happy path. Security guards (ensure_within, validate_name, review token) are correctly implemented.
crates/izba-core/src/manifest/diff.rs and crates/izba-cli/src/commands/diff.rs for the double load_repo_manifest call
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Agent participant CLI as izba CLI participant Store participant Core as izba-core participant Daemon Agent->>CLI: izba diff [--name] CLI->>Core: load_repo_manifest(dir) Core-->>CLI: (manifest, name) CLI->>Core: compute_diff(paths, dir, name) Core->>Core: load_repo_manifest (2nd read) Core->>Core: managed_normalized Core->>Core: diff / classify Core-->>CLI: (DriftState, deltas, token) CLI->>Store: write_review(sandbox_dir, token) CLI-->>Agent: drift report Agent->>CLI: izba promote [--force] CLI->>Store: read_review(sandbox_dir) CLI->>Core: compute_diff (recompute token) Core-->>CLI: current_token CLI->>CLI: gate(stored, current, force) alt token matches CLI->>Core: plan(current, target) CLI->>Daemon: live RPCs (CPU/mem/ports/egress) CLI->>Core: write_managed CLI->>Core: write_policy CLI->>Daemon: ReloadPolicy opt image or restart required CLI->>Daemon: Stop CLI->>Core: reset_rw_scratch (atomic) CLI->>Daemon: Start end CLI->>Store: clear_review else token mismatch CLI-->>Agent: error: manifest changed since diff end Agent->>CLI: izba export [dir] CLI->>Core: export(paths, name, dir) Core->>Core: managed_normalized → to_manifest Core-->>CLI: Manifest YAML CLI-->>Agent: writes izba.yml%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Agent participant CLI as izba CLI participant Store participant Core as izba-core participant Daemon Agent->>CLI: izba diff [--name] CLI->>Core: load_repo_manifest(dir) Core-->>CLI: (manifest, name) CLI->>Core: compute_diff(paths, dir, name) Core->>Core: load_repo_manifest (2nd read) Core->>Core: managed_normalized Core->>Core: diff / classify Core-->>CLI: (DriftState, deltas, token) CLI->>Store: write_review(sandbox_dir, token) CLI-->>Agent: drift report Agent->>CLI: izba promote [--force] CLI->>Store: read_review(sandbox_dir) CLI->>Core: compute_diff (recompute token) Core-->>CLI: current_token CLI->>CLI: gate(stored, current, force) alt token matches CLI->>Core: plan(current, target) CLI->>Daemon: live RPCs (CPU/mem/ports/egress) CLI->>Core: write_managed CLI->>Core: write_policy CLI->>Daemon: ReloadPolicy opt image or restart required CLI->>Daemon: Stop CLI->>Core: reset_rw_scratch (atomic) CLI->>Daemon: Start end CLI->>Store: clear_review else token mismatch CLI-->>Agent: error: manifest changed since diff end Agent->>CLI: izba export [dir] CLI->>Core: export(paths, name, dir) Core->>Core: managed_normalized → to_manifest Core-->>CLI: Manifest YAML CLI-->>Agent: writes izba.ymlReviews (20): Last reviewed commit: "ci(mutants): shard the linux incremental..." | Re-trigger Greptile
Context used: