Skip to content

glance: contained apps publish with the glance capability, not by being os.* - #86

Merged
ymote merged 1 commit into
mainfrom
feat/glance-capability
Sep 28, 2026
Merged

ymote merged 1 commit into
mainfrom
feat/glance-capability

Conversation

@ymote

@ymote ymote commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #72. Rebuilt on main bb2b219 after #70, which pins App Hub e8601b80 (with glance in KNOWN_CAPABILITIES) and Rinx 68afcf79. This PR changes no pin (Rinx, App Hub, octos, makepad): the earlier App Hub move to 59cc35eb and its README pin edits are gone. The only file changed is crates/shell/src/glance.rs.

What

  • crates/shell/src/glance.rs: the os.* stopgap is gone. It is replaced by a capability check:
    • Caller::Contained { app, granted } records whether the caller holds glance. publish, withdraw and list all refuse a contained caller without it, with the error "<app> was not granted the glance capability". list now returns a Result.
    • Where the grant comes from: the Card runner's isolate gate (makepad splash_policy::service_allowed) lets glance.* out of an app's isolate only when the app's resolved policy grants glance. So a call GlanceService receives from the app itself holds the grant. A call from a host sheet runs under no app policy, so it has granted: false and is refused.
    • System apps get no exemption. They run under their own manifest's policy like any store app (App Hub's system::prepare resolves them through the same KNOWN_CAPABILITIES). A system app that publishes must request glance, the same way Mail requests mail and AI providers requests llm. Native modules (the shell's own code) are unchanged.
    • The shell's limits are unchanged: L0 only, size caps, rate limit, per-app card cap, dedupe and expiry.
  • Tests:
    • a_contained_app_needs_the_glance_capability_whoever_it_is: a granted store app publishes. Without the grant, publish, list and withdraw are all refused, for os.* apps too. Native callers still publish.
    • the_runner_gate_admits_glance_only_with_the_capability: the makepad gate refuses glance.* without glance, allows all three methods with it, and glance grants nothing else.
    • The dispatch test now checks that a sheet-originated glance.publish is refused. It previously checked that a non-os.* app was refused.
  • News manifest unchanged: the News bundle does not call glance.*. The demo digest (OCTOSENSE_GLANCE_DEMO) is published by the shell as a granted os.news. When News publishes from its bundle, it adds glance to apps/news/bundle/manifest.json.

Checked against the real App Hub grant (e8601b80)

A scratch crate on octosense-app-policy at e8601b80 confirmed: KNOWN_CAPABILITIES has glance; a system manifest (os.news, HostLimits::system()) that declares glance resolves with allows("glance"); a system app that does not declare it does not get it; a store app declaring it resolves with it.

Conflict with #87

#87 (sys.digest) also edits glance.rs: the old Caller::Contained(String) type and the os.* gate. Whichever of #86 and #87 merges second rebases onto the other.

Verification (local, macOS)

  • python3 tools/setup.py --check --cargo: pass (.sources are hub worktrees at main's pins)
  • cargo check --locked -p octosense, with and without --features mobile-apps: pass
  • bash tools/check-shell-graph.sh -p octosense: pass
  • from phone/: cargo check --locked -p octosense-home --features mobile-apps: pass
  • from phone/: bash ../tools/check-shell-graph.sh -p octosense-home: pass
  • from phone/: cargo test --locked -p octosense-app-policy --no-run: pass, not ambiguous (one App Hub now that Rinx and the shell agree)
  • cargo test --locked -p octosense-shell glance: 12 passed. With --features app-hub: 13 passed, including the Card runner dispatch test.
  • Not run on a device.

🤖 Generated with Claude Code

…ng os.*

main pins App Hub e8601b80, whose KNOWN_CAPABILITIES has `glance`, so
replace the stopgap that admitted only system apps.

A contained caller now carries whether it holds the grant, and publish,
withdraw and list refuse one without it. The Card runner's isolate gate lets
glance.* out of an app only when the app's resolved policy grants glance, so
a call from the app itself holds it; a call from a host sheet (no app policy)
does not. System apps get no exemption: they run under their own manifest,
so one that publishes requests glance like any store app. The shell's
limits (L0, size caps, rate limit, per-app cap, dedupe, expiry) are
unchanged. News does not publish cards from its bundle yet, so its manifest
is unchanged. No pin changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ymote
ymote force-pushed the feat/glance-capability branch from c5337de to e9a4fbb Compare September 28, 2026 08:55
@ymote
ymote marked this pull request as ready for review September 28, 2026 09:27
@ymote
ymote merged commit 122e857 into main Sep 28, 2026
4 checks passed
ymote added a commit that referenced this pull request Sep 29, 2026
… [skip ci]

- approvals/contacts.rs: ContactsSource (is_known for email addresses and
  Matrix IDs), ContactList/NoContacts test doubles, MailContacts reading
  Mail's host service data, and ContactsGate: off by default, on only by
  the person's Settings tap ("Use my contacts in approval rules"), kept
  owner-only in approvals/contacts.json. The router evaluates "recipients
  in contacts" through the gate.
- mail host service: contacts::known_addresses (own accounts, recorded
  send recipients, To/Cc of sent folders; never the secret store); the
  decoder keeps To/Cc; a removed account forgets its recipients.
- docs/ai-services(.zh-CN).md refreshed against main (#106, #113, #117,
  #118, #120, #124, #95, #86), linking architecture.md; architecture's
  contacts lines updated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant