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
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ diligence-demo:
echo "diligence-demo: host Path B golden lines ok"

# Host sell-path: named attacks the kernel already refuses. Reuses
# blast / blast-hops / blast-nodes / bank-color / uncolored-compute / foreign-tenant-color / qos-credits / fence-not-ready / outside-slice / typed-window-sid / silent-remote / hbm-bw / xqueue-sid-override / set-sid-unbound / submit-sid / sid-budget / stage2-fault / softnoi-exhausted / hodge-harmonic-tree / hodge-curl-tree / hodge-quota / SoftCmdFirewall / firewall-ident-pa / greenctx-overcommit / greenctx-unbound / greenctx-exhausted / SoftSFI / SoftNoI-IS / PASID clips.
# blast / blast-hops / blast-nodes / bank-color / uncolored-compute / foreign-tenant-color / qos-credits / fence-not-ready / outside-slice / typed-window-sid / silent-remote / hbm-bw / xqueue-sid-override / set-sid-unbound / submit-sid / sid-budget / stage2-fault / softnoi-exhausted / hodge-harmonic-tree / hodge-curl-tree / hodge-quota / SoftCmdFirewall / firewall-ident-pa / greenctx-overcommit / greenctx-unbound / greenctx-exhausted / greenctx-busy / SoftSFI / SoftNoI-IS / PASID clips.
# CI greps the [redteam] proof lines. Not a QEMU guest.
REDTEAM_LOG := $(BUILD)/redteam.log

Expand Down Expand Up @@ -176,6 +176,7 @@ red-team:
grep -q "\\[redteam\\] attack=greenctx-overcommit result=refused" $(REDTEAM_LOG)
grep -q "\\[redteam\\] attack=greenctx-unbound result=refused" $(REDTEAM_LOG)
grep -q "\\[redteam\\] attack=greenctx-exhausted result=refused" $(REDTEAM_LOG)
grep -q "\\[redteam\\] attack=greenctx-busy result=refused" $(REDTEAM_LOG)
grep -F -x -q "[redteam] fabric-class admit/refuse" $(REDTEAM_LOG)
grep -F -x -q "[redteam] ATOMIC_ADD accept/reject" $(REDTEAM_LOG)
grep -F -x -q "[softsfi] tensor=refused" $(REDTEAM_LOG)
Expand Down
61 changes: 61 additions & 0 deletions core/src/greenctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,57 @@ pub fn run_greenctx_exhausted_demo() -> GreenCtxExhaustedReport {
}
}


/// Host red-team report for SoftGreenPool migrate_to_yield Busy refuse.
///
/// Sell line `[redteam] attack=greenctx-busy` — existing
/// [`SoftGreenPool::migrate_to_yield`] path only. Dest ctx already bound to
/// another queue → [`GreenCtxError::Busy`]. Same-SID happy migrate still OK on
/// a free dest. **Not** greenctx-unbound (never-bound queue), **not**
/// greenctx-overcommit / greenctx-exhausted, **not** xqueue-sid-override Soft-CP
/// Busy, **not** HW MIG / BAR0 / SoftNPU.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct GreenCtxBusyReport {
/// Bind lo→0 and hi→1; migrate 0→hi (dest busy with 1) → Busy; queues stick.
pub busy: bool,
/// Optional same-pool bind contrast: re-bind lo to a foreign queue → Busy.
pub bind_busy: bool,
/// Contrast: never-bound queue still → Unbound (sibling needle stays separate).
pub contrast_unbound: bool,
}

impl GreenCtxBusyReport {
pub fn all_ok(&self) -> bool {
self.busy && self.bind_busy && self.contrast_unbound
}
}

/// `SoftGreenPool::migrate_to_yield` when dest is bound elsewhere → [`GreenCtxError::Busy`].
/// Occupied dest path — not Unbound / Overcommit / Exhausted / xqueue Busy / HW MIG.
pub fn run_greenctx_busy_demo() -> GreenCtxBusyReport {
let mut p = SoftGreenPool::new();
let (hi, lo) = p.split_70_30().unwrap();
p.bind(lo, 0).unwrap();
p.bind(hi, 1).unwrap();
let sid = StreamId::from_raw(0x11_22_33_44);
// Dest hi already holds queue 1 ≠ 0 → Busy. Queues stay put.
let busy = p.migrate_to_yield(0, hi, sid) == Err(GreenCtxError::Busy)
&& p.ctx_for_queue(0) == Some(lo)
&& p.ctx_for_queue(1) == Some(hi);
// Optional bind-busy (same Error::Busy; not a separate PR): lo already on 0.
let bind_busy = p.bind(lo, 1) == Err(GreenCtxError::Busy);
// Fresh pool: never-bound queue → Unbound (sibling contrast).
let mut p2 = SoftGreenPool::new();
let (hi2, _lo2) = p2.split_70_30().unwrap();
let contrast_unbound = p2.migrate_to_yield(1, hi2, sid) == Err(GreenCtxError::Unbound);

GreenCtxBusyReport {
busy,
bind_busy,
contrast_unbound,
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -725,4 +776,14 @@ mod tests {
assert!(r.contrast_overcommit, "70/30 fill → Overcommit contrast");
assert!(r.all_ok());
}

#[test]
fn greenctx_busy_demo_refuses_occupied_dest() {
let r = run_greenctx_busy_demo();
assert!(r.busy, "dest bound elsewhere → Busy");
assert!(r.bind_busy, "re-bind foreign queue → Busy");
assert!(r.contrast_unbound, "never-bound → Unbound contrast");
assert!(r.all_ok());
}

}
4 changes: 2 additions & 2 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ pub use elf::{parse_elf64, ElfError, ElfImage};
pub use fabric::{ChipletRoute, EndpointId, Fabric, FabricError, Message, MsgFlags};
pub use fence::{run_fence_not_ready_demo, Fence, FenceId, FenceNotReadyReport, Timeline, TimelineId, MAX_IN_FLIGHT};
pub use greenctx::{
run_greenctx_demo, run_greenctx_exhausted_demo, run_greenctx_overcommit_demo,
run_greenctx_unbound_demo, GreenCtxError, GreenCtxExhaustedReport, GreenCtxId,
run_greenctx_busy_demo, run_greenctx_demo, run_greenctx_exhausted_demo, run_greenctx_overcommit_demo,
run_greenctx_unbound_demo, GreenCtxBusyReport, GreenCtxError, GreenCtxExhaustedReport, GreenCtxId,
GreenCtxOvercommitReport, GreenCtxReport, GreenCtxUnboundReport, MemcpyReport, SmWqBudget,
SoftGreenCtx, SoftGreenPool, DEMO_MEMCPY_BYTES, MAX_GREEN_CTX, SHARED_BW_TAX_MILLI,
SOFT_SM_POOL, SOFT_WQ_POOL, SPLIT_30, SPLIT_70,
Expand Down
6 changes: 4 additions & 2 deletions docs/DILIGENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ reserved. Freeze proof: `make design-win-standin`. Port skipped
| Command | What they see |
| --- | --- |
| `make diligence-demo` | blast / pjrt / event + fence counts / softcct package ≪ broadcast + single-chiplet=noop + incorrect-elision=refused / `[scope] soft≠strict` / firewall / greenctx 70/30 + interference + migrate SID-sticky / cdt revoke descendants / softcp sparsify DROP / opinject resident+hot-add / partner-hello bad-exec |
| `make red-team` | named refuses + fabric-class + `ATOMIC_ADD` + `[softsfi] tensor=refused` + `[softsfi] heap=refused` + `[softsfi] unknown=refused` + `[softsfi] unknown-base=refused` + `typed-window-sid` + `hbm-bw` + `xqueue-sid-override` + `set-sid-unbound` + `submit-sid` + `sid-budget` + `stage2-fault` + `softnoi-exhausted` + `hodge-harmonic-tree` + `hodge-curl-tree` + `hodge-quota` + `firewall-ident-pa` + `greenctx-overcommit` + `greenctx-unbound` + `greenctx-exhausted` + `foreign-tenant-color` |
| `make red-team` | named refuses + fabric-class + `ATOMIC_ADD` + `[softsfi] tensor=refused` + `[softsfi] heap=refused` + `[softsfi] unknown=refused` + `[softsfi] unknown-base=refused` + `typed-window-sid` + `hbm-bw` + `xqueue-sid-override` + `set-sid-unbound` + `submit-sid` + `sid-budget` + `stage2-fault` + `softnoi-exhausted` + `hodge-harmonic-tree` + `hodge-curl-tree` + `hodge-quota` + `firewall-ident-pa` + `greenctx-overcommit` + `greenctx-unbound` + `greenctx-exhausted` / `greenctx-busy` + `foreign-tenant-color` |
| `make partner-hello` | frozen `IreeHalCmd` → `IreeShapedCp`; bad exec refused |
| `make mp-shim` | MicroPerceptron-shaped thin consumer (PR #83). Inspiration name only. Not a port. |
| `make design-win-check` / `make design-win-standin` | blank they fill, or the IREE HAL research stand-in (not a partner). TRANSFER-only refused. |
Expand Down Expand Up @@ -323,7 +323,7 @@ task-local AP_EL0 leaves + Soft SMMU” (no PAN on cortex-a72).
| --- | --- | --- |
| Host tests | `cargo test --workspace` | Caps + CDT properties, fabric, arenas, color, map, typed window stub, sched, SoftNPU, Laplacian, ELF, ramfs, bootfs, mmap, opkernel, sparsify, diligence-demo + red-team + accel-client + aether-mp-shim + design-win-check crates, partner-hello |
| Diligence demo | `make diligence-demo` | Host Path B partner clip; greps `[blast]` / `[pjrt]` / `[event]` / `[softcct]` (package ≪ broadcast + `single-chiplet=noop` + `incorrect-elision=refused`) / `[scope] soft≠strict` / `[firewall]` / `[greenctx]` (incl. M3 interference + migrate SID-sticky) / `[cdt] revoke descendants ok` / `[softcp] sparsify DROP` / `[opinject] resident worker + hot-add sealed` / `[partner-hello] bad executable` + proves/does-not. No QEMU rebuild. Caps/CDT honesty ≠ CapTable milestone |
| Red-team clip | `make red-team` | Host stdout; greps `[redteam] attack=… result=refused` plus fabric-class / `ATOMIC_ADD` / `[softsfi] tensor=refused` / `[softsfi] heap=refused` / `[softsfi] unknown=refused` / `[softsfi] unknown-base=refused` / `typed-window-sid` / `hbm-bw` / `xqueue-sid-override` / `set-sid-unbound` / `submit-sid` / `sid-budget` / `stage2-fault` / `softnoi-exhausted` / `hodge-harmonic-tree` / `hodge-curl-tree` / `hodge-quota` / `firewall-ident-pa` / `greenctx-overcommit` / `greenctx-unbound` / `greenctx-exhausted` / `foreign-tenant-color` and the “what this is not” closer |
| Red-team clip | `make red-team` | Host stdout; greps `[redteam] attack=… result=refused` plus fabric-class / `ATOMIC_ADD` / `[softsfi] tensor=refused` / `[softsfi] heap=refused` / `[softsfi] unknown=refused` / `[softsfi] unknown-base=refused` / `typed-window-sid` / `hbm-bw` / `xqueue-sid-override` / `set-sid-unbound` / `submit-sid` / `sid-budget` / `stage2-fault` / `softnoi-exhausted` / `hodge-harmonic-tree` / `hodge-curl-tree` / `hodge-quota` / `firewall-ident-pa` / `greenctx-overcommit` / `greenctx-unbound` / `greenctx-exhausted` / `greenctx-busy` / `foreign-tenant-color` and the “what this is not” closer |
| Design-win checker | `make design-win-check` | Loads sample filled worksheet; refuses unknown executable / SID 0 / TRANSFER-only. No pipes |
| IREE HAL stand-in | `make design-win-standin` | Admits `docs/design-win/iree-hal-standin.toml`. Not a partner |
| Partner hello | `make partner-hello-ci` | Frozen `IreeHalCmd` pack/submit + bad executable refuse; no QEMU |
Expand Down Expand Up @@ -383,6 +383,7 @@ runs `examples/red-team` on the host and prints grep-able lines. It
| SoftGreenPool SM/WQ overcommit | `run_greenctx_overcommit_demo` — `SoftGreenPool::create` → `GreenCtxError::Overcommit` past pool (in-budget admits; after 70/30 fill refuses). **Not** diligence `run_greenctx_demo` 70/30 sell; not HW MIG / BAR0 / SoftNPU | refused |
| SoftGreenPool migrate unbound | `run_greenctx_unbound_demo` — `SoftGreenPool::migrate_to_yield` → `GreenCtxError::Unbound` on never-bound queue (bound migrate keeps SID). **Not** set-sid-unbound Soft-CP Fault; not greenctx-overcommit; not HW MIG / BAR0 / SoftNPU | refused |
| SoftGreenPool slot exhausted | `run_greenctx_exhausted_demo` — `SoftGreenPool::create` past `MAX_GREEN_CTX` → `GreenCtxError::Exhausted` (tiny in-budget fills admit; contrast after 70/30 → Overcommit). **Not** greenctx-overcommit SM/WQ; not SoftNoI Exhausted; not HW MIG / BAR0 / SoftNPU | refused |
| SoftGreenPool migrate dest busy | `run_greenctx_busy_demo` — `SoftGreenPool::migrate_to_yield` → `GreenCtxError::Busy` when dest bound to another queue (`bind(lo,0); bind(hi,1); migrate 0→hi`). **Not** greenctx-unbound; not overcommit/exhausted; not xqueue-sid-override Soft-CP Busy; not HW MIG / BAR0 / SoftNPU | refused |

Expected stdout (CI greps these):

Expand Down Expand Up @@ -416,6 +417,7 @@ Expected stdout (CI greps these):
[redteam] attack=greenctx-overcommit result=refused
[redteam] attack=greenctx-unbound result=refused
[redteam] attack=greenctx-exhausted result=refused
[redteam] attack=greenctx-busy result=refused
[redteam] fabric-class admit/refuse
[redteam] ATOMIC_ADD accept/reject
[softsfi] tensor=refused
Expand Down
4 changes: 3 additions & 1 deletion examples/red-team/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Host stdout a buyer can grep. Reuses `run_blast_demo`, `run_blast_hops_demo`,
`run_blast_nodes_demo`, `run_bank_color_demo`, `run_uncolored_compute_demo`,
`run_foreign_tenant_color_demo`, `run_qos_credits_demo`, `run_fence_not_ready_demo`, `run_outside_slice_demo`, `run_typed_window_sid_demo`,
`run_silent_remote_demo`, `run_hbm_bw_demo`, `run_xqueue_sid_override_demo`, `run_set_sid_unbound_demo`, `run_submit_sid_demo`, `run_sid_budget_demo`, `run_stage2_fault_demo`, `run_softnoi_exhausted_demo`,
`run_hodge_harmonic_tree_demo`, `run_hodge_curl_tree_demo`, `run_hodge_quota_demo`, `run_firewall_demo`, `run_firewall_ident_pa_demo`, `run_greenctx_overcommit_demo`, `run_greenctx_unbound_demo`, `run_greenctx_exhausted_demo`, `run_softsfi_demo`,
`run_hodge_harmonic_tree_demo`, `run_hodge_curl_tree_demo`, `run_hodge_quota_demo`, `run_firewall_demo`, `run_firewall_ident_pa_demo`, `run_greenctx_overcommit_demo`, `run_greenctx_unbound_demo`, `run_greenctx_exhausted_demo`, `run_greenctx_busy_demo`, `run_softsfi_demo`,
`run_softnoi_demo`, and `run_sva_demo`.
Not a new isolator, not a QEMU guest, not a slide. Blast-nodes needle:
`[redteam] attack=blast-nodes result=refused` (`admit_nodes` → `BlastRadius`;
Expand Down Expand Up @@ -69,6 +69,8 @@ set-sid-unbound Soft-CP Fault; not greenctx-overcommit; not HW MIG / BAR0 / Soft
Greenctx-exhausted needle: `[redteam] attack=greenctx-exhausted result=refused`
(`SoftGreenPool::create` past `MAX_GREEN_CTX` slots → `GreenCtxError::Exhausted`; not
greenctx-overcommit SM/WQ ceiling; not SoftNoI Exhausted; not HW MIG / BAR0 / SoftNPU).
Greenctx-busy needle: `[redteam] attack=greenctx-busy result=refused`
(`SoftGreenPool::migrate_to_yield` when dest bound to another queue → `GreenCtxError::Busy`; not greenctx-unbound; not overcommit/exhausted; not xqueue-sid-override Soft-CP Busy; not HW MIG / BAR0 / SoftNPU).
SoftSFI tensor needle: `[softsfi] tensor=refused` (`SoftOp::Tensor` → `Unmodeled`;
heap line stays separate).
SoftSFI unknown needle: `[softsfi] unknown=refused` / `[softsfi] unknown-base=refused` (bad opcode / illegal width →
Expand Down
25 changes: 22 additions & 3 deletions examples/red-team/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! `run_bank_color_demo`, `run_uncolored_compute_demo`,
//! `run_foreign_tenant_color_demo`, `run_qos_credits_demo`, `run_fence_not_ready_demo`, `run_outside_slice_demo`, `run_typed_window_sid_demo`,
//! `run_silent_remote_demo`, `run_hbm_bw_demo`, `run_xqueue_sid_override_demo`,
//! `run_set_sid_unbound_demo`, `run_submit_sid_demo`, `run_sid_budget_demo`, `run_stage2_fault_demo`, `run_softnoi_exhausted_demo`, `run_hodge_harmonic_tree_demo`, `run_hodge_curl_tree_demo`, `run_hodge_quota_demo`, `run_firewall_demo`, `run_firewall_ident_pa_demo`, `run_greenctx_overcommit_demo`, `run_greenctx_unbound_demo`, `run_greenctx_exhausted_demo`,
//! `run_set_sid_unbound_demo`, `run_submit_sid_demo`, `run_sid_budget_demo`, `run_stage2_fault_demo`, `run_softnoi_exhausted_demo`, `run_hodge_harmonic_tree_demo`, `run_hodge_curl_tree_demo`, `run_hodge_quota_demo`, `run_firewall_demo`, `run_firewall_ident_pa_demo`, `run_greenctx_overcommit_demo`, `run_greenctx_unbound_demo`, `run_greenctx_exhausted_demo`, `run_greenctx_busy_demo`,
//! `run_softsfi_demo`, `run_softnoi_demo`, `run_sva_demo`).
//! This crate does not invent a new isolation mechanism.
//!
Expand Down Expand Up @@ -60,7 +60,9 @@
//! `migrate_to_yield` on a queue with no bound ctx → `GreenCtxError::Unbound` (not set-sid-unbound Soft-CP
//! Fault; not greenctx-overcommit SM/WQ ceiling; not HW MIG / BAR0 / SoftNPU). Greenctx-exhausted is SoftGreenPool
//! `create` past `MAX_GREEN_CTX` slots → `GreenCtxError::Exhausted` (not greenctx-overcommit SM/WQ ceiling;
//! not SoftNoI Exhausted; not HW MIG / BAR0 / SoftNPU). The closer names what this is **not**:
//! not SoftNoI Exhausted; not HW MIG / BAR0 / SoftNPU). Greenctx-busy is SoftGreenPool
//! `migrate_to_yield` when dest is bound to another queue → `GreenCtxError::Busy` (not greenctx-unbound;
//! not greenctx-overcommit / exhausted; not xqueue-sid-override Soft-CP Busy; not HW MIG / BAR0 / SoftNPU). The closer names what this is **not**:
//! confidential GPU, HW MIG, hardware SMMU (Soft SMMU is software).
//!
//! Run: `make red-team` or `cargo run -p aether-redteam`.
Expand All @@ -81,7 +83,7 @@ use aether_core::sva::run_sva_demo;
use aether_core::window::run_typed_window_sid_demo;
use aether_core::opkernel::{run_hodge_curl_tree_demo, run_hodge_harmonic_tree_demo};
use aether_core::hodge::run_hodge_quota_demo;
use aether_core::greenctx::{run_greenctx_exhausted_demo, run_greenctx_overcommit_demo, run_greenctx_unbound_demo};
use aether_core::greenctx::{run_greenctx_busy_demo, run_greenctx_exhausted_demo, run_greenctx_overcommit_demo, run_greenctx_unbound_demo};
use aether_drivers::{
run_firewall_demo, run_firewall_ident_pa_demo, run_set_sid_unbound_demo,
run_xqueue_sid_override_demo,
Expand Down Expand Up @@ -117,6 +119,7 @@ const LINE_FIREWALL_IDENT_PA: &str = "[redteam] attack=firewall-ident-pa result=
const LINE_GREENCTX_OVERCOMMIT: &str = "[redteam] attack=greenctx-overcommit result=refused";
const LINE_GREENCTX_UNBOUND: &str = "[redteam] attack=greenctx-unbound result=refused";
const LINE_GREENCTX_EXHAUSTED: &str = "[redteam] attack=greenctx-exhausted result=refused";
const LINE_GREENCTX_BUSY: &str = "[redteam] attack=greenctx-busy result=refused";
const LINE_CLASS: &str = "[redteam] fabric-class admit/refuse";
const LINE_ATOMIC: &str = "[redteam] ATOMIC_ADD accept/reject";
const LINE_TENSOR: &str = "[softsfi] tensor=refused";
Expand Down Expand Up @@ -158,6 +161,7 @@ struct RedTeamReport {
greenctx_overcommit: bool,
greenctx_unbound: bool,
greenctx_exhausted: bool,
greenctx_busy: bool,
class: bool,
atomic: bool,
tensor: bool,
Expand Down Expand Up @@ -197,6 +201,7 @@ impl RedTeamReport {
&& self.greenctx_overcommit
&& self.greenctx_unbound
&& self.greenctx_exhausted
&& self.greenctx_busy
&& self.class
&& self.atomic
&& self.tensor
Expand Down Expand Up @@ -234,6 +239,7 @@ fn run_redteam() -> RedTeamReport {
let greenctx_over = run_greenctx_overcommit_demo();
let greenctx_unbound = run_greenctx_unbound_demo();
let greenctx_exhausted = run_greenctx_exhausted_demo();
let greenctx_busy = run_greenctx_busy_demo();
let sfi = run_softsfi_demo();
let noi = run_softnoi_demo();
let sva = run_sva_demo();
Expand Down Expand Up @@ -324,6 +330,9 @@ fn run_redteam() -> RedTeamReport {
// SoftGreenPool::create past MAX_GREEN_CTX slots → Exhausted.
// Not greenctx-overcommit SM/WQ; not SoftNoI Exhausted; not HW MIG.
greenctx_exhausted: greenctx_exhausted.all_ok(),
// SoftGreenPool::migrate_to_yield dest bound elsewhere → Busy.
// Not greenctx-unbound; not overcommit/exhausted; not xqueue Soft-CP Busy; not HW MIG.
greenctx_busy: greenctx_busy.all_ok(),
// Fabric-class tag: Gradient admits; second Curl refuses (ring).
class: noi.class_grad_admit && noi.class_curl_refuse,
// SID-proved toy fetch-add: in-bounds accept, foreign span Oob.
Expand Down Expand Up @@ -388,6 +397,7 @@ fn print_clip(r: &RedTeamReport) {
emit(r.greenctx_overcommit, LINE_GREENCTX_OVERCOMMIT);
emit(r.greenctx_unbound, LINE_GREENCTX_UNBOUND);
emit(r.greenctx_exhausted, LINE_GREENCTX_EXHAUSTED);
emit(r.greenctx_busy, LINE_GREENCTX_BUSY);
emit_tagged(r.class, LINE_CLASS);
emit_tagged(r.atomic, LINE_ATOMIC);
emit_tagged(r.tensor, LINE_TENSOR);
Expand Down Expand Up @@ -486,6 +496,10 @@ mod tests {
r.greenctx_exhausted,
"SoftGreenPool::create past MAX_GREEN_CTX → Exhausted"
);
assert!(
r.greenctx_busy,
"SoftGreenPool::migrate_to_yield dest bound elsewhere → Busy"
);
assert!(r.class, "fabric-class Gradient admit / Curl refuse");
assert!(r.atomic, "ATOMIC_ADD accept/reject");
assert!(r.tensor, "SoftSFI tensor named refuse");
Expand Down Expand Up @@ -565,6 +579,10 @@ mod tests {
LINE_GREENCTX_EXHAUSTED,
"[redteam] attack=greenctx-exhausted result=refused"
);
assert_eq!(
LINE_GREENCTX_BUSY,
"[redteam] attack=greenctx-busy result=refused"
);
assert_eq!(LINE_CLASS, "[redteam] fabric-class admit/refuse");
assert_eq!(LINE_ATOMIC, "[redteam] ATOMIC_ADD accept/reject");
assert_eq!(LINE_TENSOR, "[softsfi] tensor=refused");
Expand Down Expand Up @@ -597,6 +615,7 @@ mod tests {
LINE_GREENCTX_OVERCOMMIT,
LINE_GREENCTX_UNBOUND,
LINE_GREENCTX_EXHAUSTED,
LINE_GREENCTX_BUSY,
] {
assert!(
line.starts_with("[redteam] attack=") && line.ends_with(" result=refused"),
Expand Down
Loading