You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bridge: scan() — barcode / QR scanning for Console fields #146
Add the bridge method scan(opts?: { formats?: string[] }): Promise<string | null>, announced as capability scan.
It opens a native full-screen scanner (expo-camera) with torch and cancel controls, and resolves the decoded text, or null on cancel.
Add the camera permission strings to app.config.ts, localized in en / zh / ar.
Follow the steps in docs/HYBRID-SHELL.md (Adding a method): add to BRIDGE_METHODS, the handler with argument validation, the bootstrap wrapper, and the docs.
Acceptance
Unit tests cover the handler (formats validation, cancel → null, permission denied → failed) and the bootstrap wrapper.
Manual device check.
Follow-up: after acceptance, the seat files the Console consumer card in objectstack-ai/objectstack (a scan affordance on text/lookup fields when has('scan')).
First touch, gate released. This card moves to pm:blocked on #156, type enhancement.
Per the gate's table, scan() reuses the scanner screen that #156 builds. Building it here first would invert that order and make the two cards collide on the same new screen and on app.config.ts.
Blocked-by: objectstack-ai/mobile#156 (the body's #144 line is already satisfied: #144 merged).
Claim: PM loop round 1
Session: session_01QSeKYnW1Xf6HDSWz1eGAqv
Account: os-justin
Branch: claude/issue-146-bridge-scan
Worktree: mobile-issue-146
Domain: n/a — single-lane repo (repo:mobile)
Seat: repo:mobile#1
File surface: lib/shell/bridge/**, components/shell/QrScanner.tsx (reuse only; extend props if formats needs it), a new scan route under app/, components/shell/ConsoleWebView.tsx (only if the call/answer plumbing requires it), locales/*.json, __tests__/**, docs/HYBRID-SHELL.md, .changeset/146-bridge-scan.md (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: default tier (opus) — dispatch-gates --tier --repo objectstack-ai/mobile: no path-derived mandate, effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6576936446
Premise: holds. main at 728b3c5 has components/shell/QrScanner.tsx and app/connect-scan.tsx. BRIDGE_METHODS (lib/shell/bridge/protocol.ts:56-62) has no scan. The handler admits calls only from the configured server origin (lib/shell/bridge/handler.ts:50-56).
Serial constraints cleared:
{
"issue": 146,
"status": "done",
"branch": "claude/issue-146-bridge-scan",
"pr": "https://github.com/objectstack-ai/mobile/pull/170",
"session": "session_01QSeKYnW1Xf6HDSWz1eGAqv",
"premise_still_valid": true,
"summary": "Added bridge method scan(opts?: {formats?: string[]}): Promise of string or null, capability 'scan', via BRIDGE_METHODS, a handler with strict argument validation (bad_args for empty/unknown/non-string formats, non-object opts, extra keys), a bootstrap wrapper and a new docs section. It reuses #156's QrScanner with three optional props (barcodeTypes, permissionText, onPermissionStatus) through a new route app/bridge-scan.tsx plus lib/shell/bridge/scan-session.ts. Every exit settles the call: text, null on cancel, failed 'Camera permission denied', and a second scan() refused as failed 'A scan is already open' (the first is left alone). Bridge answers are now scoped to the calling document (per-document call ids; native drop on a replaced WebView). Seat follow-up: origin/main merged (13d5b01 + aef6993); the new keys are in all ten bundles; QrScanner's roots carry useLayoutDirection (RTL across react-native-screens NOT MEASURED, pattern applied); app/connect-scan.tsx is untouched.",
"tests": "head f856d04. npx jest --ci --coverage: exit 0, Test Suites 33/33, Tests 519/519. Cold: npx jest --ci --no-cache --maxWorkers=2 QrScanner.test.tsx ConsoleWebView.test.tsx: exit 0, Tests 56/56. Ablations via scripts/ablation-replace.mjs (mutation landed on disk, blob restored == HEAD, git diff HEAD empty; no build leg, since babel-jest reads src): (1) ConsoleWebView guard removed: 2 failed/25 passed (both drop tests); (2) bootstrap id back to c+seq: 2 failed/26 passed (doc-token id + stale-document tests); (3) QrScanner camera-root direction removed: 2 failed/27 passed (RTL tests).",
"gates": "head f856d04, all under os-verify-lock, exit captured before any pipe: npx tsc --noEmit exit 0; npx eslint . --ext .ts,.tsx exit 0 (0 warnings); npx jest --ci --coverage exit 0; jest cold variant exit 0. Locale key parity across ten bundles: parity (scripted). Control-byte scan of changed files: no hits. PR #170 check-runs at report time: Code Quality in_progress, Lint & Type Check in_progress. dispatch-gates --commands not run: objectstack-only tool, and this diff is in objectstack-ai/mobile.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/mobile/pulls, draft, no labels, no assignees; run 41451916338 success, body 8148/8148 bytes identical) and this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/mobile/issues/146/comments)",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [],
"deviations": [
"app/console.tsx: one capability line plus an import, outside the claimed surface. It is the real producer of BridgeDeps capabilities (ConsoleWebView passes them through).",
"components/shell/ConsoleWebView.tsx: touched for the answer plumbing (document counter in onMessage/remount/onDocumentStart), as the dispatch allowed when required.",
"locales: seven bundles beyond en/zh/ar, because #169 landed first (seat note); permissions.camera text reworded in all ten to name both camera uses; plugin config untouched.",
"Changeset level patch (Metadata-protocol none; precedent 163-install-id-token-rotation.md)."
],
"files_changed": ".changeset/146-bridge-scan.md, __tests__/components/ConsoleWebView.test.tsx, __tests__/components/QrScanner.test.tsx, __tests__/lib/shell/bridge-handler.test.ts, __tests__/lib/shell/bridge-protocol.test.ts, __tests__/lib/shell/bridge-scripts.test.ts, __tests__/lib/shell/scan-session.test.ts, app/bridge-scan.tsx, app/console.tsx, components/shell/ConsoleWebView.tsx, components/shell/QrScanner.tsx, docs/HYBRID-SHELL.md, lib/shell/bridge/handler.ts, lib/shell/bridge/protocol.ts, lib/shell/bridge/scan-session.ts, lib/shell/bridge/scripts.ts, locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.json",
"device_check": "NOT VERIFIED — listed for the maintainer under 需要你做的"
}
ACCEPT → PR #170 (head f5f3225, after patch round 1). Ready for review; the maintainer is requested. The maintainer merges. The Console consumer card for scan() is filed after the merge.
Activity
objectstack-fleet commentedon Nov 2, 2026
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv
First touch, gate released. This card moves to
pm:blockedon #156, typeenhancement.Per the gate's table,
scan()reuses the scanner screen that #156 builds. Building it here first would invert that order and make the two cards collide on the same new screen and onapp.config.ts.Blocked-by: objectstack-ai/mobile#156(the body's#144line is already satisfied: #144 merged).objectstack-fleet commentedon Nov 2, 2026
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv
Unblocked:
Blocked-by#156 merged as728b3c5.Claim: PM loop round 1
Session:
session_01QSeKYnW1Xf6HDSWz1eGAqvAccount:
os-justinBranch:
claude/issue-146-bridge-scanWorktree:
mobile-issue-146Domain:
n/a — single-lane repo (repo:mobile)Seat:
repo:mobile#1File surface:
lib/shell/bridge/**,components/shell/QrScanner.tsx(reuse only; extend props ifformatsneeds it), a new scan route underapp/,components/shell/ConsoleWebView.tsx(only if the call/answer plumbing requires it),locales/*.json,__tests__/**,docs/HYBRID-SHELL.md,.changeset/146-bridge-scan.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default tier (opus) — dispatch-gates --tier --repo objectstack-ai/mobile: no path-derived mandate,effort: highClause-②: no
Metadata-protocol: none
Responsibility:
n/a — not a defect cardThread-read: 6576936446
Premise: holds.
mainat728b3c5hascomponents/shell/QrScanner.tsxandapp/connect-scan.tsx.BRIDGE_METHODS(lib/shell/bridge/protocol.ts:56-62) has noscan. The handler admits calls only from the configured server origin (lib/shell/bridge/handler.ts:50-56).Serial constraints cleared:
readyandrouteChangedsignals, and settle who pads the safe area #162) awaits the maintainer and touchesConsoleWebView.tsxanddocs/HYBRID-SHELL.md. Ordinary concurrency; the PR that lands second reconciles.objectstack-fleet commentedon Nov 2, 2026
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv
os-dev-report
{ "issue": 146, "status": "done", "branch": "claude/issue-146-bridge-scan", "pr": "https://github.com/objectstack-ai/mobile/pull/170", "session": "session_01QSeKYnW1Xf6HDSWz1eGAqv", "premise_still_valid": true, "summary": "Added bridge method scan(opts?: {formats?: string[]}): Promise of string or null, capability 'scan', via BRIDGE_METHODS, a handler with strict argument validation (bad_args for empty/unknown/non-string formats, non-object opts, extra keys), a bootstrap wrapper and a new docs section. It reuses #156's QrScanner with three optional props (barcodeTypes, permissionText, onPermissionStatus) through a new route app/bridge-scan.tsx plus lib/shell/bridge/scan-session.ts. Every exit settles the call: text, null on cancel, failed 'Camera permission denied', and a second scan() refused as failed 'A scan is already open' (the first is left alone). Bridge answers are now scoped to the calling document (per-document call ids; native drop on a replaced WebView). Seat follow-up: origin/main merged (13d5b01 + aef6993); the new keys are in all ten bundles; QrScanner's roots carry useLayoutDirection (RTL across react-native-screens NOT MEASURED, pattern applied); app/connect-scan.tsx is untouched.", "tests": "head f856d04. npx jest --ci --coverage: exit 0, Test Suites 33/33, Tests 519/519. Cold: npx jest --ci --no-cache --maxWorkers=2 QrScanner.test.tsx ConsoleWebView.test.tsx: exit 0, Tests 56/56. Ablations via scripts/ablation-replace.mjs (mutation landed on disk, blob restored == HEAD, git diff HEAD empty; no build leg, since babel-jest reads src): (1) ConsoleWebView guard removed: 2 failed/25 passed (both drop tests); (2) bootstrap id back to c+seq: 2 failed/26 passed (doc-token id + stale-document tests); (3) QrScanner camera-root direction removed: 2 failed/27 passed (RTL tests).", "gates": "head f856d04, all under os-verify-lock, exit captured before any pipe: npx tsc --noEmit exit 0; npx eslint . --ext .ts,.tsx exit 0 (0 warnings); npx jest --ci --coverage exit 0; jest cold variant exit 0. Locale key parity across ten bundles: parity (scripted). Control-byte scan of changed files: no hits. PR #170 check-runs at report time: Code Quality in_progress, Lint & Type Check in_progress. dispatch-gates --commands not run: objectstack-only tool, and this diff is in objectstack-ai/mobile.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/mobile/pulls, draft, no labels, no assignees; run 41451916338 success, body 8148/8148 bytes identical) and this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/mobile/issues/146/comments)", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [], "deviations": [ "app/console.tsx: one capability line plus an import, outside the claimed surface. It is the real producer of BridgeDeps capabilities (ConsoleWebView passes them through).", "components/shell/ConsoleWebView.tsx: touched for the answer plumbing (document counter in onMessage/remount/onDocumentStart), as the dispatch allowed when required.", "locales: seven bundles beyond en/zh/ar, because #169 landed first (seat note); permissions.camera text reworded in all ten to name both camera uses; plugin config untouched.", "Changeset level patch (Metadata-protocol none; precedent 163-install-id-token-rotation.md)." ], "files_changed": ".changeset/146-bridge-scan.md, __tests__/components/ConsoleWebView.test.tsx, __tests__/components/QrScanner.test.tsx, __tests__/lib/shell/bridge-handler.test.ts, __tests__/lib/shell/bridge-protocol.test.ts, __tests__/lib/shell/bridge-scripts.test.ts, __tests__/lib/shell/scan-session.test.ts, app/bridge-scan.tsx, app/console.tsx, components/shell/ConsoleWebView.tsx, components/shell/QrScanner.tsx, docs/HYBRID-SHELL.md, lib/shell/bridge/handler.ts, lib/shell/bridge/protocol.ts, lib/shell/bridge/scan-session.ts, lib/shell/bridge/scripts.ts, locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.json", "device_check": "NOT VERIFIED — listed for the maintainer under 需要你做的" }objectstack-fleet commentedon Nov 2, 2026
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv
ACCEPT → PR #170 (head
f5f3225, after patch round 1). Ready for review; the maintainer is requested. The maintainer merges. The Console consumer card forscan()is filed after the merge.objectstack-fleet commentedon Nov 2, 2026
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv
Landed. #170 merged as
92a0a26, merged byos-zhuang, from headf5f3225(CI green). The card closedcompletedviaFixes #146.pm:dispatchedremoved.scan()objectstack#29378.readyandrouteChangedsignals, and settle who pads the safe area #162) reconciles with this change inConsoleWebView.tsxin its merge round, which is dispatched.