Skip to content

feat(iot): integrate Scanner Inbox, inbound Create plan, shift-close, labels, Guard Desk#328

Merged
mohabbis merged 15 commits into
masterfrom
cursor/iot-working-integrate-e1a6
Jul 18, 2026
Merged

feat(iot): integrate Scanner Inbox, inbound Create plan, shift-close, labels, Guard Desk#328
mohabbis merged 15 commits into
masterfrom
cursor/iot-working-integrate-e1a6

Conversation

@mohabbis

@mohabbis mohabbis commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

Single integration branch that stacks the IoT feature work into working software on top of master (design docs already merged via #321):

  1. Build fix — disable tokenizers esaxx_fast so --features experimental compiles on Linux (fix(build): unbreak experimental feature compile (esaxx-rs) #326)
  2. F1 — Scanner Inbox Zone preset + ready-to-file signal → Scan & Preview only (feat(organizer): Scanner Inbox preset + ready-to-file signal (F1) #323)
  3. F2 — inbound intent list + fabric_convert_inbound_intent → read-only plan / Converted; /inbound/webhook alias (feat(inbound): batch-landed intents → Create plan (F2) #327)
  4. F3pos.close taxonomy, samples, shift-close UI copy; no POS key injection (feat(inbound): pos.close shift-close intent packet (F3) #324)
  5. F4 — post-run folder label preview/export + audit sidecar notes; no printer SDK (feat(organizer): folder label preview/export after run (F4) #325)
  6. F5 — Guard Desk on-demand chosen-file OCR copy + DOM contract (feat(guard-desk): on-demand chosen-file OCR copy (F5) #322)
  7. macOS CI — Enigo init timeout is Windows-only (Enigo is !Send on Darwin)

Supersedes closed individual PRs #322#327 and #326 — merge this PR.

Trust invariants preserved: devices/webhooks propose only; Create plan never executes; no camera/mic; Guard Desk stays prototype-labeled.

Validation (this branch)

  • cargo fmt --check
  • cargo check --all-targets
  • cargo check --all-targets --features experimental
  • cargo clippy --all-targets (+ experimental) -- -D warnings
  • cargo test --features experimental --lib convert
  • cargo test --lib folder_label
  • cargo test --test frontend_dom_contract
  • ghost mcp demo smoke (plan path)

Test plan

  • CI green (esp. macOS Tauri smoke after Enigo fix)
  • Organizer: Scanner Inbox preset → drop files → banner → Scan & Preview → Approve
  • Experimental: MCP HTTP → POST /inbound/webhook → Create plan → Approve separately
  • POST pos.close sample → shift-close card
  • After organize: Preview folder label → export txt
  • Guard Desk: choose file → Run review (no camera prompt)
Open in Web Open in Cursor 

cursoragent and others added 14 commits July 18, 2026 21:12
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
tokenizers' default esaxx_fast feature compiles esaxx-rs via clang/c++,
which fails on Linux VMs where /usr/bin/c++ is clang selecting GCC 14
without libstdc++-14-dev (`cstdint` not found). Keep progressbar+onig
only — local_llm only needs load/encode. Document the VM workaround.

Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ghost Ready Ready Preview, Comment Jul 18, 2026 9:51pm

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Stacked integration of #326 + F1–F5. Individual feature PRs (#322#327, #326) are superseded by this branch — merge this one when CI is green.

Validated locally: fmt, check, experimental check/clippy, convert + folder_label + frontend_dom_contract tests.

macOS Enigo holds CGEventSource (!Send), so the timeout thread that
fixed Windows CI hangs fails to compile on Darwin Tauri smoke builds.

Co-authored-by: Muhammad Rafiq <mohabbis@users.noreply.github.com>
@mohabbis
mohabbis merged commit 8dae8ae into master Jul 18, 2026
21 of 23 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0bb5af073

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main.js
const intent = intentId ? pendingById.get(intentId) : null;
if (!intent) return;
const card = organizerInboundIntentCopy(intent);
if (!intent.zone_id) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify inbound zones before creating plans

When the webhook payload is CloudEvents/Fabric item, parse_inbound_body stores the event subject as zone_id (the checked-in sample uses lakehouses/lh-001), but this new truthiness check treats any non-empty value as a real Organizer Zone and calls fabric_convert_inbound_intent. In that common case the primary “Create plan” path just fails with no zone with id ... and the UI never offers the Zone-selection flow; validate that the zone exists (or only set zone_id for Ghost-native payloads) before taking this branch.

Useful? React with 👍 / 👎.

.map_err(|e| e.to_string())?
.ok_or_else(|| format!("no zone with id {zone_id}"))?;
let rules = list_folder_rules(&conn, &zone_id).map_err(|e| e.to_string())?;
let ready_files = crate::organizer::planner::scan_zone_files(&conn, &zone_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Count only Scanner Inbox source files

For Scanner Inbox two-folder zones, the inbox rule is the readable/non-create source while the destination rule is also readable so planning can inspect conflicts. scan_zone_files scans every can_read rule, so after filing, files already in the destination are counted as ready_files and the banner keeps prompting “Scan & Preview” even when the inbox is empty; count only the source/inbox rule set for this signal.

Useful? React with 👍 / 👎.

Comment thread src/main.js
Comment on lines +4025 to +4027
const presetName =
presetChoice ||
(await ghostPick(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore click events when opening guided setup

The existing toolbar wiring still passes organizerRunWizard directly to addEventListener, so clicking the normal “Guided setup” button supplies the click Event as presetChoice. Because that object is truthy, this branch skips the preset picker and looks up ORGANIZER_PRESETS[event], immediately showing “Unknown Organizer preset” instead of opening setup; wrap the handler or accept only string preset names.

Useful? React with 👍 / 👎.

Comment on lines +183 to +184
reset_store_for_tests();
let intent = record_intent(Some("zone-1".into()), "pos.close", "Shift closed");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Isolate inbound intent tests from shared store

These new inbound tests share the process-global STORE and the same fabric-inbound-intents.json file with each other and the command-layer conversion test, while Rust runs tests in parallel by default. One test can call reset_store_for_tests() between another test's record_intent and convert_intent/list_pending, producing intermittent empty queues or unknown-intent failures; serialize these tests or give each test an isolated store path.

Useful? React with 👍 / 👎.

"hash": stored.hash,
"prev_hash": stored.prev_hash,
"audit": stored.audit.masked(),
"label_notes": stored.label_notes,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mask label notes in audit exports

When users export an audit after using the new label flow, these sidecar notes are written raw even though the JSON export masks the audit log itself. The note detail can include the generated label filename, which is derived from the Zone name, so a client/email-like Zone name leaks into the portable JSON/CSV/signed reports despite the existing PII-redaction contract; mask or sanitize stored.label_notes before exporting them.

Useful? React with 👍 / 👎.

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.

2 participants