sim/runtime/glasses/proofs/
co_use.rs1use sim_kernel::{Error, Expr, Result, Symbol};
2use sim_lib_intent::{Origin, intent};
3use sim_lib_view::SurfaceCaps;
4use sim_lib_view_device::{ConsentReceipt, DeviceCapability, EdgeId};
5use sim_lib_web_bridge::GlassesCoUseSession;
6use sim_value::{access, build};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct CoUseProof {
11 pub peers: usize,
13 pub broadcasts: usize,
15 pub ledger_rows: usize,
17 pub viture_panel_acked: bool,
19}
20
21impl CoUseProof {
22 pub fn to_expr(&self) -> Expr {
24 build::map(vec![
25 ("kind", build::qsym("glasses/sdk", "co-use-proof")),
26 ("peers", build::uint(self.peers as u64)),
27 ("broadcasts", build::uint(self.broadcasts as u64)),
28 ("ledger-rows", build::uint(self.ledger_rows as u64)),
29 ("viture-panel-acked", Expr::Bool(self.viture_panel_acked)),
30 ])
31 }
32}
33
34pub fn prove_co_use() -> Result<CoUseProof> {
36 let edge = EdgeId::named("sdk-glasses-co-use");
37 let receipt = ConsentReceipt::new(
38 vec![
39 DeviceCapability::Pose.grant_symbol(),
40 DeviceCapability::Mic.grant_symbol(),
41 ],
42 60_000,
43 Vec::new(),
44 edge.clone(),
45 7,
46 );
47 let mut session =
48 GlassesCoUseSession::new(edge, receipt, build::keyword("workspace"), workspace())?;
49 session.attach_viture(
50 SurfaceCaps::from_preset("glasses-luma-ultra", "sdk.co-use.viture")
51 .ok_or_else(|| Error::HostError("Viture surface preset missing".to_owned()))?,
52 )?;
53 session.attach_halo(
54 SurfaceCaps::from_preset("glasses-hud", "sdk.co-use.halo")
55 .ok_or_else(|| Error::HostError("Halo surface preset missing".to_owned()))?,
56 )?;
57 let tap = intent(
58 "invoke",
59 Origin::human(8),
60 vec![
61 ("target", build::sym("workspace")),
62 (
63 "op",
64 Expr::Symbol(Symbol::qualified("glasses/input", "double-tap")),
65 ),
66 ("args", build::list(Vec::new())),
67 ],
68 );
69 let broadcasts =
70 session.acknowledge_review_from_halo(&tap, Symbol::qualified("bridge", "packet-review"))?;
71 let review = access::field(session.workspace()?, "review");
72
73 Ok(CoUseProof {
74 peers: session.live_bindings().len(),
75 broadcasts: broadcasts.len(),
76 ledger_rows: session.ledger().len(),
77 viture_panel_acked: review
78 .and_then(|review| access::field_sym(review, "status"))
79 .is_some_and(|status| status.name.as_ref() == "acked"),
80 })
81}
82
83fn workspace() -> Expr {
84 build::map(vec![
85 ("title", build::text("Bridge review")),
86 (
87 "review",
88 build::map(vec![
89 (
90 "mission",
91 Expr::Symbol(Symbol::qualified("bridge", "packet-review")),
92 ),
93 ("status", build::sym("pending")),
94 ]),
95 ),
96 ])
97}