[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M699NJD5P0XERYRXNYJFS3YG":3,"skill-same:01M699NJD5P0XERYRXNYJFS3YG":88},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":51,"linkOnly":52,"markdownContent":53,"markdownBody":54,"frontMatter":55,"refName":59,"commitSha":60,"skillDirectory":61,"forksCount":62,"repositoryHtmlUrl":63,"repositoryHomepageUrl":64,"ownerHtmlUrl":65,"ownerBlogUrl":66,"ownerDescription":67,"updatedAt":68,"install":69,"resources":81},"01M699NJD5P0XERYRXNYJFS3YG","debug-app",null,"Diagnose Power Apps mobile install\u002Fstartup failures, npm run dev errors, missing package entry points, or QR\u002Fdevice-opening problems even before an app is loaded. Inspect locally first; restore locked dependencies or restart Metro only with explicit approval, never upgrade packages or patch host\u002FMSAL source. For a running native app, monitor sanitized project-local Metro logs and diagnose runtime errors or silent failures such as empty lists and blank screens. Supports startup-only diagnosis, symptoms, port\u002Fplatform filters, bounded monitoring, and non-mutating --no-fix mode. Verify the original symptom, not merely installation or quiet logs.","microsoft\u002Fpower-platform-skills","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M699JVYJFB75D9JM70BN4H0Q",1149,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fmobile-apps\u002Fskills\u002Fdebug-app\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,9,50],"debug app","debug","app","power","mode","inspect","qr","port","apps","diagnosis","host","project","local","upgrade","MCP","fix","monitoring","logs","search","run","power apps","docs","2026-11-10 10:12:30",false,"---\nname: debug-app\ndescription: Diagnose Power Apps mobile install\u002Fstartup failures, npm run dev errors, missing package entry points, or QR\u002Fdevice-opening problems even before an app is loaded. Inspect locally first; restore locked dependencies or restart Metro only with explicit approval, never upgrade packages or patch host\u002FMSAL source. For a running native app, monitor sanitized project-local Metro logs and diagnose runtime errors or silent failures such as empty lists and blank screens. Supports startup-only diagnosis, symptoms, port\u002Fplatform filters, bounded monitoring, and non-mutating --no-fix mode. Verify the original symptom, not merely installation or quiet logs.\nuser-invocable: true\nallowed-tools: Read, Edit, Write, Grep, Glob, Bash, AskUserQuestion, WebFetch, mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search\nmodel: sonnet\n---\n\n> **Plugin check**: Run `node \"${PLUGIN_ROOT}\u002Fscripts\u002Fcheck-version.js\"` - if it outputs a message, show it to the user before proceeding.\n\n**? Shared instructions: [shared-instructions.md](${PLUGIN_ROOT}\u002Fshared\u002Fshared-instructions.md)** — read first.\n\nStartup diagnosis uses the targeted compatibility inspection below instead of\nthe shared blanket version check; missing dependencies must not prevent diagnosis.\nIt does not check for updates. Explicit startup repair\u002Frestart approval overrides\nshared auto-proceed\u002Fdefault-answer guidance.\n\n# Debug App — Monitor & Fix\n\nMonitor the running app through the project-local `.powernative\u002Fmetro-logs\u002F` files written by `metro.config.js`, detect runtime and bundle errors, and fix them autonomously by editing the affected files (or routing to the right skill when the fix belongs in a domain like Dataverse schema or auth registration). For silent failures, inject temporary `console.log` statements at data-path boundaries, read only newly appended log bytes, then clean the traces after the root cause is fixed. Modeled on the upstream `app-debugger.agent.md` pattern — foreground loop, bounded polling, configurable clean-check\u002Ftimeout exits, and optional watch-only operation.\n\nWhen setup\u002Fstartup or device opening is failing, first execute\n[startup-diagnostics.md](references\u002Fstartup-diagnostics.md). This bounded phase\ncan run without Metro logs or a loaded app and returns to the runtime path only\nwhen its prerequisites actually hold. Running `npm run dev` alone does not\nactivate an agent, and this skill installs no background watcher.\n\n> **Dev-client limitation:** the standalone dev client sends app\u002Fruntime logs, React errors, host diagnostics, and Metro bundler output through Metro. The template's `metro.config.js` writes Metro terminal output and HTTP bundle failures into `.powernative\u002Fmetro-logs\u002F`; there is no separate device log source. Host diagnostics include strings such as `[AuthProvider] MSAL init failed:`, `[bridge] fetch THREW for`, `[bridge] HTTP \u003Cstatus> for`, `[addAadAppToConnectionAcl] failed HTTP \u003Cstatus> for connection`, `[useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required`, and `[PAHost][ErrorBoundary] Unhandled JS error:`.\n\n## Subcommands (parsed from `$ARGUMENTS`)\n\n| Form | Behavior |\n|---|---|\n| `\u002Fdebug-app` (no args) | **Default — project-log-driven mode.** Run Phase 0, discover valid project-local Metro sessions, select automatically when one is live or ask when several are live, then monitor the selected log. No host terminal ID is required. |\n| `\u002Fdebug-app \"\u003Csymptom text>\"` | **Symptom-driven mode** (recommended when there's a user-visible problem). Free-text symptom such as `\"todos not appearing on home screen\"`, `\"login button does nothing\"`, `\"list empty after refresh\"`. Run Phase 0 → Phase 0.5 (parse symptom → ask the user to reproduce\u002Fnavigate → walk the likely data path from terminal traces) → enter monitor loop. Catches silent failures (empty lists, blank screens, swallowed errors) that pure log polling misses. |\n| `\u002Fdebug-app startup [\"\u003Csymptom text>\"] [--tunnel] [--tunnel-tenant \u003Ctenant-guid>]` | **Startup-only diagnosis.** Inspect install\u002Fstartup\u002FQR failures, offer bounded approved repair, and verify the original symptom. Preserve explicitly selected authenticated tunnel options for an approved retry. Return without the runtime monitor; also used by creation-time failure handoffs. |\n| `\u002Fdebug-app status` | Discover all project-local Metro logs and print each valid session's project, platform, PID, port, start time, and log path. Mark the session referenced by the saved cursor when present, then print fixes and unresolved errors. Do NOT ask for a selection or enter the loop. |\n| `\u002Fdebug-app stop` | Stop only the foreground debug loop and preserve `.powernative\u002Fdebug-app\u002F` state. It does not stop Metro; the user owns the `npm run dev` process. |\n| `\u002Fdebug-app version` | Print the installed `mobile-app` plugin name and version from `${PLUGIN_ROOT}\u002F.plugin\u002Fplugin.json`, then exit. |\n\n### Monitoring options\n\nOptions may follow the default command, a symptom, or `status`:\n\n| Option | Meaning | Default |\n|---|---|---|\n| `--working-dir \u003Cpath>` | App root containing `package.json`. Startup diagnosis accepts missing Metro config or dependencies; runtime monitoring requires a configured, live Metro session. Relative paths resolve from the current shell directory. | Current shell directory |\n| `--port \u003C1-65535>` | Monitor only the valid Metro session on this port. | Any port |\n| `--platform \u003Cios\\|android>` | Consider only sessions whose recent log identifies this platform. | Any platform |\n| `--cycles \u003C1-50>` | Exit after this many consecutive clean observation intervals. | `3` |\n| `--timeout \u003Cduration>` | Maximum wall-clock monitoring time. Accept `30s`–`60m` using `s`, `m`, or `h`. | `5m` |\n| `--no-fix` | Inspect\u002Fwatch-only: never edit project source\u002Fconfig, inject traces, install, regenerate, start\u002Fstop\u002Frestart Metro, open the device app, or invoke a mutating handoff. Debug cursor\u002Faudit\u002Fhealth state may still advance. | Fix enabled |\n| `--tunnel` | Startup only: preserve `--tunnel` when an approved retry invokes `npm run dev`. Never switch a LAN launch to a tunnel automatically. | Disabled |\n| `--tunnel-tenant \u003Ctenant-guid>` | Startup only: preserve the Entra tenant used to authenticate the dev tunnel. Requires `--tunnel`. | Active Azure CLI tenant |\n\nExamples:\n\n```text\n\u002Fdebug-app --port 8082 --platform ios\n\u002Fdebug-app \"orders screen is empty\" --cycles 10 --timeout 15m\n\u002Fdebug-app --no-fix --timeout 30m\n\u002Fdebug-app status --platform android\n\u002Fdebug-app status --working-dir ..\u002Fmy-mobile-app\n\u002Fdebug-app startup \"npm run dev exits before the QR appears\"\n\u002Fdebug-app startup \"tunnel launch fails\" --tunnel --tunnel-tenant 11111111-1111-1111-1111-111111111111\n\u002Fdebug-app \"QR won't open the app\" --no-fix\n```\n\n**Argument parsing:**\n\n1. Parse quoted text as one symptom value and parse recognized flags wherever they appear.\n2. The first reserved token (`startup`, `status`, `stop`, `help`, `--help`, `-h`, `version`, `--version`) selects the subcommand. `stop`, help, and version do not accept monitoring options. `status` accepts only `--working-dir`, `--port`, and `--platform`; reject symptoms, `--cycles`, `--timeout`, `--no-fix`, and tunnel options because it does not enter the loop. `startup` accepts one symptom and all options except `--cycles`, because it never enters the runtime monitor. Reject `--tunnel` and `--tunnel-tenant` on every other subcommand.\n3. After removing recognized options and their values, any remaining non-reserved text is the symptom and enables symptom mode.\n4. Reject unknown flags, duplicate flags, missing values, invalid numbers, unsupported platforms, or more than one free-text symptom. Print the valid forms and exit without monitoring.\n5. Normalize `platform` to lowercase. Convert `timeout` to `timeoutSeconds`; require `30 \u003C= timeoutSeconds \u003C= 3600`. Validate `--tunnel-tenant` as a GUID and require `--tunnel`; never derive either option from symptom text or untrusted diagnostic context. Resolve `workingDir` from explicit `--working-dir`, or inherit the caller's absolute root; use the current shell directory only for a direct invocation without either. Reject conflicting explicit\u002Finherited roots and do not search parent directories. Require `package.json` at that root; missing `metro.config.js`, configuration, or installed dependencies routes to startup inspection, not runtime monitoring. An unreadable\u002Fmalformed manifest is a blocked diagnostic, not permission to initialize a new app. Every shell call must explicitly enter the selected absolute `workingDir`; every relative project path and command below runs from that directory.\n6. Initialize:\n   ```text\n   workingDir=\u003Cabsolute app root>\n   portFilter=\u003Cnumber|none>\n   platformFilter=\u003Cios|android|none>\n   targetCleanCycles=\u003Cnumber, default 3>\n   timeoutSeconds=\u003Cnumber, default 300>\n   noFix=\u003Ctrue|false, default false>\n   devArgs=\u003C[]|[\"--tunnel\"]|[\"--tunnel\",\"--tunnel-tenant\",\"\u003Ctenant-guid>\"]>\n   monitorStartedAt=\u003Ccurrent ISO timestamp>\n   ```\n\nFor `help` \u002F `--help` \u002F `-h`, print the subcommands and monitoring-options tables and exit.\n\nSet `startupStartedAt` only when entering startup diagnostics. Its timeout and\nattempt budget include caller-supplied prior attempts. After a verified live app\ncontinues into monitoring, reset `monitorStartedAt` for that separate bounded loop.\n\n**Early-return subcommands:**\n\n- `stop`: if received while this foreground loop owns the conversation, clean up any injected traces using Phase 0.5.5 and exit at the next safe boundary. For a standalone `stop` invocation, report that no loop is active. Never stop Metro or delete `.powernative\u002Fdebug-app\u002F` state.\n- `version` \u002F `--version`: read `${PLUGIN_ROOT}\u002F.plugin\u002Fplugin.json`, print `\u003Cname> \u003Cversion>`, and exit without resolving a project or writing state. If the manifest is missing or malformed, report that the plugin version is unavailable and exit.\n- `status`: validate `workingDir`, then execute only Phase 0.0 discovery through the status branch below. Do not run project preflight, create state files, ask for a session, initialize a baseline, or enter the monitor loop.\n\nIf `stop` arrives during startup diagnosis, cancel upcoming diagnostic\u002Frepair\nsteps and report any in-flight approved command accurately. Do not automatically\nkill an installation or Metro process, or claim a partly restored install is complete.\n\n**Tip — \"play around then debug\":** Metro persists recent app output in `.powernative\u002Fmetro-logs\u002F` even across chat\u002Feditor restarts. If something weird just happened, keep using the app normally, then run `\u002Fdebug-app` or `\u002Fdebug-app \"\u003Cwhat you saw>\"`. The first cycle reads the latest persisted log window; subsequent cycles read only bytes appended after the saved cursor.\n\n## Core Principles\n\n- **Foreground autonomous loop** — Once started, this skill owns the conversation until `targetCleanCycles` consecutive clean polls confirm the app is healthy, `timeoutSeconds` elapses, the user types `stop`, or the escalation rule trips. **Do not run other skills concurrently** — they'll queue behind the loop.\n- **Watch-only means no project mutation** — With `--no-fix`, do not edit project source\u002Fconfiguration, inject diagnostic logs, install packages, regenerate schemas, switch accounts, or invoke a mutating skill. Continue to advance `.powernative\u002Fdebug-app\u002F` cursor\u002Faudit\u002Fhealth state, classify errors, and provide the fix\u002Fhandoff that would have been used.\n- **Runtime monitoring requires a live app; startup diagnosis does not.** First\n  classify install\u002Fstartup\u002Fopening failures through the bounded startup reference.\n  Do not enter the runtime monitor or claim healthy runtime without a verified\n  live native session.\n- **Native-only runtime target** — The app must be loaded in a native dev client on a device or simulator; `.powernative\u002Fmetro-logs\u002F` is the authoritative log source for that native session.\n- **No web or direct Metro probes** — Do not use React Native Web, browser automation, `curl`, `fetch`, `WebFetch`, or any direct request to a Metro\u002Flocalhost endpoint for runtime diagnosis. Read only the `.powernative` log and source files.\n- **No screen-by-screen verification** — Do not crawl routes or validate every screen. In symptom mode, focus only on the user-reported workflow and the terminal\u002Fsource evidence needed to diagnose it.\n- **One fix at a time** — Fully resolve one issue (context → fix → type-check → reload → re-poll) before starting the next. No batching.\n- **Working-dir state** — Debug audit state lives in `.powernative\u002Fdebug-app\u002F`: `fixes.md`, `unresolved.md`, `injected-logs.md`, `health.json`, and `metro-cursor.json`. Metro logs live in the already-ignored `.powernative\u002Fmetro-logs\u002F`. Both survive chat\u002Feditor restarts without binding state to a specific agent host.\n- **Defense-in-depth redaction** — The Metro logger removes credential-like lines before writing `.powernative`, but `\u002Fdebug-app` must independently minimize and sanitize every value before persisting it to `.powernative\u002Fdebug-app\u002F`. Never copy raw response bodies, record objects, tokens, headers, trace payloads, or absolute home-directory paths into debugger state.\n- **The port is the log identity** — the dev-server port is the number the QR encodes, the device dials, and this skill verifies. Liveness is a socket probe (does the log's PID still hold that port?), never terminal scrollback. A `port-taken` status means the log belongs to a dead session and must not be diagnosed.\n- **Never fix history** — the log is a record of the past, so an error in it is not proof of a current problem. Errors found in the baseline window must pass the Phase 0.2.1 supersession check before any code is edited. Editing working code to chase an already-resolved error is a worse outcome than reporting nothing.\n- **First-party native packages are an immutable boundary** — a frame under `node_modules\u002F@microsoft\u002Fpower-apps-native-*` is evidence, not proof, of package ownership. First rule out broken installation, Node\u002Fnative compatibility, invalid app inputs, unsupported configuration, and misuse of the package's documented API. Once the evidence confirms a defect inside an installed `@microsoft\u002Fpower-apps-native-*` package, do not apply a customer-project workaround: do not edit `node_modules\u002F`, create a `patch-package` patch or postinstall rewrite, vendor or fork package source, redirect the package through Metro\u002FBabel\u002FTypeScript aliases, or replace its dependency with a git, tarball, or local fork. Record a sanitized package-defect report and route the user to `\u002Freport-issue`. Host\u002FMSAL source patches remain prohibited; approved same-lock installation restoration is not a source patch or upgrade.\n- **Host terminal APIs are optional only** — Never ask for or persist a terminal\n  ID. During runtime monitoring, available host output is only a convenience and\n  diagnosis still advances the authoritative `.powernative` cursor. Before a log\n  exists, the bounded startup phase may use the current failed command's sanitized\n  terminal output; it must not fabricate a cursor or treat that output as a live\n  runtime session.\n- **Context-first diagnosis** — Read `memory-bank.md` when present. Read `power.config.json` for environment, Dataverse, and connector context. Consult `native-app-plan.md` only when the failure concerns a planned screen, data model, connector, offline profile, or native capability; do not parse it for unrelated syntax\u002Fruntime errors.\n- **Reference resolution order** — For Dataverse\u002FPower Platform errors: read [skills\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md](${PLUGIN_ROOT}\u002Fskills\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md) first, inspect generated services\u002Fmodels and project context, then query `mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search` when behavior remains uncertain. For Expo\u002FExpo Router\u002FReact Native errors: inspect installed versions and project code first, then use targeted `WebFetch` against official `https:\u002F\u002Fdocs.expo.dev\u002F` documentation. Use package documentation next and general web search only as a last resort.\n\n## Workflow — Task List First\n\nBefore entering the monitor loop, write a task list and keep it up to date:\n\n```\n- [ ] Discover valid `.powernative` Metro sessions and select one when needed\n- [ ] If startup\u002Finstall\u002FQR failure or no live session: inspect and classify; repair only with approval; verify original symptom or return pending\u002Fblocked\n- [ ] Capture baseline log state from the selected session and save its byte cursor\n- [ ] (Symptom mode only) Phase 0.5: parse symptom → ask user to navigate → inject console.logs → read new log bytes → walk data path → clean up logs\n- [ ] Monitoring cycle 1: collect → classify → fix if needed\n- [ ] Monitoring cycle 2: collect → classify → fix if needed\n- [ ] Monitoring cycle 3: collect → classify → fix if needed\n   (add cycles as needed; after \u003CtargetCleanCycles> consecutive clean cycles, use the resolved\u002Fflagged\u002Fpending symptom outcome)\n- [ ] Fix: \u003Cerror summary> → \u003Cinline edit | skill route>  (one task per error found)\n```\n\nMark each cycle complete (clean OR fixed) before starting the next.\n\n---\n\n## Phase 0 — Startup Check\n\nBefore entering the loop:\n\n### 0.setup Startup\u002Fsetup diagnostic dispatch\n\nAfter the early-return subcommands, run\n[startup-diagnostics.md](references\u002Fstartup-diagnostics.md) when:\n\n- the subcommand is `startup`;\n- the supplied symptom concerns installation, `npm run dev`, Node\u002Fpackage\n  compatibility, startup before loading, or QR\u002Fdevice opening; or\n- Phase 0.0 finds no valid live session (not merely a mismatched port\u002Fplatform\n  filter when another session is live), or Phase 0.2 finds no connected client.\n\nFor a healthy live app with a runtime symptom, skip setup and use the existing\nruntime path. On `startup` or a creation handoff, return the structured startup\noutcome without entering the monitor. Otherwise a verified live app re-enters\nPhase 0.preflight, session discovery, and state initialization (0.1) before\nPhase 0.2; pending\u002Fblocked\u002Fcancelled returns without a green runtime result.\nRecord `startupOutcome` in invocation context so this return does not re-enter\nsetup just because the original symptom mentioned startup. If only installation\nor Metro startup is verified but no native app is connected, report runtime\nverification pending and return instead of repeatedly dispatching setup.\nNo unbounded redispatch: repeated setup failures consume the same attempt budget.\n\n### 0.preflight Read project context\n\nFollow the shared instructions before diagnosing logs:\n\nUse `workingDir` from argument parsing as `\u003Cworking_dir>` throughout this workflow. It is already validated as an app root; do not derive it again from a later phase or silently switch projects.\n\n1. If `\u003Cworking_dir>\u002Fmemory-bank.md` exists, read its Project facts, Power Platform context, Data model, Connectors, Screens, Native capabilities, and Build history. Do not create a memory bank from `\u002Fdebug-app`; absence is valid.\n2. Read `\u003Cworking_dir>\u002Fpower.config.json` when present. Capture `environmentId`, `databaseReferences`, and `connectionReferences`. `power.config.json` is the preferred environment source.\n3. Read `\u003Cworking_dir>\u002Fnative-app-plan.md` only when the supplied symptom or a classified error concerns a planned screen, Dataverse entity\u002Fcolumn, connector, offline behavior, navigation contract, or native capability. Treat the plan as intended design, not proof of live schema\u002Fruntime state.\n4. Inspect `src\u002Fgenerated\u002Fservices\u002F`, `src\u002Fgenerated\u002Fmodels\u002F`, and `src\u002Fgenerated\u002FconnectorSchemas.ts` only when the affected data path uses them. Never edit generated files.\n\nAppend a compact context line to `fixes.md` after Phase 0.1 creates it:\n\n```text\n[\u003CHH:MM:SS>] Context — memory-bank=\u003Cpresent|absent> native-plan=\u003Cpresent|absent|not-needed> environment=\u003CenvironmentId|none> dataverse-tables=\u003CN> connectors=\u003CN>\n```\n\nDo not resolve the environment or call Dataverse during ordinary bundle, React, or local JavaScript failures. When a current symptom\u002Ferror is Dataverse or Power Platform related, perform the read-only Dataverse diagnostic sequence in D2 before handing off.\n\n### 0.0 Discover and select the project-local Metro session\n\nUse the validated `\u003Cworking_dir>` from argument parsing. Enumerate **all** matching logs, newest first:\n\n```bash\nLOG_DIR='\u003Cworking_dir>\u002F.powernative\u002Fmetro-logs'\nls -t \"$LOG_DIR\"\u002Fmetro-*-pid-*-port-*.log 2>\u002Fdev\u002Fnull\n```\n\nFor every candidate, parse:\n\n- `pid` and `port` from `metro-\u003Ctimestamp>-pid-\u003Cpid>-port-\u003Cport>.log`;\n- `startedAt` from the filename timestamp;\n- `project` from `power.config.json.appDisplayName`, falling back to the basename of `\u003Cworking_dir>`;\n- `platform` by scanning only the latest 64 KiB for the most recent `iOS ... Bundled` \u002F `iOS Bundling` or `Android ... Bundled` \u002F `Android Bundling` line; use `unknown` when neither appears.\n\nCheck every recorded PID with a cross-platform Node probe: `process.kill(pid, 0)` means alive; treat `EPERM` as alive and other errors as gone. When `port` is numeric, verify ownership with `lsof -nP -iTCP:\u003Cport> -sTCP:LISTEN -t` on macOS\u002FLinux when available, or `netstat.exe -ano -p tcp` on Git Bash\u002FWindows. On Linux without `lsof`, use `ss -ltnp` when available. A candidate is **valid\u002Flive** only when its PID is alive and either owns the recorded port, has `port=unknown`, or no supported port-ownership probe exists. A probe that runs and reports a different PID is a contradiction, not an unavailable probe. Do not persist terminal IDs or depend on terminal output.\n\nSelection rules:\n\n- Apply `portFilter` and `platformFilter` to the valid\u002Flive candidates before selection. When no valid session matches, print the filters plus the available valid sessions and stop. If a platform-filtered candidate is `unknown`, do not guess; tell the user to use `--port` or omit `--platform`.\n- **One valid session** — select it automatically.\n- **Multiple valid sessions** — show one choice per session in this exact shape, then ask which to monitor:\n  ```text\n  \u003Cproject> — \u003Cplatform> — port \u003Cport> — pid \u003Cpid> — started \u003CstartedAt>\n  ```\n  Use `AskUserQuestion`; identify choices internally by the complete `logPath` + `pid` + `port`, not by port alone. If `metro-cursor.json` points to one of the valid sessions, make that session the default choice but still ask. Never silently choose the newest session when more than one is live.\n- **No valid sessions** — apply the failure branches below. Stale or contradictory logs are evidence for the report, never selectable choices.\n\n**`status` branch — return before selection:** After filtering and liveness checks, read `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` only when it is nonempty valid JSON with string `logPath`, numeric `pid`, and numeric-or-`unknown` `port`. Treat a missing, empty, malformed, or shape-invalid cursor as absent and print a warning; never overwrite it from `status`. Print every valid session newest-first using the normal session display shape, marking `[saved]` only when `logPath` + `pid` + `port` match the valid cursor. Then print at most the last 20 nonempty lines from `fixes.md` and `unresolved.md`, passing the displayed text through the persistence redactor first. Print stale\u002Fcontradictory candidate counts without diagnosing their log content, then exit. When no valid session exists, print that result plus the applicable no-log\u002Fstale reason and exit.\n\nFor monitoring modes only, select a session using the rules above. After selection, set `LOG_PATH`, `pid`, `port`, `project`, `platform`, and `startedAt` from the chosen candidate. This selection is sticky for the current monitor run.\n\nWhen no log exists, inspect `metro.config.js` and resolve the logging module from `\u003Cworking_dir>` before choosing a failure branch:\n\n- **Current factory form:** the config uses `createPowerAppsMetroConfig` from `@microsoft\u002Fpower-apps-native-host\u002Fconfig\u002FmetroConfig`, and that exact subpath resolves from the project's installed dependencies. The factory installs project-local logging internally.\n- **Legacy direct form:** the config directly imports `@microsoft\u002Fpower-apps-native-host\u002Fmetro-logger`, and that exact subpath resolves from the project's installed dependencies.\n- **Unavailable:** neither configured subpath resolves, the referenced form is absent, or `@microsoft\u002Fpower-apps-native-host` is missing from `package.json`. A dependency version string alone does not prove that the configured export exists.\n\nBranch as follows:\n\n| Status | Meaning | Action |\n|---|---|---|\n| Exactly one valid log exists, PID is alive, and either port is unknown or the port probe is unavailable | Select it. Capture `project`, `platform`, `startedAt`, `port`, `pid`, and `logPath`, then continue. |\n| Exactly one valid log exists and PID still owns the logged port | Select it. Capture `project`, `platform`, `startedAt`, `port`, `pid`, and `logPath`, then continue. |\n| Multiple valid logs exist | Show every valid session and ask which one to monitor. Do not select by recency alone. |\n| Log exists, PID is gone, and another process owns the logged port | Do NOT diagnose from this log. Tell the user which PID holds the port and ask them to restart `npm run dev`. |\n| Log exists but PID\u002Fport contradict each other | The device may be talking to the wrong server. Ask the user to stop stale Metro processes and rerun `npm run dev`. |\n| No log exists and the logging form is unavailable | This project predates project-local Metro logging or has incomplete dependencies. Enter startup diagnostics to distinguish broken install, unsupported export, and config mismatch; do not edit native\u002FMetro config or loop on restarts. |\n| No log exists and the current factory or legacy direct logging form resolves | If available host output contains `[powernative] Metro logging instrumentation failed`, preserve that bounded evidence. Enter startup diagnostics rather than assume a package defect or require the app to load first. |\n\nThe PID\u002Fport check prevents stale-log diagnosis: a log file can outlive its Metro process, so only the socket probe reveals that the log stopped belonging to the app under test. The explicit choice prevents a valid session on one port from being confused with another valid session in the same project.\n\nIf no `.powernative` log exists but the host exposes a live Metro terminal, use\nits bounded output only as startup evidence. Do not ask for or store its terminal\nID or enter the continuous monitor against it. The startup phase owns any\napproved retry; runtime monitoring still requires a valid project-local log.\n\nRecord the stable source in `fixes.md`:\n\n```text\n[\u003CHH:MM:SS>] Log source — \u003Cproject> \u003Cplatform> — \u003ClogPath> (pid \u003Cpid>, port \u003Cport>, started \u003CstartedAt>)\n```\n\n### 0.1 Ensure state directory\n\n```bash\nmkdir -p .powernative\u002Fdebug-app\ntouch .powernative\u002Fdebug-app\u002Ffixes.md\ntouch .powernative\u002Fdebug-app\u002Funresolved.md\ntouch .powernative\u002Fdebug-app\u002Finjected-logs.md\ntouch .powernative\u002Fdebug-app\u002Fhealth.json\ntouch .powernative\u002Fdebug-app\u002Fmetro-cursor.json\nrm -f .powernative\u002Fdebug-app\u002Fsymptom-state    # per-session — Phase 0.5 rewrites it if symptom mode is active\n```\n\nIf `fixes.md` is empty, write a session header:\n```\n# Debug session — \u003Cdate>\n\n```\n\nAppend the effective invocation settings:\n\n```text\n[\u003CHH:MM:SS>] Monitor config — port=\u003Cany|port> platform=\u003Cany|ios|android> clean-cycles=\u003CtargetCleanCycles> timeout=\u003CtimeoutSeconds>s no-fix=\u003Ctrue|false>\n```\n\n### 0.1.1 Initialize health state\n\nWrite `.powernative\u002Fdebug-app\u002Fhealth.json` without raw log content:\n\n```json\n{\n  \"bundle\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"runtime\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"authentication\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"dataverse\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"connector\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"offline\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"navigation\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"nativeCapability\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"updatedAt\": \"\u003CISO timestamp>\"\n}\n```\n\nAllowed statuses are `healthy`, `degraded`, `failed`, `unknown`, and `not-configured`. Update only the affected domain after each classified signal:\n\n| Signal | Health update |\n|---|---|\n| Successful native bundle after the latest bundle error | `bundle=healthy` |\n| Bundle\u002Ftransform\u002Fimport failure | `bundle=failed` |\n| Uncaught JS\u002FReact error | `runtime=failed`; set `healthy` after the repaired workflow produces clean new output |\n| Auth success\u002Ffailure host diagnostics | `authentication=healthy|failed` |\n| Dataverse 2xx\u002Ferror for the affected operation | `dataverse=healthy|failed` |\n| Connector resolution\u002Fcall success or failure | `connector=healthy|failed` |\n| No offline profile | `offline=not-configured`; offline activation\u002Fsync warning or failure → `degraded|failed` |\n| Confirmed route\u002Fnavigation error | `navigation=failed`; repaired route confirmation → `healthy` |\n| Native wrapper success, permission denial, missing module, or native failure | `nativeCapability=healthy|degraded|failed` |\n\nAbsence of evidence remains `unknown`; never convert an unobserved domain to `healthy`.\n\n### 0.1.2 Persistence redaction gate\n\nBefore appending diagnostic text to `fixes.md` or `unresolved.md`, or storing a health `summary`, sanitize it:\n\n1. Convert project paths to paths relative to `\u003Cworking_dir>`. Replace other absolute home-directory paths with `[REDACTED_PATH]`.\n2. Replace complete authorization\u002Fcookie\u002Fsecret headers (`Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`, `x-api-key`, `api-key`, `client-secret`, and token headers) with `[REDACTED_HEADER]`.\n3. Replace Bearer values, JWT-like three-segment values, SAS\u002Fquery secrets (`sig`, `se`, `sp`, `sv`, `code`, `token`, `access_token`, `refresh_token`, `id_token`, `client_secret`), passwords, and API keys with `[REDACTED_SECRET]`.\n4. Replace email addresses with `[REDACTED_EMAIL]` and GUIDs\u002Frecord identifiers with `[REDACTED_ID]` unless the identifier is a non-sensitive local PID\u002Fport.\n5. Never persist Dataverse\u002Fconnector response bodies or arbitrary `[TRACE]` object values. Persist only status, source\u002Fconfig table or column names, counts, error codes, and a bounded error message.\n6. Scan the sanitized result again. If any sensitive pattern remains, persist `[REDACTION_BLOCKED: diagnostic omitted]` instead.\n\nRun the bundled verifier for every candidate diagnostic before writing:\n\n```bash\nprintf '%s' \"$DIAGNOSTIC_SUMMARY\" | node \\\n   \"${PLUGIN_ROOT}\u002Fscripts\u002Fredact-debug-diagnostic.js\" \\\n  --working-dir '\u003Cworking_dir>'\n```\n\nPersist only the verifier's stdout. Build `DIAGNOSTIC_SUMMARY` from minimal fields first; do not pass a full Metro window or response body and rely on redaction to make it safe.\n\nStore `logPath` in `metro-cursor.json` relative to `\u003Cworking_dir>` and resolve it against `\u003Cworking_dir>` when reading. This gate is required even though `.powernative` logs are already sanitized.\n\n### 0.2 Verify Metro bundled and the app is running\n\n**Telemetry checkpoint: `validate_metro_session`**\n\nRead a bounded baseline window and return a real byte cursor:\n\n```bash\nnode - \"$LOG_PATH\" 262144 \u003C\u003C'NODE'\nconst fs = require('node:fs');\nconst [file, maxText] = process.argv.slice(2);\nconst maxBytes = Number(maxText);\nconst size = fs.statSync(file).size;\nconst start = Math.max(0, size - maxBytes);\nconst fd = fs.openSync(file, 'r');\nconst buffer = Buffer.alloc(size - start);\nconst bytesRead = fs.readSync(fd, buffer, 0, buffer.length, start);\nfs.closeSync(fd);\nprocess.stdout.write(JSON.stringify({\n   cursor: start,\n   nextCursor: start + bytesRead,\n   truncated: start > 0,\n   output: buffer.subarray(0, bytesRead).toString('utf8')\n}, null, 2));\nNODE\n```\n\nThe logger initially writes `port-unknown` and may atomically rename that file to the numeric port. If the baseline read gets `ENOENT`, rediscover once before reporting failure. When the same filename timestamp and PID now exist with a numeric port, update `LOG_PATH` and `port` to that file and retry the bounded read once; do not process both names as separate sessions.\n\nParse `output`, `cursor`, `nextCursor`, and `truncated`; use the `pid`, `port`, and `logPath` resolved in Phase 0.0. Scan `output`:\n\n- Most recent error-class line is `SyntaxError`, `Unable to resolve module`, `transform failed`, or `error: Bundling failed` → bundle is broken. Treat as a Step B \"Import \u002F Bundle\" critical error and route through Step D immediately. Do NOT enter the steady-state loop until the bundle is healthy.\n- Output contains `Bundling complete` \u002F `iOS Bundled` \u002F `Android Bundled` with no later error-class line → Metro is healthy. Proceed.\n- Output contains a Metro banner (`Metro waiting on`, `Logs for your project`, or `› Metro:`) but no native `Bundled` \u002F `bundling` lines yet → Metro is up but no native client has connected. Tell the user:\n  > **Metro is running but no app is connected yet.**\n  Enter startup diagnostics for a reported QR\u002Fopening problem, or ask the user\n  to open the native client. If they cannot verify it now, return\n  `verification-pending`; no reinstall merely because the client has not connected.\n- Output contains only the logger startup line while the selected PID\u002Fport session remains live → Metro has not emitted enough state yet. Tell the user to wait for the native URL, then re-run `\u002Fdebug-app`; do not guess readiness.\n\nIf `truncated: true`, the baseline covers only the latest 256 KiB. Record that older history was omitted; do not claim the full session history was inspected.\n\nBefore initializing the cursor, pass **all** classifiable entries in this initial\nwindow through Step B, including JS runtime errors, React warnings, network\u002FAPI\nfailures, native errors, and host diagnostics. Do not advance past a prior error\njust because it is not a bundle error. This preserves the promise that users can\n\"play around, then debug\" after a symptom already occurred.\n\n### 0.2.1 Supersession — never re-fix an error the log already shows resolved\n\nThe baseline window is **history, not current state**. It can contain errors that\nwere already fixed, that the user resolved themselves, or that were transient.\nFixing those is worse than doing nothing: it edits working code to chase a\nsymptom that no longer exists, and the \"fix\" is unverifiable because the error\ncannot reproduce.\n\nSo every error found in the **baseline window only** (not in later polls) is\ntreated as *unconfirmed* until checked for supersession. Scan forward from the\nerror line to the end of the window:\n\n| Error class | Superseded when a later line shows |\n|---|---|\n| Import \u002F Bundle | `Bundling complete`, `iOS Bundled`, or `Android Bundled` |\n| Network \u002F API | a 2xx for the same route\u002Fresource that previously failed |\n| JS runtime \u002F React | a later app reload or successful bundle, and the error does not reappear after it |\n| Host diagnostic (`[AuthProvider]`, `[bridge]`, …) | a later success from the same subsystem (e.g. a token acquired after `acquireTokenSilent failed`) |\n\nThen:\n\n- **Superseded** → do NOT fix. Record it and move on:\n  ```\n  [\u003CHH:MM:SS>] Observed (already resolved, not fixed) — \u003Cerror summary> — superseded by \u003Cevidence line>\n  ```\n- **Not superseded** → the error is live. Fix it normally through Step D.\n- **Ambiguous** (no clear supersession evidence either way) → do NOT edit code yet. Ask the user whether they still see it, or wait for it to reappear in the next poll. An error that recurs after the cursor advances is confirmed live.\n\nThis applies to the baseline window only. Anything appearing in a later\n`tail --cursor` poll is by definition new output and needs no supersession check.\n\n**Symptom mode overrides this.** If the user supplied a symptom, that is\nfirst-hand evidence the problem is current, so a matching baseline error is\ntreated as live even when a later line would otherwise look like supersession.\n\n### 0.3 Capture baseline\n\n**Telemetry checkpoint: `capture_runtime_baseline`**\n\nUse the output from Phase 0.2. Note the most recently bundled native platform (iOS \u002F Android) and any recent runtime log lines. Append to `fixes.md`:\n```\n[\u003CHH:MM:SS>] Baseline — last Metro activity: \u003C1-line summary of most recent lines>\n```\n\n### 0.4 Initialize the durable byte cursor\n\nWrite `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` using structured JSON:\n\n```json\n{\n   \"logPath\": \".powernative\u002Fmetro-logs\u002Fmetro-\u003Ctimestamp>-pid-12345-port-8081.log\",\n   \"pid\": 12345,\n   \"port\": 8081,\n   \"project\": \"My Mobile App\",\n   \"platform\": \"ios\",\n   \"startedAt\": \"2026-08-27T12:41:32.050Z\",\n   \"monitorStartedAt\": \"\u003CISO timestamp>\",\n   \"monitorConfig\": {\n      \"port\": null,\n      \"platform\": null,\n      \"targetCleanCycles\": 3,\n      \"timeoutSeconds\": 300,\n      \"noFix\": false\n   },\n   \"cursor\": 12345,\n   \"updatedAt\": \"\u003CISO timestamp>\"\n}\n```\n\nSet project-relative `logPath`, plus `pid`, `port`, `project`, `platform`, and `startedAt` from Phase 0.0. Set `monitorStartedAt` and `monitorConfig` from the current invocation, and set `cursor` to `nextCursor` from Phase 0.2. Resolve `logPath` against `\u003Cworking_dir>` before file access. A new invocation always replaces the prior monitoring configuration and start time. On later invocations:\n\n- Parse an existing cursor only when it is nonempty valid JSON with the expected field types. Treat a missing, empty, malformed, or shape-invalid file as no saved cursor, append a sanitized reset warning to `fixes.md`, and initialize from the selected session's bounded baseline. Never fail startup solely because prior debug state is partial.\n\n- Same `logPath`, `pid`, and `port`, with the process still owning the port → reuse the saved cursor so old errors are not processed again.\n- Multiple valid sessions → ask which session to monitor. Default to the saved session when it remains valid.\n- A different session is explicitly selected, or the saved session is no longer valid → discard the old cursor and initialize from the selected session's latest log window.\n- `rotationLost: true` from Step A → accept the returned reset cursor and record the file shrink\u002Freplacement in `fixes.md`.\n\n---\n\n## Phase 0.5 — Symptom-driven setup (only when `$ARGUMENTS` is a symptom string)\n\nSkip this entire phase if no symptom was provided. The standard log-polling loop alone is good at *visible* errors but blind to *silent* ones: an empty list because the connector wasn't added, a blank screen because `useFocusEffect` wasn't wired, blank rows because column names don't match the model. Phase 0.5 closes that gap.\n\n**`--no-fix` behavior:** Parse the symptom and ask the user to reproduce it, but do not inject `[INJECTED-TRACE]` logs or edit any file. Read only new Metro output. If the symptom is silent and produces no classifiable output, write `pending` to `symptom-state`, append `watch-only: traces not injected` to `unresolved.md`, then enter the standard loop.\n\n### 0.5.1 Parse the symptom\n\nExtract three signals from the user's text:\n\n| Signal | How to derive |\n|---|---|\n| **Affected screen** | Match keywords against route filenames in `app\u002F` (e.g., `\"todos\"` → `app\u002F(tabs)\u002Ftodos.tsx`, `app\u002Ftodos\u002Findex.tsx`, `app\u002F(tabs)\u002Findex.tsx`). Use `Glob` to enumerate `app\u002F**\u002F*.tsx`; pick the closest substring match. If multiple, ask once. |\n| **Affected entity \u002F service** | Same keyword against `src\u002Fgenerated\u002Fservices\u002F*Service.ts` and `src\u002Fgenerated\u002Fmodels\u002F*Model.ts` (e.g., `\"todos\"` → `TodosService`, `Todo` model). Use `Glob`. |\n| **Symptom class** | Map the text to one of: `empty-list`, `blank-screen`, `wrong-data`, `unresponsive-control`, `stale-data`, `wrong-navigation`, `crash`, `pdf-viewer`, `pdf-report`, `pen-input`, `geolocation`, `dataverse-upload`. Default for \"PDF won't open \u002F preview PDF fails\": `pdf-viewer`. Default for \"report PDF not generated \u002F print report fails\": `pdf-report`. Default for \"signature \u002F pen \u002F ink fails\": `pen-input`. Default for \"location not tracking \u002F GPS not updating \u002F background location stopped \u002F breadcrumb gaps \u002F route not consistent\": `geolocation`. Default for \"signature\u002Freport saved but missing\", or \"location rows not reaching Dataverse\": `dataverse-upload`. Default for \"not appearing \u002F not showing \u002F nothing here \u002F missing\": `empty-list`. Default for \"doesn't load \u002F freezes \u002F spinner forever\": `blank-screen`. |\n\nAppend to `fixes.md`:\n```\n[\u003CHH:MM:SS>] Symptom — class=\u003Cclass> screen=\u003Cpath> entity=\u003Cservice>\n```\n\nIf no screen\u002Fentity match: keep `screen=unknown` \u002F `entity=unknown` and proceed — Phase 0.5 still injects diagnostic logs and reads the terminal from whatever data path is most likely based on the symptom text.\n\n### 0.5.2 Ask the user to navigate to the affected screen\n\nThe dev-player has no automation API for navigation. Ask the user:\n> \"Please open the `\u003Cscreen>` screen on the device\u002Fsimulator, then reply `ready`.\"\n\nWait for the user to confirm before proceeding.\n\n### 0.5.3 Inject diagnostic console.log statements and read terminal\n\nInject targeted `console.log` statements at the boundaries of the suspected data path so the Metro terminal reveals what's happening.\n\n**Injection sites — choose the minimum set that covers the symptom class:**\n\n| Symptom class | Inject at |\n|---|---|\n| `empty-list` | (a) entry point of the data-fetching hook, logging `[TRACE items]` the raw response length; (b) the screen component, logging `[TRACE render]` the `items` array length before the list renders |\n| `blank-screen` | Entry point of the screen component, logging `[TRACE mount]` with a timestamp plus only booleans or counts that describe whether required auth\u002Fdata props are present |\n| `wrong-data` \u002F `stale-data` | The hook that calls the generated service (NOT inside `src\u002Fgenerated\u002F`), logging `[TRACE service-response]` with an allowlisted summary: result count, error presence, bounded error code\u002Fstatus, and expected-field presence booleans |\n| `unresponsive-control` | The event handler (`onPress`, `onSubmit`, etc.) logging `[TRACE handler-called]` before any async work |\n| `crash` | Skip injection — jump to the monitor loop (Step A), crash stacks appear in the terminal |\n\n**Console.log injection pattern — all injected lines MUST use this exact format:**\n\n```ts\nconsole.log('[TRACE \u003Ctag>]', \u003Cvalue>); \u002F\u002F [INJECTED-TRACE]\n```\n\n- `\u003Ctag>` — short unique label for this site (e.g., `items`, `render`, `service-response`)\n- `\u002F\u002F [INJECTED-TRACE]` trailing comment on the SAME LINE — this is the cleanup grep key\n- Log only primitives or a newly constructed allowlisted summary of counts, booleans, bounded error\u002Fstatus codes, and configured table\u002Fcolumn names. `JSON.stringify` is allowed only for that constructed summary.\n- Never log raw records, response bodies, arbitrary objects, field values, user-entered text, auth\u002Fdata prop values, identifiers, URLs, headers, or credentials. The host logger removes credential-like lines, but it cannot prove arbitrary app data is free of sensitive information.\n- **Never inject inside `src\u002Fgenerated\u002F`** — inject in the hook\u002Fscreen that calls into it\n\nRecord every injection in `.powernative\u002Fdebug-app\u002Finjected-logs.md`:\n```\n[\u003CHH:MM:SS>] Injected [INJECTED-TRACE] at \u003Cfile>:\u003Cline> — tag=\u003Ctag>\n```\n\nThen tell the user:\n> \"I've added diagnostic console.log statements. Fast Refresh should apply them automatically. Navigate to `\u003Cscreen>` and trigger the symptom (for example, scroll the list or tap the button). If the app does not refresh, reload it from the native dev-client menu. Reply `done` when finished.\"\n\nWait for the user to reply, then run the Step A `tail --cursor` procedure, persist `nextCursor`, and filter the returned `output` for `[TRACE` lines.\n\n### 0.5.4 Walk the data path from terminal output\n\nUse the `[TRACE` lines to walk the chain:\n\n1. **Screen TSX** (`app\u002F\u003Croute>.tsx`)\n   - Find the `useListData(...)` \u002F `use*Data(...)` call.\n   - Check service-call options — a stray `top: 0`, an over-strict `filter`, a `search: query` bound to a never-cleared input, or `orderBy` on a missing column can each silently return zero rows.\n   - Check any client-side `.filter(...)` after the data lands.\n\n2. **Data hook** (`src\u002Fhooks\u002FuseListData.ts` or sibling)\n   - **Critical:** the template hook has TWO mock-fallback paths:\n     - **Error path**: service returns `{ error }` → hook substitutes mock AND may call `setError`. **Silent** if the screen ignores `error`.\n     - **Empty-result path**: service returns `{ data: [] }` (no error) → hook silently substitutes mock. Always invisible without a `[TRACE]` log.\n   - Detect: `Grep` for `MOCK_` imports in the screen file. If present, mock data is wired in.\n   - Confirm `useFocusEffect` is used (not `useEffect`) — `useEffect` won't re-run on back-navigate.\n\n3. **Generated service** (`src\u002Fgenerated\u002Fservices\u002F\u003CName>Service.ts`)\n   - If a TODO stub or file missing → route to `\u002Fadd-connector` or `\u002Fadd-dataverse`. Do NOT edit `src\u002Fgenerated\u002F`.\n   - If it exists and the `[TRACE service-response]` summary shows an error → use its bounded status\u002Ferror code; 401\u002F403 = auth issue; 404 = wrong resource name. Use separately emitted, already-sanitized host diagnostics for message context; do not add a raw error trace.\n\n4. **Generated model** (`src\u002Fgenerated\u002Fmodels\u002F\u003CName>Model.ts`)\n   - Confirm field names match what the screen references. `item.title` vs `cr3e9_title` produces blank rows.\n\n5. **`power.config.json`**\n   - Confirm the `datasources` array contains the suspected entity \u002F connector. If absent, `pa app add data-source` was never run for it.\n\n6. **Auth state** (`src\u002FplayerConfig.ts`, `app.config.js`, `auth.config.json`, `useAuth()` hook)\n   - 401 from the service wrapped as `{ error }` — the `[TRACE service-response]` summary surfaces the status without persisting the error object or message.\n   - **OAuth deeplink handoff**: verify `app.config.js` → `expo.scheme` matches `src\u002FplayerConfig.ts` → `connectorOAuthRedirectUri`, AND the same redirect URI is in `auth.config.json` and the Entra ID registration. If the app registration is missing, route the user to the Power Apps Wrap page via `\u002Fset-app-registration-native`.\n\n**Classify the `[TRACE` output:**\n\n| Output | Meaning | Next step |\n|---|---|---|\n| `[TRACE items] 0` or `[]` — no error field | Service returned empty — check filter\u002Fquery or data not seeded | Fix the query; if no records exist, seed sample data |\n| `[TRACE items] undefined` | Hook never received a response — likely service stub or missing datasource | Route to `\u002Fadd-connector` or `\u002Fadd-dataverse` |\n| `[TRACE service-response]` shows an error status\u002Fcode | Service threw — 401\u002F403 = auth; 404 = wrong resource | Fix auth config or re-run `pa app add data-source` |\n| `[TRACE render]` N > 0 but list looks empty | Field name mismatch between model and screen | Fix screen field references to match the model |\n| `[TRACE handler-called]` never appears | `onPress` not wired or component not mounted | Read TSX, fix the event binding |\n| No `[TRACE` lines at all | Metro may have cached the old bundle | Ask the user to stop Metro, rerun `npm run dev -- --clear`, then reload the native app |\n\nRecord the outcome in `.powernative\u002Fdebug-app\u002Fsymptom-state` (single line: `resolved`, `flagged`, or `pending`).\n\n- **Fix is clear and local** → apply via Step D3 + D4 (type-check + reload + re-poll). After the fix, ask the user to interact with the screen again and read the terminal. If the `[TRACE items]` line shows N > 0, write `resolved`.\n- **Fix routes to another skill** → tell the user, log to `unresolved.md`. Write `flagged`.\n- **No obvious cause** → log a structured note to `unresolved.md`. Write `pending` and enter the monitor loop.\n\n### 0.5.5 Clean up injected console.log statements\n\nAfter the root cause is identified and a fix is applied (or Phase 0.5 concludes), remove ALL injected logs:\n\n```bash\nfind app src -type f \\( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \\) \\\n   ! -path 'src\u002Fgenerated\u002F*' -exec grep -nH 'INJECTED-TRACE' {} +\n```\n\nFor each matching file, edit out the `console.log(...); \u002F\u002F [INJECTED-TRACE]` lines. Verify with:\n```bash\nfind app src -type f \\( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \\) \\\n   ! -path 'src\u002Fgenerated\u002F*' -exec grep -nH 'INJECTED-TRACE' {} +  # must print zero matches\n```\n\nClear the tracking file:\n```bash\necho '' > .powernative\u002Fdebug-app\u002Finjected-logs.md\n```\n\nRun `npm run type-check` once after cleanup.\n\n> **Hard rule:** Never leave `[INJECTED-TRACE]` lines in code. Clean up before marking the session done, even if the symptom is `pending` or `flagged`.\n\n### 0.5.6 Re-enter the standard monitor loop\n\nAfter Phase 0.5 completes, fall through to the monitor loop (Step A). Count clean cycles normally, but let Step C choose the exit from the single-line `symptom-state`: `resolved` may exit green, while `flagged` and `pending` use their non-green exits after `targetCleanCycles`. Never report a green result for a flagged or pending symptom.\n\n---\n\n## Monitor Loop\n\nRepeat until **`targetCleanCycles` consecutive clean cycles**, `timeoutSeconds` elapses, the user types `stop`, OR the escalation rule trips.\n\nBefore every collection cycle and immediately after any fix verification, compare the current time with `monitorStartedAt`. When elapsed time is greater than or equal to `timeoutSeconds`:\n\n1. Clean up all `[INJECTED-TRACE]` lines before exit.\n2. Append the elapsed time, cycle count, clean count, active session identity, and unresolved issue count to `fixes.md`.\n3. Exit without stopping Metro:\n   ```text\n   ⚠ Monitoring timeout reached after \u003Cduration>.\n     Session: \u003Cproject> — \u003Cplatform> — port \u003Cport> — pid \u003Cpid>\n     Clean checks: \u003Cclean>\u002F\u003CtargetCleanCycles>\n   Details: .powernative\u002Fdebug-app\u002Ffixes.md\n   ```\n\n### Step A — Collect logs\n\n**Telemetry checkpoint: `collect_runtime_logs`**\n\nRead `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` and rediscover all live `.powernative` sessions using Phase 0.0's validation logic.\n\n- If the saved `logPath` + `pid` + `port` is still valid, keep monitoring it even when a newer valid session has appeared. Do not interrupt the current run or jump ports.\n- If the saved session is no longer valid and exactly one valid session remains, select that session and return to Phase 0.2 for a new baseline.\n- If the saved session is no longer valid and multiple valid sessions remain, show the session choices and ask which one to monitor, then return to Phase 0.2.\n- If no valid session remains, stop with the applicable Phase 0.0 failure instead of reading a stale log.\n\nOtherwise collect newly appended bytes from the pinned session. When no bytes are already waiting, this foreground collector watches the log directory until that file changes or a full 5-second observation interval completes:\n\n```bash\nnode - \"$LOG_PATH\" \u003Csaved-cursor> 262144 5000 \u003C\u003C'NODE'\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst [file, cursorText, maxText, observationText] = process.argv.slice(2);\nconst cursor = Number(cursorText);\nconst maxBytes = Number(maxText);\nconst observationMs = Number(observationText);\nconst observedAt = Date.now();\nlet watcher;\nlet timer;\nlet finished = false;\n\nfunction snapshot(observation) {\n   try {\n      const size = fs.statSync(file).size;\n      const start = Number.isInteger(cursor) && cursor >= 0 && cursor \u003C= size ? cursor : 0;\n      const fd = fs.openSync(file, 'r');\n      const buffer = Buffer.alloc(Math.min(maxBytes, Math.max(0, size - start)));\n      let bytesRead;\n      try {\n         bytesRead = fs.readSync(fd, buffer, 0, buffer.length, start);\n      } finally {\n         fs.closeSync(fd);\n      }\n      return {\n         cursor: start,\n         nextCursor: start + bytesRead,\n         rotationLost: start !== cursor,\n         truncated: start + bytesRead \u003C size,\n         fileMissing: false,\n         readError: null,\n         observation,\n         observedMs: Date.now() - observedAt,\n         output: buffer.subarray(0, bytesRead).toString('utf8'),\n      };\n   } catch (error) {\n      return {\n         cursor,\n         nextCursor: cursor,\n         rotationLost: false,\n         truncated: false,\n         fileMissing: error && error.code === 'ENOENT',\n         readError: error && typeof error.code === 'string' ? error.code : 'UNKNOWN',\n         observation,\n         observedMs: Date.now() - observedAt,\n         output: '',\n      };\n   }\n}\n\nfunction finish(observation) {\n   if (finished) return;\n   finished = true;\n   if (watcher) watcher.close();\n   if (timer) clearTimeout(timer);\n   process.stdout.write(JSON.stringify(snapshot(observation), null, 2));\n}\n\nconst initial = snapshot('initial');\nif (initial.readError || initial.rotationLost || initial.truncated || initial.output) {\n   process.stdout.write(JSON.stringify(initial, null, 2));\n} else {\n   try {\n      watcher = fs.watch(path.dirname(file), (_event, changedFile) => {\n         if (!changedFile || String(changedFile) === path.basename(file)) finish('change');\n      });\n      watcher.on('error', () => finish('watch-error'));\n      timer = setTimeout(() => finish('interval'), observationMs);\n   } catch {\n      finish('watch-error');\n   }\n}\nNODE\n```\n\nUse only the returned `output` for this cycle. `fileMissing: true` means the logger may have renamed `port-unknown`; rediscover sessions instead of advancing the cursor. Any other non-null `readError`, or `observation: watch-error`, is not a clean cycle: report the bounded error code and stop rather than polling rapidly. Otherwise immediately persist the current `logPath`, `pid`, `port`, `nextCursor`, and a new `updatedAt` to `metro-cursor.json`, even when `output` is empty or contains an error; this prevents duplicate processing after interruption and handles file replacement safely.\n\nCount a clean cycle only when `readError` is null, `observation: interval`, `observedMs >= 5000`, and `output` is empty or contains no classifiable error. An early `change` observation with informational output is not yet a full clean interval; process it and start the next collection cycle. If the log file changes, the PID\u002Fport check becomes contradictory, or the cursor resets because the file shrank\u002Frotated, never count that cycle as clean.\n\nIf `truncated: true`, never count the result as clean. Process any nonempty output, then issue at most three additional tail calls from the returned cursor in the same cycle. If `rotationLost: true`, record an explicit rotation warning in `fixes.md` and require a fresh full observation interval before incrementing the clean counter. If data remains truncated after four chunks, record a backlog warning and continue next cycle rather than consuming unbounded context.\n\nIn the new output, surface as classifiable signal and update the matching `health.json` domain:\n- Runtime ` ERROR ` \u002F ` WARN ` \u002F ` LOG ` prefixes\n- Host diagnostic lines with prefixes like `[PAHost]`, `[bridge]`, `[AuthProvider]`, `[AuthContext]`, `[useConnectionRefs]`, `[useConnectionSetup]`, `[addAadAppToConnectionAcl]`, `[PAHost][ErrorBoundary]`\n- Stack frames (`at \u003Cfn> (\u003Cfile>:\u003Cline>:\u003Ccol>)`)\n- Bundle-class errors (`Unable to resolve module`, `SyntaxError`, `transform failed`) — re-classify as Step B \"Import \u002F Bundle\" Critical and route through Step D\n- HTTP method + status from Metro's request log (e.g., `\"GET \u002Findex.bundle?platform=ios&dev=true ...\" 500 -`) — non-200 on `.bundle` is a bundle\u002Ftransform failure; non-2xx on connector \u002F Dataverse hosts feeds Step B \"Network \u002F API\"\n- Lines containing `Bundling complete` \u002F `iOS Bundled` \u002F `Android Bundled` are informational — log to `fixes.md` at debug volume but do NOT classify as an issue\n- `[TRACE` prefixed lines from injected trace statements — classify under the symptom walk (Phase 0.5.4), not as errors\n\nInterpretation rule for host diagnostic lines:\n- Treat as classifiable signal only when lines match emitted host strings such as:\n   - `[AuthProvider] MSAL init failed:`\n   - `[AuthProvider] Intune enrollment failed:`\n   - `[AuthContext] acquireTokenSilent failed for scopes:`\n   - `[AuthProvider] Intune unenroll failed:`\n   - `[bridge] unhandled plugin call`\n   - `[bridge] fetch THREW for`\n   - `[bridge] HTTP \u003Cstatus> for`\n   - `[addAadAppToConnectionAcl] failed HTTP \u003Cstatus> for connection`\n   - `[addAadAppToConnectionAcl] error:`\n   - `[useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required`\n   - `[useConnectionRefs] Failed to load connections:`\n   - `[useConnectionSetup] could not grant connection ACL: missing Power Apps token or user OID`\n   - `[PAHost] getConnectorToken: acquireToken threw for apiId=\"...\":`\n   - `[PAHost] getConnectorToken: acquireToken returned null for apiId=\"...\"`\n   - `[PAHost] getDataverseToken: acquireToken threw for orgUrl=\"...\":`\n   - `[PAHost] getDataverseToken: acquireToken returned null for orgUrl=\"...\"`\n   - `[PAHost][ErrorBoundary] Unhandled JS error:`\n   - `[PAHost][ErrorBoundary] Error stack:`\n   - `[PAHost][ErrorBoundary] Component stack:`\n- Treat as informational when lines are lifecycle\u002Fstatus-only, such as bridge setup\u002Fready, token acquisition start\u002Fsuccess, bridge registration, and connection-setup screen visibility.\n\n### Step B — Classify each new log entry\n\n**Telemetry checkpoint: `classify_runtime_failures`**\n\nApply the 8-category table. Treat each unique stack trace \u002F error message as one issue.\n\n| Priority | Pattern | Category |\n|---|---|---|\n| Critical | Uncaught exception, unhandled promise rejection, app crash | JS Runtime |\n| Critical | `Unable to resolve module`, `Cannot find module` | Import \u002F Bundle |\n| Critical | `SyntaxError`, `Unexpected token`, `transform failed` (multi-line block from Metro terminal, primary mode only) | Import \u002F Bundle |\n| Critical | `Cannot read properties of undefined`, `is not a function` | JS Runtime |\n| High | `NATIVE_MODULE_MISSING` from `pdfViewer` or `penInput` wrapper | Native |\n| High | `NATIVE_MODULE_MISSING`, `PERMISSION_DENIED`, or `TRACKING_FAILED` from `geolocation` wrapper | Native |\n| High | `INVALID_URL` from `pdfViewer`, or logs mentioning `content:\u002F\u002F`, `blob:`, or `http:\u002F\u002F` PDF viewer input | JS Runtime |\n| High | `VIEWER_FAILED` or `CAPTURE_FAILED` from PDF\u002Fpen wrapper | Native |\n| High | `ERROR` level runtime log | JS Runtime |\n| High | HTTP 4xx \u002F 5xx surfaced in logs | Network \u002F API |\n| High | Native module or bridge error | Native |\n| Medium | React `Warning:` component error | React |\n| Low | `WARN` level log that is not known noise | General |\n\n**Parsing the multi-line bundle\u002Ftransform block (primary mode):** Metro prints these as a banner (e.g., `error: Bundling failed`, `iOS Bundling failed`) followed by an indented block. Unlike runtime stacks, the file:line is on the **first non-banner line of the block**, formatted as `\u003Cabsolute or relative path>:\u003Cline>:\u003Ccol>`. There are usually **no** `at \u003Cfn>` stack frames. Example to recognize:\n```\niOS Bundling failed 412ms\nSyntaxError: \u002FUsers\u002F...\u002Fapp\u002F(tabs)\u002Ftodos.tsx: Unexpected token (47:12)\n  45 |   return (\n  46 |     \u003CYStack>\n> 47 |       \u003CText>{title\u003C\u002FText>\n     |             ^\n  48 |     \u003C\u002FYStack>\n  49 |   );\n```\nTake `app\u002F(tabs)\u002Ftodos.tsx:47:12` as the fix site. The recipes in D3.1 below operate on this format.\n\n**Ignore known-noisy lines:**\n- `Require cycle:` warnings from Metro\n- `VirtualizedList: You have a large list…` without an associated crash\n- Expo SDK informational banners (`Starting Metro…`, `Connecting to…`)\n- React Navigation development warnings about non-serializable params (unless tied to a crash)\n- `USER_CANCELLED` from pen input when the screen leaves state unchanged and does not show an error\n- Host lifecycle\u002Finfo lines with no failure indicator, for example `[bridge] setupNativeHost: bridge ready`, `[PAHost] bridge registered`, `[PAHost] render: waiting for connection resolution (spinner)`\n\n### Step C — If NO issues found\n\n**Telemetry checkpoint: `confirm_runtime_health`**\n\nIncrement the consecutive-clean-cycle counter.\n\n**Before exiting at `targetCleanCycles`, check the symptom guard.** Read `.powernative\u002Fdebug-app\u002Fsymptom-state` and pick the matching exit path below. (If no symptom-driven mode was used this session, Phase 0.1 cleared the file at startup, so the \"file missing\" branch fires.)\n\nBefore every clean, flagged, pending, timeout, iteration-cap, or escalation exit, print this sanitized health table from `health.json`:\n\n```text\nHealth\nBundle             \u003Cstatus>  \u003Csummary>\nRuntime            \u003Cstatus>  \u003Csummary>\nAuthentication     \u003Cstatus>  \u003Csummary>\nDataverse          \u003Cstatus>  \u003Csummary>\nConnector          \u003Cstatus>  \u003Csummary>\nOffline            \u003Cstatus>  \u003Csummary>\nNavigation         \u003Cstatus>  \u003Csummary>\nNative capability  \u003Cstatus>  \u003Csummary>\n```\n\nKeep `unknown` when no evidence was observed and `not-configured` only when configuration absence was positively detected. Apply the persistence redaction gate to every summary. A clean log interval does not make all unknown domains healthy.\n\n**`resolved`** OR file missing (no symptom mode this session):\n\n```\n✓ App is running cleanly — no errors detected across \u003CtargetCleanCycles> consecutive log checks.\n  Symptom verification: \u003CPASS | n\u002Fa — no symptom provided>.\n   Session summary written to .powernative\u002Fdebug-app\u002Ffixes.md.\n\n  To resume monitoring, run \u002Fdebug-app again.\n```\n\n**`flagged`** (Phase 0.5 found a real problem that needs another skill):\n\n```\n⚠ Logs are clean BUT the symptom isn't fixed — it requires another skill.\n  Symptom: \u003Cclass> on \u003Cscreen>\n  Next step: \u003Cskill route recorded in unresolved.md by Phase 0.5> (e.g., run \u002Fadd-connector)\n   Details: .powernative\u002Fdebug-app\u002Funresolved.md\n\n  Re-run \u002Fdebug-app \"\u003Csymptom>\" after taking that step to verify the fix.\n```\n\nDo NOT print the green ✓ — the app is technically log-clean but the user-visible problem persists, and the user needs to act before re-running.\n\n**`pending`** (still active after `targetCleanCycles` clean log cycles):\n\nAppend to `unresolved.md` with the Phase 0.5 chain findings, then print:\n\n> \"⚠ Symptom `\u003Cclass>` on `\u003Cscreen>` still active after `\u003CtargetCleanCycles>` clean log cycles. The runtime is quiet but the user-visible problem persists — likely a swallowed data-path error. See `.powernative\u002Fdebug-app\u002Funresolved.md` for the chain walk. Suggested next step: \u003Cderived from the walk>.\"\n\n---\n\nExit the loop. Do NOT auto-resume.\n\n**Iteration cap (applies in both modes):** independent of the clean-cycle counter and timeout, the loop exits after **50 total cycles**. Track `cycle: \u003CN>` at the top of `fixes.md` and increment per cycle. On cap-hit, exit with:\n\n> \"⚠ Loop reached the iteration cap (50 cycles). Symptom may be intermittent OR a fix is regressing on every reload. See `.powernative\u002Fdebug-app\u002Ffixes.md` for the per-cycle log. Suggested next step: review the last 3 fixes for circular regressions, or re-run with a more specific symptom.\"\n\nIf counter is below `targetCleanCycles` and the cap has not tripped, return to Step A. Its foreground file watcher provides the observation interval; do not add shell `sleep`, a host-specific wait command, or a rapid polling loop.\n\n### Step D — If issues ARE found\n\n**Telemetry checkpoint: `repair_and_verify_runtime_issue`**\n\nReset the consecutive-clean counter to 0. For each issue, work through the sequence below **one at a time** before moving to the next.\n\n#### D0. Watch-only branch (`--no-fix`)\n\nWhen `noFix=true`, do not continue to D1–D4 for mutation:\n\n1. Record the category, a minimal sanitized error summary, the project-relative top user-code frame when available, and the fix recipe or handoff that would have been used. Apply the persistence redaction gate before writing.\n2. Append:\n   ```text\n   [\u003CHH:MM:SS>] Observed (no-fix) — \u003Ccategory> — \u003Cfile:line|no user frame> — \u003Csummary>\n     Would do: \u003Cinline fix recipe | skill handoff | manual native action>\n   ```\n3. Do not edit project source\u002Fconfiguration, inject traces, type-check, reload, install, regenerate, switch accounts, or invoke another skill. Updating `.powernative\u002Fdebug-app\u002F` cursor, audit, and health files is allowed.\n4. Continue to the next issue, then return to Step A. New output is still monitored until the clean target, timeout, stop, or iteration cap is reached.\n\n#### D1. Gather context\n\nUse the current Step A `output` block. Note whether the log shows:\n- A crash with a full stack trace (app is crashing)\n- A React error boundary message (component threw)\n- A network error or HTTP status (API\u002Fconnector failure)\n- Empty response with no error (silent failure — consider injecting a `[INJECTED-TRACE]` console.log; see Phase 0.5.3 for the pattern)\n\nFor JS Runtime \u002F React errors, the stack trace in the terminal IS the context. Read the topmost user-code frame to locate the file.\n\nFor crashes or blank screens with no terminal output: ask the user:\n> \"Do you see anything on screen — error boundary, blank white, or loading spinner? Please copy any visible error text.\"\n\n#### D2. Root-cause analysis\n\nRead the relevant source file(s). Identify:\n- The exact file and line causing the error. For runtime errors (JS Runtime, React, Network\u002FAPI), pick the topmost user-code frame from the stack trace (skip `node_modules\u002F` and `src\u002Fgenerated\u002F`). For bundle \u002F transform errors (Import \u002F Bundle category, primary mode), use the file:line on the first non-banner line of the Metro error block — see Step B's parsing note.\n- Whether the fix touches the data layer, UI layer, routing, or schema.\n- Whether the fix could regress other screens.\n\n**Dataverse \u002F Power Platform diagnostic sequence (before handoff):**\n\n1. Read [skills\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md](..\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md). Use `memory-bank.md` and the relevant `native-app-plan.md` sections when present.\n2. Read `power.config.json`; take `environmentId` from it before any other source. Inspect the relevant generated service\u002Fmodel and `connectorSchemas.ts`.\n3. Resolve the environment read-only:\n   ```bash\n   node \"${PLUGIN_ROOT}\u002Fscripts\u002Fresolve-environment.js\" \"\u003CenvironmentId-or-url>\"\n   ```\n   If resolution fails, run `$PA auth status --json`. Never switch accounts, log out, or open login from `\u002Fdebug-app` without user confirmation.\n4. When environment resolution succeeds and live evidence is required, use only read-only `GET` requests through:\n   ```bash\n   node \"${PLUGIN_ROOT}\u002Fscripts\u002Fdataverse-request.js\" \u003CenvUrl> GET \u003CapiPath> \\\n     --tenant-id '\u003Cresolved-tenant-id>'\n   ```\n   Start with `WhoAmI` when authentication\u002Ftenant identity is in question. Use bounded metadata\u002Fentity reads to confirm table and column names. Do not create, update, delete, publish, seed, flood, or intentionally invalidate credentials from `\u002Fdebug-app`.\n5. App runtime data fixes must continue to use generated `\u003CTable>Service` calls. Never replace them with direct `fetch`\u002F`axios` Dataverse calls.\n6. If OData syntax, lookup behavior, choice\u002Fvirtual\u002Ffile\u002Fimage fields, authentication, throttling, or error shape remains uncertain, query Microsoft Learn with the exact error\u002Ftoken before forming a fix.\n\nOnly after this sequence proves that a table\u002Fcolumn\u002Fservice\u002Fschema artifact is missing or incompatible should D3 route to `\u002Fadd-dataverse`.\n\n**Expo \u002F Expo Router \u002F React Native diagnostic sequence:**\n\n1. Read the cited app file plus `package.json`, `app.json`\u002F`app.config.js`, and route layout only as relevant.\n2. Prefer installed package types\u002Freadmes for the exact version.\n3. If behavior remains uncertain, use a targeted `WebFetch` against official `https:\u002F\u002Fdocs.expo.dev\u002F` documentation (Expo Router pages for routing; SDK pages for native modules). Do not query Microsoft Learn for Expo\u002FReact Native behavior.\n\n**First-party native package ownership gate:**\n\nApply this gate before D3 whenever the failing stack, module, or export involves an installed package whose name matches `@microsoft\u002Fpower-apps-native-*`.\n\n1. Treat a `node_modules\u002F` frame as a lead only. Read the app call site, the installed package's public types\u002Freadme\u002Fexports, and the declared and lockfile-resolved package version. Check that the app uses a documented API with supported inputs and configuration.\n2. Classify the problem as customer code when correcting the caller, input, or supported configuration resolves the contract violation. Apply the normal D3 route in that case.\n3. Classify the problem as package-owned only when the supported app call is valid and the failure is caused by package-internal implementation, a missing\u002Fbroken advertised export, or an internal package import. If ownership remains uncertain, do not patch either side; record the uncertainty and escalate.\n4. For a confirmed package-owned defect, stop automated fix attempts for that issue. Do not change app source, configuration, dependency resolution, or installed package contents to compensate. Capture only the package name, declared\u002Fresolved version, platform, minimal reproduction, expected\u002Factual behavior, and a sanitized bounded stack\u002Ferror summary. Then route the user to `\u002Freport-issue`; mention an official published fix or documented workaround when one is known, but do not apply it from `\u002Fdebug-app`.\n\n#### D3. Apply the fix\n\n**For Import \u002F Bundle category errors, jump to D3.1 first** — those have specific recipes that pre-empt the generic routing table below. For everything else (JS Runtime, Network\u002FAPI, React, etc.), use the routing table:\n\n| Error location \u002F category | Action |\n|---|---|\n| `app\u002F` screen file, `_layout.tsx`, route segment | Inline edit via `Edit` tool |\n| `src\u002Fcomponents\u002F` | Inline edit via `Edit` tool |\n| `src\u002Fhooks\u002F`, `src\u002Fservices\u002F` | Inline edit via `Edit` tool |\n| `src\u002Fgenerated\u002F` | **Do not edit.** Hand off service\u002Fmodel repair to the owning data-source skill using CLI refresh; `npm run generate-schemas` only regenerates the runtime connector map. Do not re-add an intentionally retired source. |\n| Dataverse schema (column\u002Ftable missing) | Run D2's read-only Dataverse diagnostic sequence first. If live metadata\u002Fgenerated artifacts confirm the schema or service is missing, **hand off** to `\u002Fadd-dataverse`. Do not mutate Dataverse or edit generated files from `\u002Fdebug-app`. |\n| Auth \u002F MSAL (`AADSTS65001`, `AADSTS50011`) | **Hand-off:** route user to the Power Apps Wrap page via `\u002Fset-app-registration-native`. Do not auto-edit registrations. |\n| Connection \u002F connector reference missing | **Hand-off:** route user to `\u002Flist-connections` or `\u002Fadd-connector`. |\n| Confirmed defect inside `@microsoft\u002Fpower-apps-native-*` | **Do not fix in the customer project.** Emit the package-defect report below and route to `\u002Freport-issue`. This route takes precedence over native, import\u002Fbundle, and unrecognized-error recipes. |\n| Native module, `app.config.js`, `app.plugin.js`, `Podfile`, `build.gradle` | **Inform the user.** Do NOT auto-edit native config — print the error + suggested action and skip to next issue. |\n| Unrecognized error pattern | **Best-effort autonomous fix** — see D3.2 below. The skill attempts a single named hypothesis instead of stopping; the existing 2-attempt escalation rule is the safety net. |\n\nPDF\u002Fpen\u002Fgeolocation-specific routing:\n- `INVALID_URL` for PDF viewer input is an inline screen\u002Fwrapper fix. Allow `https:\u002F\u002F` and non-empty `file:\u002F\u002F` inputs with viewer 0.2.9+. Never add support for `content:\u002F\u002F`, `blob:`, or `http:\u002F\u002F` in the native viewer path.\n- A generated PDF local `file:\u002F\u002F` URI may be opened by native PDF viewer 0.2.9+.\n- `NATIVE_MODULE_MISSING` for PDF viewer or pen input means the native extension is not in the running build. Do not install packages or edit native config from debug; route to `\u002Fadd-native pdf-viewer` or `\u002Fadd-native pen-input` to verify wrapper\u002Fpackage state, then tell the user a native rebuild\u002Ftemplate update is needed if the package is absent from the app build.\n- For `geolocation`, debug the actual failure dimension: can tracking start (`startTracking`, permissions, native module), are rows reaching Dataverse (default `msdyn_locationrecords` exists, native upload\u002Fauth errors, no JS upload path), and does behavior match the user expectation (background, restart persistence, breadcrumb\u002Froute continuity). Fix visible screen handling inline; if the native module\u002Ftable is missing, block use and route to the relevant geolocation setup path, not `\u002Fadd-dataverse`.\n- `USER_CANCELLED` from pen input is not a bug unless the screen renders it as an error. Inline fix screens that show cancellation as failure.\n- Dataverse artifact writes are local app fixes only when the schema\u002Fservice already exists. If File\u002FImage columns are missing, route to `\u002Fadd-dataverse`.\n\nFor inline edits, keep the change minimal and surgical. Do not refactor surrounding code, rename symbols, or change component contracts.\n\nFor a confirmed first-party native package defect, do not append a successful fix entry. Pass this report through the persistence redaction gate, append it to `.powernative\u002Fdebug-app\u002Funresolved.md`, clean up injected traces, and stop the loop so `\u002Freport-issue` can run:\n\n```text\nConfirmed first-party native package defect — no customer-project workaround applied\nPackage: \u003C@microsoft\u002Fpower-apps-native-*>\nDeclared\u002Fresolved version: \u003Cdeclared> \u002F \u003Cresolved>\nPlatform: \u003Cios|android>\nReproduction: \u003Cminimal sanitized steps>\nExpected: \u003Cbounded behavior>\nActual: \u003Cbounded error\u002Fstatus>\nOwnership evidence: \u003Cwhy the documented caller contract is satisfied and the failure is package-internal>\nNext step: \u002Freport-issue \"\u003Cpackage>: \u003Csanitized summary>\"\n```\n\nAppend to `.powernative\u002Fdebug-app\u002Ffixes.md`:\n```\n[\u003CHH:MM:SS>] \u003Ccategory> — \u003Cfile>:\u003Cline> — \u003Cone-line description of fix>\n```\n\n#### D3.1 Bundle \u002F transform error fix recipes (Import \u002F Bundle category)\n\nThese recipes apply to errors classified as \"Import \u002F Bundle\" in Step B. They are read from the persisted `.powernative` Metro log. Each recipe is opinionated: take the action listed if its precondition matches, otherwise fall through to the next.\n\nBefore applying any recipe, run the first-party native package ownership gate when the cited source\u002Fimporter or failed internal import is under `node_modules\u002F@microsoft\u002Fpower-apps-native-*`. A confirmed package-owned defect routes to `\u002Freport-issue`; never repair it with a resolver alias, copied source, patch, postinstall rewrite, or replacement dependency.\n\n| Error pattern | Precondition | Action |\n|---|---|---|\n| `SyntaxError: \u003Cfile>:\u003Cline>:\u003Ccol>` in `app\u002F`, `src\u002Fcomponents\u002F`, `src\u002Fhooks\u002F`, `src\u002Fservices\u002F` | The cited line is in editable user code (NOT `src\u002Fgenerated\u002F`, NOT `node_modules\u002F`) | `Read` the file around the cited line (±10 lines), identify the syntactic issue (unclosed JSX tag, missing closing brace\u002Fparen, stray comma, missing `from` in import, unterminated string, missing semicolon between statements), apply a single minimal `Edit`. Do NOT reformat surrounding code. |\n| `SyntaxError` in `src\u002Fgenerated\u002F` | Cited file is under `src\u002Fgenerated\u002F` | **Do not edit.** For `connectorSchemas.ts`, regenerate the runtime map. For services\u002Fmodels, resolve the existing registration and hand off to `\u002Fadd-connector` or `\u002Fadd-dataverse` with `--refresh --data-source-name \"\u003Cregistered-name>\"`, the absolute app root, and approved scope for targeted CLI refresh and validation. Check the approved plan first: a removed source needs consumer cleanup through `\u002Fedit-app`, not re-registration. Missing\u002Fambiguous registrations block refresh; do not fall back to addition. |\n| `Unable to resolve module \u003Cname>` from `\u003Cimporter>` | `\u003Cname>` starts with `.` or `..` (relative import) | `Glob` the importer's directory for files matching `\u003Cname>` with any extension (`.ts`, `.tsx`, `.js`, `.jsx`, `.json`). If found with a different extension → fix the import to drop the extension OR match the actual one. If found with a typo (Levenshtein ≤ 2) → fix the typo. If not found at all → the file genuinely doesn't exist; surface to user and ask whether to create it or remove the import. |\n| `Unable to resolve module \u003Cname>` | `\u003Cname>` is a bare package AND not present in `package.json` `dependencies` \u002F `devDependencies` | Follow [`shared\u002Freferences\u002Fjavascript-dependency-planning.md`](${PLUGIN_ROOT}\u002Fshared\u002Freferences\u002Fjavascript-dependency-planning.md) to classify the published package by contents, not its name. If native-bound and absent from the template, report that a template\u002Fruntime update is required. If verified pure JavaScript, ask consent for the exact version, install with `npm install --save-exact`, validate, and retry. Do NOT install without consent. |\n| `Unable to resolve module \u003Cname>` | `\u003Cname>` IS in `package.json` but the bundle still fails | Run the targeted startup inspection before blaming cache: compare locked\u002Finstalled versions and resolve the exact entry point. Restore only with approval when installation is broken; unsupported exports or native build mismatches need different remedies. |\n| `transform failed` referencing a babel plugin (e.g., `[BABEL] ... unknown plugin \"react-native-reanimated\u002Fplugin\"`) | Error references `babel.config.js` | **Hand-off.** `babel.config.js` is project config (same constraint that protects `app.config.js`). Print the cited plugin and suggested fix order (e.g., \"`react-native-reanimated\u002Fplugin` MUST be the LAST plugin in `babel.config.js` `plugins` array\"); skip to next issue. |\n| `transform failed` without a babel reference | Generic transform failure (often a TS feature Metro's transformer can't handle) | Read the cited file, look for syntax that requires a specific TS lib (e.g., decorators, top-level await). If the issue is a known-bad pattern, surface and ask before fixing. Otherwise hand-off. |\n| `predev` script failure (e.g., `npm run generate-schemas` errored before `expo start` ran) | Output shows failure before Metro started | Use startup diagnostics to identify the failed stage (installation, config, schema generation, or type-check). Do not assume a connector problem or edit `power.config.json` directly. |\n| `[BABEL] ... You're trying to use the @babel\u002Fplugin-X plugin twice` | Duplicate babel plugin entries | **Hand-off** for the same reason as above — `babel.config.js` is project config. Surface the duplicate; let the user dedupe. |\n\nAfter applying any inline edit (rows 1, 3, 4 above), Metro auto-detects the file save and re-bundles. Skip directly to D4 — do NOT manually trigger a reload. The verify step picks up Metro's `Bundling complete` (or the next error block) automatically.\n\nAppend to `.powernative\u002Fdebug-app\u002Ffixes.md`:\n```\n[\u003CHH:MM:SS>] Import\u002FBundle — \u003Cfile>:\u003Cline> — \u003Crecipe applied>\n```\n\n#### D3.2 Best-effort fix recipe for uncategorized errors\n\nWhen an error falls through every row of Step B's classification table AND every row of D3.1's bundle recipes, the skill still attempts a fix instead of stopping. The discipline below keeps best-effort from degrading into wild guessing.\n\n**Step 1 — Locate the cite.** Try in order; stop at the first that yields a file:line in editable user code:\n\n1. **Stack trace top user-frame** — walk the stack from the top, skip frames in `node_modules\u002F`, `src\u002Fgenerated\u002F`, and React\u002FHermes internals (`react-native\u002F`, `hermes-engine\u002F`, `metro\u002F`). First remaining frame is the cite.\n2. **Multi-line bundle block** — see Step B's parsing note (file:line on the first non-banner line).\n3. **Verbatim grep across the repo** — `Grep` for the exact error message text (or its most distinctive 4–6 word phrase, with regex special chars escaped) across `app\u002F`, `src\u002Fcomponents\u002F`, `src\u002Fhooks\u002F`, `src\u002Fservices\u002F`. A match at a `throw new Error('...')` site IS the cite.\n4. **Module + symbol grep** — if the error mentions a function or component name (e.g., `useFoo is not a function`), `Grep` for the symbol; the unique declaration site is the cite.\n\nIf no cite can be located by step 4: log a structured note to `.powernative\u002Fdebug-app\u002Funresolved.md` (minimal sanitized error summary + which lookup attempts ran), surface to the user, advance to next issue. **Do not guess at a file.** Best-effort still requires a target.\n\n**Step 2 — Enrich understanding (do not skip).**\n\n- If the error contains a Microsoft-stack token (`AADSTS\\d+`, `Dataverse`, `Power Platform`, `MSAL`, `Entra`, `Graph API`): first run D2's project\u002Freference\u002Fread-only diagnostic sequence, then query `mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search` with the exact code or token when behavior remains uncertain.\n- If the error concerns Expo, Expo Router, an Expo SDK module, or React Native behavior: inspect the installed version and local package documentation, then use targeted `WebFetch` against `https:\u002F\u002Fdocs.expo.dev\u002F`. Do not use Microsoft Learn for these errors.\n- If the error involves `@microsoft\u002Fpower-apps-native-*`, run D2's first-party native package ownership gate. A confirmed package-owned defect is not eligible for best-effort editing.\n- Read the cited file ±15 lines for surrounding context. Note recent imports, the function signature, and any nearby `try\u002Fcatch` or `useEffect` deps.\n- If the error mentions a third-party module (anything in `node_modules\u002F` from the stack), one targeted `WebFetch` against the module's npm page or GitHub README is acceptable; do NOT do open-ended web searches in the loop.\n\n**Step 3 — Form ONE named hypothesis.** Write it to `.powernative\u002Fdebug-app\u002Ffixes.md` BEFORE editing, in this format:\n\n```\n[\u003CHH:MM:SS>] Hypothesis (best-effort) — \u003Cfile>:\u003Cline> — \u003Cone-sentence theory>\n   Evidence: \u003Csanitized error code\u002Fsummary + what in the cited code led you here>\n  Planned change: \u003Cwhat you'll edit, in 1 line>\n```\n\nExamples of acceptable hypotheses:\n- \"`\u003CUserAvatar>` reads `user.profile.image` but `user` can be undefined during the first render — add a null guard\"\n- \"The `useEffect` at line 42 captures a stale `userId` because `userId` isn't in its deps array\"\n- \"`AsyncStorage.getItem` returns null for missing keys, but the caller assumes JSON-parseable string\"\n\nNOT acceptable (refuse to apply, escalate instead):\n- \"Something is wrong with state management\" (vague — no specific change implied)\n- \"Try wrapping in try\u002Fcatch\" (mask, not fix — silently swallows the real bug)\n- \"Maybe also update X, Y, and Z\" (multi-armed — violates one-fix-at-a-time)\n\n**Step 4 — Apply a single minimal edit.** One `Edit` call, smallest possible diff that implements the planned change. Do NOT change unrelated code, rename symbols, or refactor surrounding structure. Re-confirm the file path is in editable user code (NOT under `src\u002Fgenerated\u002F`, `node_modules\u002F`, or any path in the Constraints section's protected list).\n\n**Step 5 — Defer to D4 verify.** The existing verify cycle (type-check + reload + re-poll) decides whether the hypothesis was right. Do NOT preemptively try a second hypothesis \"just in case.\"\n\n**Step 6 — On verify failure, ONE alternative is allowed.** If D4 shows the same error reappearing, you may form ONE alternative hypothesis (this counts as fix attempt #2 against the original error). If THAT also fails, the existing Escalation rule trips and the skill stops on this error — surface to the user, append to `unresolved.md`, advance to the next issue. Do NOT chain a third hypothesis.\n\n**Constraint reminder for best-effort mode (no exceptions):**\n- Never edit `src\u002Fgenerated\u002F`, `node_modules\u002F`, `app.config.js`, `app.plugin.js`, `babel.config.js`, `metro.config.js`, `Podfile`, `build.gradle`, `gradle.properties`, `power.config.json`, `auth.config.json`.\n- Never run `npm install \u003Cpkg>`, `npm uninstall \u003Cpkg>`, `npx expo install \u003Cpkg>`, or any command that mutates `package.json` \u002F `package-lock.json` without explicit user consent (same gate as D3.1's bare-package recipe).\n- Never restart Metro from a runtime repair recipe or run `expo prebuild`.\n  Only the separately approved, bounded startup retry in the startup reference\n  may start\u002Frestart the selected app's Metro session.\n- If the only plausible hypothesis violates one of these constraints, treat the error as out-of-scope: hand-off to the user with a one-line explanation and advance.\n\n#### D4. Verify the fix\n\nAfter the fix is applied:\n\n1. **Type-check:**\n   ```bash\n   npm run type-check\n   ```\n   If TS errors exist, fix them before continuing. Do not advance until type-check exits 0.\n\n2. **Wait for Metro to re-bundle (Import\u002FBundle fix only):**\n   For inline edits applied via D3.1, Metro auto-watches the file and triggers a re-bundle on save. Re-run the Step A cursored tail procedure for a bounded set of checks, watching for one of:\n   - `Bundling complete` \u002F `iOS Bundled` \u002F `Android Bundled` → success, proceed to step 4.\n   - A new bundle error block (different file:line, or different message) → treat as a NEW issue and return to Step B.\n   - Same error repeats → the fix didn't take. Treat as fix attempt #2 against the same error (Escalation rule applies after 2).\n   - 30s elapsed with no bundling activity → Metro may be paused\u002Fwedged; surface to user, do NOT auto-restart Metro (Constraints).\n\n3. **Reload the app (all other fixes — JS Runtime, Network\u002FAPI, React, etc.):**\n   Fast Refresh should apply most inline edits. If no new bundle\u002Fruntime activity appears, instruct the user:\n   > \"Please reload the app from the native dev-client menu, then trigger the workflow again.\"\n\n   After the user confirms, run the Step A cursored tail procedure to check only new output.\n\n4. **Confirm the fix via persisted output.** If the previous error pattern is absent from newly appended log bytes and no new errors appear, the fix held. If any `[INJECTED-TRACE]` lines are relevant, use them to confirm the data path is healthy. After confirming, clean up injected logs (Phase 0.5.5).\n\n5. **Reset clean-cycle counter to 0** and return to Step A.\n\n---\n\n## Escalation\n\nIf the same error persists after **2 fix attempts**, stop and report:\n\n```\n⚠ Unresolved after 2 attempts: \u003Cerror summary>\n  File:           \u003Cpath>\n   Log:            \u003Csanitized bounded error summary>\n  Last fix tried: \u003Cone-line description>\n  Suggested next step: \u003Cmanual action>\n```\n\nPass the block through the persistence redaction gate, append only the verifier's output to `.powernative\u002Fdebug-app\u002Funresolved.md`, and clean up any `[INJECTED-TRACE]` logs before exiting (Phase 0.5.5 procedure).\n\nDo NOT attempt a third automated fix for the same error. Wait for user guidance.\n\n---\n\n## Constraints\n\n- **Never fix native config files** (`app.config.js`, `app.plugin.js`, `Podfile`, `build.gradle`, `gradle.properties`) — report the error to the user with the exact line and a suggested manual action.\n- **Startup restoration is not an upgrade.** Only the approved same-lock restore\n  and bounded Metro retry in the startup reference are allowed exceptions.\n  No blind upgrades, lockfile deletion, Node installation, or host\u002FMSAL patches.\n- **Never modify `src\u002Fgenerated\u002F`** — these files are auto-generated. The owning\n  data-source skill uses CLI add\u002Frefresh\u002Fremove for models\u002Fservices and config;\n  `npm run generate-schemas` only rebuilds the runtime map afterward. Preserve\n  the approved source inventory; do not resurrect retired sources during repair.\n- **Never patch or fork first-party native packages in a customer project** — for confirmed defects in `@microsoft\u002Fpower-apps-native-*`, do not edit `node_modules\u002F`, generate `patch-package` artifacts or postinstall rewrites, vendor\u002Fcopy package source, generate or install a fork, replace the dependency with a git\u002Ftarball\u002Flocal path, or add resolver aliases\u002Fshims that shadow the package. Route the sanitized evidence to `\u002Freport-issue`.\n- **Dataverse diagnosis is read-only** — `\u002Fdebug-app` may resolve the configured environment and issue bounded Dataverse `GET` requests through the bundled scripts. It must never perform metadata\u002Fdata writes, publish, seed records, intentionally trigger throttling, invalidate tokens, switch CLI accounts, or replace generated services with direct HTTP.\n- **Do not ask the user about errors mid-cycle** — investigate autonomously using the tools above. Only surface to the user when:\n  1. The fix requires a native config change.\n  2. The fix requires a tenant admin action (e.g., AAD consent).\n  3. You have attempted a fix twice and the same error persists (escalation).\n  4. The fix routes to another skill (`\u002Fadd-dataverse`, `\u002Fset-app-registration-native`, `\u002Flist-connections`).\n  5. Startup restoration\u002Frestart needs explicit approval or device verification.\n- **One fix at a time** — fully resolve one issue (including type-check + reload + log verification) before starting the next.\n- **Always clean up injected logs** — any `\u002F\u002F [INJECTED-TRACE]` line added during a session MUST be removed before the session ends, even if the symptom is `pending` or `flagged`. Use the Phase 0.5.5 `find` scan across editable `app\u002F` and `src\u002F` files, excluding `src\u002Fgenerated\u002F`, to find them.\n- **Preserve existing behavior** — fixes must be minimal and surgical. Do not refactor, rename, or change component contracts as a side effect of a bug fix.\n- **Bounded polling** — do not busy-loop. Every poll advances a persisted byte cursor and each cycle processes at most four 256 KiB chunks.\n- **Log every action** — before each tool call, print a one-line description of what you're about to do and why, so the user can follow along.\n\n---\n\n## Failure Modes\n\n| Symptom | Likely cause | Fix |\n|---|---|---|\n| Phase 0 reports `not-started` or `stopped` | No live `.powernative` Metro log exists | Run the bounded startup diagnosis; offer approved restoration\u002Fretry only when supported by evidence |\n| Phase 0 sees recent failure lines | Expo\u002FMetro exited during startup or runtime | If no live session remains, correlate the failed launch in startup diagnostics; otherwise use the runtime baseline\u002Fsupersession check before fixing |\n| Phase 0 reports \"Metro running but no app connected\" | Device\u002Fplayer\u002FQR\u002Fnetwork issue, or the user has not opened the app | Diagnose the opening symptom without reinstalling by default; require user retry and fresh evidence |\n| Loop appears stuck | Fix taking longer than expected (e.g., type-check on large project) | Wait — log lines should still print as the fix runs. Type `stop` to exit. |\n| Loop exits with \"iteration cap reached\" | Symptom is intermittent OR a fix is regressing on every reload | Inspect the last 3 entries in `fixes.md` for circularity; re-run with a more specific symptom or fix manually |\n| Same error keeps recurring after fix | Fast Refresh didn't apply the change, or the fix targeted the wrong file | Verify with `git status`; reload from the native dev-client menu; re-run |\n| Same error persists after fix AND `git status` shows the change saved AND type-check is clean | Stale Metro transform cache | Ask the user to stop Metro, rerun `npm run dev -- --clear`, reload, then rerun `\u002Fdebug-app` |\n| Escalation triggered immediately | Error pattern is in a category we hand-off (auth, schema, native) | Take the suggested manual action, then re-run `\u002Fdebug-app` |\n| `.powernative\u002Fdebug-app\u002Ffixes.md` not appearing | Phase 0 didn't run \u002F state directory not created | Run `mkdir -p .powernative\u002Fdebug-app` manually, re-run skill |\n| \"App is running cleanly\" but the user still sees the problem | Symptom-driven mode was not used — log polling alone is blind to silent failures | Re-run as `\u002Fdebug-app \"\u003Cdescribe what you see>\"` to trigger Phase 0.5 (console.log injection) |\n| Phase 0.5 reports `screen=unknown` | Symptom text didn't match any route filename | Re-run with a more specific symptom (`\u002Fdebug-app \"todos screen empty\"` not `\"data is broken\"`), OR navigate to the broken screen first then re-run |\n| No `[TRACE` lines after reload | Metro cached the old bundle | Ask the user to stop Metro, rerun `npm run dev -- --clear`, then reload the app |\n| `[INJECTED-TRACE]` lines left in code after session | Cleanup step was skipped | Run the Phase 0.5.5 `find` scan and remove each matching line |\n\n---\n\n## Notes\n\n- **Designed to be re-run** — every invocation is idempotent. `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` advances past previously seen bytes and resets safely when a new Metro session or rotated log is detected.\n- **Honest about limits** — startup diagnosis can precede a running app, but runtime\n  monitoring is still a bounded foreground loop. It does not wake an idle agent\n  when an unrelated terminal fails. Type `stop` to leave the monitor.\n- **No specialist agents** — upstream's `app-debugger.agent.md` delegates to `screen-builder`, `component-author`, `api-integration`, `dataverse-data-modeler` agents. We don't have all those agents in this plugin, so this skill fixes inline OR routes to skills (`\u002Fadd-dataverse`, `\u002Fset-app-registration-native`, `\u002Flist-connections`, `\u002Fadd-connector`). Behavior is equivalent for the categories we cover.\n- **Host diagnostics caveat** — host-prefixed diagnostics (`[PAHost]`, `[bridge]`, `[AuthProvider]`, etc.) are expected in dev-player sessions and should be treated as first-class telemetry. If these lines are absent in non-dev-player builds, that is expected and not itself a bug.\n- **Upstream parity table:**\n\n  | Behavior | Upstream | This skill |\n  |---|---|---|\n   | Log-driven monitor loop | yes | yes — project-local sanitized Metro log is authoritative; host terminal APIs are optional only |\n  | 8-category classification | yes | yes |\n  | Verification cycle (type-check + reload + re-poll) | yes | yes |\n  | Escalation after 2 attempts | yes | yes |\n   | Bounded polling | yes | yes — durable byte cursor, bounded chunks |\n  | Configurable consecutive-clean exit | fixed at 3 | yes — default 3, configurable with `--cycles`, and gated on symptom resolution |\n  | Specialist agent delegation | yes | replaced with skill routing |\n   | Working-dir audit log | no | yes (additional — `.powernative\u002Fdebug-app\u002Ffixes.md`, `injected-logs.md`) |\n  | MS Learn fallback for unknown errors | no | yes (additional) |\n   | Persisted Metro\u002Fapp log source (bundler errors + Hermes console + HTTP request log) | no | yes — survives host restarts; no MCP fallback |\n  | Bundle \u002F transform error fix recipes (D3.1) | no | yes (additional) |\n  | Bundle-aware verify (poll Metro for `Bundling complete`) | no | yes (additional) |\n  | Best-effort autonomous fix for uncategorized errors (D3.2) | no | yes (additional) |\n  | Symptom-driven mode — console.log injection + terminal read + data-path walk | no | yes (additional — catches silent failures invisible to log polling; injects `[INJECTED-TRACE]` logs, reads terminal, cleans up logs after root cause found) |\n","> **Plugin check**: Run `node \"${PLUGIN_ROOT}\u002Fscripts\u002Fcheck-version.js\"` - if it outputs a message, show it to the user before proceeding.\n\n**? Shared instructions: [shared-instructions.md](${PLUGIN_ROOT}\u002Fshared\u002Fshared-instructions.md)** — read first.\n\nStartup diagnosis uses the targeted compatibility inspection below instead of\nthe shared blanket version check; missing dependencies must not prevent diagnosis.\nIt does not check for updates. Explicit startup repair\u002Frestart approval overrides\nshared auto-proceed\u002Fdefault-answer guidance.\n\n# Debug App — Monitor & Fix\n\nMonitor the running app through the project-local `.powernative\u002Fmetro-logs\u002F` files written by `metro.config.js`, detect runtime and bundle errors, and fix them autonomously by editing the affected files (or routing to the right skill when the fix belongs in a domain like Dataverse schema or auth registration). For silent failures, inject temporary `console.log` statements at data-path boundaries, read only newly appended log bytes, then clean the traces after the root cause is fixed. Modeled on the upstream `app-debugger.agent.md` pattern — foreground loop, bounded polling, configurable clean-check\u002Ftimeout exits, and optional watch-only operation.\n\nWhen setup\u002Fstartup or device opening is failing, first execute\n[startup-diagnostics.md](references\u002Fstartup-diagnostics.md). This bounded phase\ncan run without Metro logs or a loaded app and returns to the runtime path only\nwhen its prerequisites actually hold. Running `npm run dev` alone does not\nactivate an agent, and this skill installs no background watcher.\n\n> **Dev-client limitation:** the standalone dev client sends app\u002Fruntime logs, React errors, host diagnostics, and Metro bundler output through Metro. The template's `metro.config.js` writes Metro terminal output and HTTP bundle failures into `.powernative\u002Fmetro-logs\u002F`; there is no separate device log source. Host diagnostics include strings such as `[AuthProvider] MSAL init failed:`, `[bridge] fetch THREW for`, `[bridge] HTTP \u003Cstatus> for`, `[addAadAppToConnectionAcl] failed HTTP \u003Cstatus> for connection`, `[useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required`, and `[PAHost][ErrorBoundary] Unhandled JS error:`.\n\n## Subcommands (parsed from `$ARGUMENTS`)\n\n| Form | Behavior |\n|---|---|\n| `\u002Fdebug-app` (no args) | **Default — project-log-driven mode.** Run Phase 0, discover valid project-local Metro sessions, select automatically when one is live or ask when several are live, then monitor the selected log. No host terminal ID is required. |\n| `\u002Fdebug-app \"\u003Csymptom text>\"` | **Symptom-driven mode** (recommended when there's a user-visible problem). Free-text symptom such as `\"todos not appearing on home screen\"`, `\"login button does nothing\"`, `\"list empty after refresh\"`. Run Phase 0 → Phase 0.5 (parse symptom → ask the user to reproduce\u002Fnavigate → walk the likely data path from terminal traces) → enter monitor loop. Catches silent failures (empty lists, blank screens, swallowed errors) that pure log polling misses. |\n| `\u002Fdebug-app startup [\"\u003Csymptom text>\"] [--tunnel] [--tunnel-tenant \u003Ctenant-guid>]` | **Startup-only diagnosis.** Inspect install\u002Fstartup\u002FQR failures, offer bounded approved repair, and verify the original symptom. Preserve explicitly selected authenticated tunnel options for an approved retry. Return without the runtime monitor; also used by creation-time failure handoffs. |\n| `\u002Fdebug-app status` | Discover all project-local Metro logs and print each valid session's project, platform, PID, port, start time, and log path. Mark the session referenced by the saved cursor when present, then print fixes and unresolved errors. Do NOT ask for a selection or enter the loop. |\n| `\u002Fdebug-app stop` | Stop only the foreground debug loop and preserve `.powernative\u002Fdebug-app\u002F` state. It does not stop Metro; the user owns the `npm run dev` process. |\n| `\u002Fdebug-app version` | Print the installed `mobile-app` plugin name and version from `${PLUGIN_ROOT}\u002F.plugin\u002Fplugin.json`, then exit. |\n\n### Monitoring options\n\nOptions may follow the default command, a symptom, or `status`:\n\n| Option | Meaning | Default |\n|---|---|---|\n| `--working-dir \u003Cpath>` | App root containing `package.json`. Startup diagnosis accepts missing Metro config or dependencies; runtime monitoring requires a configured, live Metro session. Relative paths resolve from the current shell directory. | Current shell directory |\n| `--port \u003C1-65535>` | Monitor only the valid Metro session on this port. | Any port |\n| `--platform \u003Cios\\|android>` | Consider only sessions whose recent log identifies this platform. | Any platform |\n| `--cycles \u003C1-50>` | Exit after this many consecutive clean observation intervals. | `3` |\n| `--timeout \u003Cduration>` | Maximum wall-clock monitoring time. Accept `30s`–`60m` using `s`, `m`, or `h`. | `5m` |\n| `--no-fix` | Inspect\u002Fwatch-only: never edit project source\u002Fconfig, inject traces, install, regenerate, start\u002Fstop\u002Frestart Metro, open the device app, or invoke a mutating handoff. Debug cursor\u002Faudit\u002Fhealth state may still advance. | Fix enabled |\n| `--tunnel` | Startup only: preserve `--tunnel` when an approved retry invokes `npm run dev`. Never switch a LAN launch to a tunnel automatically. | Disabled |\n| `--tunnel-tenant \u003Ctenant-guid>` | Startup only: preserve the Entra tenant used to authenticate the dev tunnel. Requires `--tunnel`. | Active Azure CLI tenant |\n\nExamples:\n\n```text\n\u002Fdebug-app --port 8082 --platform ios\n\u002Fdebug-app \"orders screen is empty\" --cycles 10 --timeout 15m\n\u002Fdebug-app --no-fix --timeout 30m\n\u002Fdebug-app status --platform android\n\u002Fdebug-app status --working-dir ..\u002Fmy-mobile-app\n\u002Fdebug-app startup \"npm run dev exits before the QR appears\"\n\u002Fdebug-app startup \"tunnel launch fails\" --tunnel --tunnel-tenant 11111111-1111-1111-1111-111111111111\n\u002Fdebug-app \"QR won't open the app\" --no-fix\n```\n\n**Argument parsing:**\n\n1. Parse quoted text as one symptom value and parse recognized flags wherever they appear.\n2. The first reserved token (`startup`, `status`, `stop`, `help`, `--help`, `-h`, `version`, `--version`) selects the subcommand. `stop`, help, and version do not accept monitoring options. `status` accepts only `--working-dir`, `--port`, and `--platform`; reject symptoms, `--cycles`, `--timeout`, `--no-fix`, and tunnel options because it does not enter the loop. `startup` accepts one symptom and all options except `--cycles`, because it never enters the runtime monitor. Reject `--tunnel` and `--tunnel-tenant` on every other subcommand.\n3. After removing recognized options and their values, any remaining non-reserved text is the symptom and enables symptom mode.\n4. Reject unknown flags, duplicate flags, missing values, invalid numbers, unsupported platforms, or more than one free-text symptom. Print the valid forms and exit without monitoring.\n5. Normalize `platform` to lowercase. Convert `timeout` to `timeoutSeconds`; require `30 \u003C= timeoutSeconds \u003C= 3600`. Validate `--tunnel-tenant` as a GUID and require `--tunnel`; never derive either option from symptom text or untrusted diagnostic context. Resolve `workingDir` from explicit `--working-dir`, or inherit the caller's absolute root; use the current shell directory only for a direct invocation without either. Reject conflicting explicit\u002Finherited roots and do not search parent directories. Require `package.json` at that root; missing `metro.config.js`, configuration, or installed dependencies routes to startup inspection, not runtime monitoring. An unreadable\u002Fmalformed manifest is a blocked diagnostic, not permission to initialize a new app. Every shell call must explicitly enter the selected absolute `workingDir`; every relative project path and command below runs from that directory.\n6. Initialize:\n   ```text\n   workingDir=\u003Cabsolute app root>\n   portFilter=\u003Cnumber|none>\n   platformFilter=\u003Cios|android|none>\n   targetCleanCycles=\u003Cnumber, default 3>\n   timeoutSeconds=\u003Cnumber, default 300>\n   noFix=\u003Ctrue|false, default false>\n   devArgs=\u003C[]|[\"--tunnel\"]|[\"--tunnel\",\"--tunnel-tenant\",\"\u003Ctenant-guid>\"]>\n   monitorStartedAt=\u003Ccurrent ISO timestamp>\n   ```\n\nFor `help` \u002F `--help` \u002F `-h`, print the subcommands and monitoring-options tables and exit.\n\nSet `startupStartedAt` only when entering startup diagnostics. Its timeout and\nattempt budget include caller-supplied prior attempts. After a verified live app\ncontinues into monitoring, reset `monitorStartedAt` for that separate bounded loop.\n\n**Early-return subcommands:**\n\n- `stop`: if received while this foreground loop owns the conversation, clean up any injected traces using Phase 0.5.5 and exit at the next safe boundary. For a standalone `stop` invocation, report that no loop is active. Never stop Metro or delete `.powernative\u002Fdebug-app\u002F` state.\n- `version` \u002F `--version`: read `${PLUGIN_ROOT}\u002F.plugin\u002Fplugin.json`, print `\u003Cname> \u003Cversion>`, and exit without resolving a project or writing state. If the manifest is missing or malformed, report that the plugin version is unavailable and exit.\n- `status`: validate `workingDir`, then execute only Phase 0.0 discovery through the status branch below. Do not run project preflight, create state files, ask for a session, initialize a baseline, or enter the monitor loop.\n\nIf `stop` arrives during startup diagnosis, cancel upcoming diagnostic\u002Frepair\nsteps and report any in-flight approved command accurately. Do not automatically\nkill an installation or Metro process, or claim a partly restored install is complete.\n\n**Tip — \"play around then debug\":** Metro persists recent app output in `.powernative\u002Fmetro-logs\u002F` even across chat\u002Feditor restarts. If something weird just happened, keep using the app normally, then run `\u002Fdebug-app` or `\u002Fdebug-app \"\u003Cwhat you saw>\"`. The first cycle reads the latest persisted log window; subsequent cycles read only bytes appended after the saved cursor.\n\n## Core Principles\n\n- **Foreground autonomous loop** — Once started, this skill owns the conversation until `targetCleanCycles` consecutive clean polls confirm the app is healthy, `timeoutSeconds` elapses, the user types `stop`, or the escalation rule trips. **Do not run other skills concurrently** — they'll queue behind the loop.\n- **Watch-only means no project mutation** — With `--no-fix`, do not edit project source\u002Fconfiguration, inject diagnostic logs, install packages, regenerate schemas, switch accounts, or invoke a mutating skill. Continue to advance `.powernative\u002Fdebug-app\u002F` cursor\u002Faudit\u002Fhealth state, classify errors, and provide the fix\u002Fhandoff that would have been used.\n- **Runtime monitoring requires a live app; startup diagnosis does not.** First\n  classify install\u002Fstartup\u002Fopening failures through the bounded startup reference.\n  Do not enter the runtime monitor or claim healthy runtime without a verified\n  live native session.\n- **Native-only runtime target** — The app must be loaded in a native dev client on a device or simulator; `.powernative\u002Fmetro-logs\u002F` is the authoritative log source for that native session.\n- **No web or direct Metro probes** — Do not use React Native Web, browser automation, `curl`, `fetch`, `WebFetch`, or any direct request to a Metro\u002Flocalhost endpoint for runtime diagnosis. Read only the `.powernative` log and source files.\n- **No screen-by-screen verification** — Do not crawl routes or validate every screen. In symptom mode, focus only on the user-reported workflow and the terminal\u002Fsource evidence needed to diagnose it.\n- **One fix at a time** — Fully resolve one issue (context → fix → type-check → reload → re-poll) before starting the next. No batching.\n- **Working-dir state** — Debug audit state lives in `.powernative\u002Fdebug-app\u002F`: `fixes.md`, `unresolved.md`, `injected-logs.md`, `health.json`, and `metro-cursor.json`. Metro logs live in the already-ignored `.powernative\u002Fmetro-logs\u002F`. Both survive chat\u002Feditor restarts without binding state to a specific agent host.\n- **Defense-in-depth redaction** — The Metro logger removes credential-like lines before writing `.powernative`, but `\u002Fdebug-app` must independently minimize and sanitize every value before persisting it to `.powernative\u002Fdebug-app\u002F`. Never copy raw response bodies, record objects, tokens, headers, trace payloads, or absolute home-directory paths into debugger state.\n- **The port is the log identity** — the dev-server port is the number the QR encodes, the device dials, and this skill verifies. Liveness is a socket probe (does the log's PID still hold that port?), never terminal scrollback. A `port-taken` status means the log belongs to a dead session and must not be diagnosed.\n- **Never fix history** — the log is a record of the past, so an error in it is not proof of a current problem. Errors found in the baseline window must pass the Phase 0.2.1 supersession check before any code is edited. Editing working code to chase an already-resolved error is a worse outcome than reporting nothing.\n- **First-party native packages are an immutable boundary** — a frame under `node_modules\u002F@microsoft\u002Fpower-apps-native-*` is evidence, not proof, of package ownership. First rule out broken installation, Node\u002Fnative compatibility, invalid app inputs, unsupported configuration, and misuse of the package's documented API. Once the evidence confirms a defect inside an installed `@microsoft\u002Fpower-apps-native-*` package, do not apply a customer-project workaround: do not edit `node_modules\u002F`, create a `patch-package` patch or postinstall rewrite, vendor or fork package source, redirect the package through Metro\u002FBabel\u002FTypeScript aliases, or replace its dependency with a git, tarball, or local fork. Record a sanitized package-defect report and route the user to `\u002Freport-issue`. Host\u002FMSAL source patches remain prohibited; approved same-lock installation restoration is not a source patch or upgrade.\n- **Host terminal APIs are optional only** — Never ask for or persist a terminal\n  ID. During runtime monitoring, available host output is only a convenience and\n  diagnosis still advances the authoritative `.powernative` cursor. Before a log\n  exists, the bounded startup phase may use the current failed command's sanitized\n  terminal output; it must not fabricate a cursor or treat that output as a live\n  runtime session.\n- **Context-first diagnosis** — Read `memory-bank.md` when present. Read `power.config.json` for environment, Dataverse, and connector context. Consult `native-app-plan.md` only when the failure concerns a planned screen, data model, connector, offline profile, or native capability; do not parse it for unrelated syntax\u002Fruntime errors.\n- **Reference resolution order** — For Dataverse\u002FPower Platform errors: read [skills\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md](${PLUGIN_ROOT}\u002Fskills\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md) first, inspect generated services\u002Fmodels and project context, then query `mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search` when behavior remains uncertain. For Expo\u002FExpo Router\u002FReact Native errors: inspect installed versions and project code first, then use targeted `WebFetch` against official `https:\u002F\u002Fdocs.expo.dev\u002F` documentation. Use package documentation next and general web search only as a last resort.\n\n## Workflow — Task List First\n\nBefore entering the monitor loop, write a task list and keep it up to date:\n\n```\n- [ ] Discover valid `.powernative` Metro sessions and select one when needed\n- [ ] If startup\u002Finstall\u002FQR failure or no live session: inspect and classify; repair only with approval; verify original symptom or return pending\u002Fblocked\n- [ ] Capture baseline log state from the selected session and save its byte cursor\n- [ ] (Symptom mode only) Phase 0.5: parse symptom → ask user to navigate → inject console.logs → read new log bytes → walk data path → clean up logs\n- [ ] Monitoring cycle 1: collect → classify → fix if needed\n- [ ] Monitoring cycle 2: collect → classify → fix if needed\n- [ ] Monitoring cycle 3: collect → classify → fix if needed\n   (add cycles as needed; after \u003CtargetCleanCycles> consecutive clean cycles, use the resolved\u002Fflagged\u002Fpending symptom outcome)\n- [ ] Fix: \u003Cerror summary> → \u003Cinline edit | skill route>  (one task per error found)\n```\n\nMark each cycle complete (clean OR fixed) before starting the next.\n\n---\n\n## Phase 0 — Startup Check\n\nBefore entering the loop:\n\n### 0.setup Startup\u002Fsetup diagnostic dispatch\n\nAfter the early-return subcommands, run\n[startup-diagnostics.md](references\u002Fstartup-diagnostics.md) when:\n\n- the subcommand is `startup`;\n- the supplied symptom concerns installation, `npm run dev`, Node\u002Fpackage\n  compatibility, startup before loading, or QR\u002Fdevice opening; or\n- Phase 0.0 finds no valid live session (not merely a mismatched port\u002Fplatform\n  filter when another session is live), or Phase 0.2 finds no connected client.\n\nFor a healthy live app with a runtime symptom, skip setup and use the existing\nruntime path. On `startup` or a creation handoff, return the structured startup\noutcome without entering the monitor. Otherwise a verified live app re-enters\nPhase 0.preflight, session discovery, and state initialization (0.1) before\nPhase 0.2; pending\u002Fblocked\u002Fcancelled returns without a green runtime result.\nRecord `startupOutcome` in invocation context so this return does not re-enter\nsetup just because the original symptom mentioned startup. If only installation\nor Metro startup is verified but no native app is connected, report runtime\nverification pending and return instead of repeatedly dispatching setup.\nNo unbounded redispatch: repeated setup failures consume the same attempt budget.\n\n### 0.preflight Read project context\n\nFollow the shared instructions before diagnosing logs:\n\nUse `workingDir` from argument parsing as `\u003Cworking_dir>` throughout this workflow. It is already validated as an app root; do not derive it again from a later phase or silently switch projects.\n\n1. If `\u003Cworking_dir>\u002Fmemory-bank.md` exists, read its Project facts, Power Platform context, Data model, Connectors, Screens, Native capabilities, and Build history. Do not create a memory bank from `\u002Fdebug-app`; absence is valid.\n2. Read `\u003Cworking_dir>\u002Fpower.config.json` when present. Capture `environmentId`, `databaseReferences`, and `connectionReferences`. `power.config.json` is the preferred environment source.\n3. Read `\u003Cworking_dir>\u002Fnative-app-plan.md` only when the supplied symptom or a classified error concerns a planned screen, Dataverse entity\u002Fcolumn, connector, offline behavior, navigation contract, or native capability. Treat the plan as intended design, not proof of live schema\u002Fruntime state.\n4. Inspect `src\u002Fgenerated\u002Fservices\u002F`, `src\u002Fgenerated\u002Fmodels\u002F`, and `src\u002Fgenerated\u002FconnectorSchemas.ts` only when the affected data path uses them. Never edit generated files.\n\nAppend a compact context line to `fixes.md` after Phase 0.1 creates it:\n\n```text\n[\u003CHH:MM:SS>] Context — memory-bank=\u003Cpresent|absent> native-plan=\u003Cpresent|absent|not-needed> environment=\u003CenvironmentId|none> dataverse-tables=\u003CN> connectors=\u003CN>\n```\n\nDo not resolve the environment or call Dataverse during ordinary bundle, React, or local JavaScript failures. When a current symptom\u002Ferror is Dataverse or Power Platform related, perform the read-only Dataverse diagnostic sequence in D2 before handing off.\n\n### 0.0 Discover and select the project-local Metro session\n\nUse the validated `\u003Cworking_dir>` from argument parsing. Enumerate **all** matching logs, newest first:\n\n```bash\nLOG_DIR='\u003Cworking_dir>\u002F.powernative\u002Fmetro-logs'\nls -t \"$LOG_DIR\"\u002Fmetro-*-pid-*-port-*.log 2>\u002Fdev\u002Fnull\n```\n\nFor every candidate, parse:\n\n- `pid` and `port` from `metro-\u003Ctimestamp>-pid-\u003Cpid>-port-\u003Cport>.log`;\n- `startedAt` from the filename timestamp;\n- `project` from `power.config.json.appDisplayName`, falling back to the basename of `\u003Cworking_dir>`;\n- `platform` by scanning only the latest 64 KiB for the most recent `iOS ... Bundled` \u002F `iOS Bundling` or `Android ... Bundled` \u002F `Android Bundling` line; use `unknown` when neither appears.\n\nCheck every recorded PID with a cross-platform Node probe: `process.kill(pid, 0)` means alive; treat `EPERM` as alive and other errors as gone. When `port` is numeric, verify ownership with `lsof -nP -iTCP:\u003Cport> -sTCP:LISTEN -t` on macOS\u002FLinux when available, or `netstat.exe -ano -p tcp` on Git Bash\u002FWindows. On Linux without `lsof`, use `ss -ltnp` when available. A candidate is **valid\u002Flive** only when its PID is alive and either owns the recorded port, has `port=unknown`, or no supported port-ownership probe exists. A probe that runs and reports a different PID is a contradiction, not an unavailable probe. Do not persist terminal IDs or depend on terminal output.\n\nSelection rules:\n\n- Apply `portFilter` and `platformFilter` to the valid\u002Flive candidates before selection. When no valid session matches, print the filters plus the available valid sessions and stop. If a platform-filtered candidate is `unknown`, do not guess; tell the user to use `--port` or omit `--platform`.\n- **One valid session** — select it automatically.\n- **Multiple valid sessions** — show one choice per session in this exact shape, then ask which to monitor:\n  ```text\n  \u003Cproject> — \u003Cplatform> — port \u003Cport> — pid \u003Cpid> — started \u003CstartedAt>\n  ```\n  Use `AskUserQuestion`; identify choices internally by the complete `logPath` + `pid` + `port`, not by port alone. If `metro-cursor.json` points to one of the valid sessions, make that session the default choice but still ask. Never silently choose the newest session when more than one is live.\n- **No valid sessions** — apply the failure branches below. Stale or contradictory logs are evidence for the report, never selectable choices.\n\n**`status` branch — return before selection:** After filtering and liveness checks, read `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` only when it is nonempty valid JSON with string `logPath`, numeric `pid`, and numeric-or-`unknown` `port`. Treat a missing, empty, malformed, or shape-invalid cursor as absent and print a warning; never overwrite it from `status`. Print every valid session newest-first using the normal session display shape, marking `[saved]` only when `logPath` + `pid` + `port` match the valid cursor. Then print at most the last 20 nonempty lines from `fixes.md` and `unresolved.md`, passing the displayed text through the persistence redactor first. Print stale\u002Fcontradictory candidate counts without diagnosing their log content, then exit. When no valid session exists, print that result plus the applicable no-log\u002Fstale reason and exit.\n\nFor monitoring modes only, select a session using the rules above. After selection, set `LOG_PATH`, `pid`, `port`, `project`, `platform`, and `startedAt` from the chosen candidate. This selection is sticky for the current monitor run.\n\nWhen no log exists, inspect `metro.config.js` and resolve the logging module from `\u003Cworking_dir>` before choosing a failure branch:\n\n- **Current factory form:** the config uses `createPowerAppsMetroConfig` from `@microsoft\u002Fpower-apps-native-host\u002Fconfig\u002FmetroConfig`, and that exact subpath resolves from the project's installed dependencies. The factory installs project-local logging internally.\n- **Legacy direct form:** the config directly imports `@microsoft\u002Fpower-apps-native-host\u002Fmetro-logger`, and that exact subpath resolves from the project's installed dependencies.\n- **Unavailable:** neither configured subpath resolves, the referenced form is absent, or `@microsoft\u002Fpower-apps-native-host` is missing from `package.json`. A dependency version string alone does not prove that the configured export exists.\n\nBranch as follows:\n\n| Status | Meaning | Action |\n|---|---|---|\n| Exactly one valid log exists, PID is alive, and either port is unknown or the port probe is unavailable | Select it. Capture `project`, `platform`, `startedAt`, `port`, `pid`, and `logPath`, then continue. |\n| Exactly one valid log exists and PID still owns the logged port | Select it. Capture `project`, `platform`, `startedAt`, `port`, `pid`, and `logPath`, then continue. |\n| Multiple valid logs exist | Show every valid session and ask which one to monitor. Do not select by recency alone. |\n| Log exists, PID is gone, and another process owns the logged port | Do NOT diagnose from this log. Tell the user which PID holds the port and ask them to restart `npm run dev`. |\n| Log exists but PID\u002Fport contradict each other | The device may be talking to the wrong server. Ask the user to stop stale Metro processes and rerun `npm run dev`. |\n| No log exists and the logging form is unavailable | This project predates project-local Metro logging or has incomplete dependencies. Enter startup diagnostics to distinguish broken install, unsupported export, and config mismatch; do not edit native\u002FMetro config or loop on restarts. |\n| No log exists and the current factory or legacy direct logging form resolves | If available host output contains `[powernative] Metro logging instrumentation failed`, preserve that bounded evidence. Enter startup diagnostics rather than assume a package defect or require the app to load first. |\n\nThe PID\u002Fport check prevents stale-log diagnosis: a log file can outlive its Metro process, so only the socket probe reveals that the log stopped belonging to the app under test. The explicit choice prevents a valid session on one port from being confused with another valid session in the same project.\n\nIf no `.powernative` log exists but the host exposes a live Metro terminal, use\nits bounded output only as startup evidence. Do not ask for or store its terminal\nID or enter the continuous monitor against it. The startup phase owns any\napproved retry; runtime monitoring still requires a valid project-local log.\n\nRecord the stable source in `fixes.md`:\n\n```text\n[\u003CHH:MM:SS>] Log source — \u003Cproject> \u003Cplatform> — \u003ClogPath> (pid \u003Cpid>, port \u003Cport>, started \u003CstartedAt>)\n```\n\n### 0.1 Ensure state directory\n\n```bash\nmkdir -p .powernative\u002Fdebug-app\ntouch .powernative\u002Fdebug-app\u002Ffixes.md\ntouch .powernative\u002Fdebug-app\u002Funresolved.md\ntouch .powernative\u002Fdebug-app\u002Finjected-logs.md\ntouch .powernative\u002Fdebug-app\u002Fhealth.json\ntouch .powernative\u002Fdebug-app\u002Fmetro-cursor.json\nrm -f .powernative\u002Fdebug-app\u002Fsymptom-state    # per-session — Phase 0.5 rewrites it if symptom mode is active\n```\n\nIf `fixes.md` is empty, write a session header:\n```\n# Debug session — \u003Cdate>\n\n```\n\nAppend the effective invocation settings:\n\n```text\n[\u003CHH:MM:SS>] Monitor config — port=\u003Cany|port> platform=\u003Cany|ios|android> clean-cycles=\u003CtargetCleanCycles> timeout=\u003CtimeoutSeconds>s no-fix=\u003Ctrue|false>\n```\n\n### 0.1.1 Initialize health state\n\nWrite `.powernative\u002Fdebug-app\u002Fhealth.json` without raw log content:\n\n```json\n{\n  \"bundle\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"runtime\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"authentication\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"dataverse\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"connector\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"offline\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"navigation\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"nativeCapability\": { \"status\": \"unknown\", \"summary\": \"No evidence yet\" },\n  \"updatedAt\": \"\u003CISO timestamp>\"\n}\n```\n\nAllowed statuses are `healthy`, `degraded`, `failed`, `unknown`, and `not-configured`. Update only the affected domain after each classified signal:\n\n| Signal | Health update |\n|---|---|\n| Successful native bundle after the latest bundle error | `bundle=healthy` |\n| Bundle\u002Ftransform\u002Fimport failure | `bundle=failed` |\n| Uncaught JS\u002FReact error | `runtime=failed`; set `healthy` after the repaired workflow produces clean new output |\n| Auth success\u002Ffailure host diagnostics | `authentication=healthy|failed` |\n| Dataverse 2xx\u002Ferror for the affected operation | `dataverse=healthy|failed` |\n| Connector resolution\u002Fcall success or failure | `connector=healthy|failed` |\n| No offline profile | `offline=not-configured`; offline activation\u002Fsync warning or failure → `degraded|failed` |\n| Confirmed route\u002Fnavigation error | `navigation=failed`; repaired route confirmation → `healthy` |\n| Native wrapper success, permission denial, missing module, or native failure | `nativeCapability=healthy|degraded|failed` |\n\nAbsence of evidence remains `unknown`; never convert an unobserved domain to `healthy`.\n\n### 0.1.2 Persistence redaction gate\n\nBefore appending diagnostic text to `fixes.md` or `unresolved.md`, or storing a health `summary`, sanitize it:\n\n1. Convert project paths to paths relative to `\u003Cworking_dir>`. Replace other absolute home-directory paths with `[REDACTED_PATH]`.\n2. Replace complete authorization\u002Fcookie\u002Fsecret headers (`Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`, `x-api-key`, `api-key`, `client-secret`, and token headers) with `[REDACTED_HEADER]`.\n3. Replace Bearer values, JWT-like three-segment values, SAS\u002Fquery secrets (`sig`, `se`, `sp`, `sv`, `code`, `token`, `access_token`, `refresh_token`, `id_token`, `client_secret`), passwords, and API keys with `[REDACTED_SECRET]`.\n4. Replace email addresses with `[REDACTED_EMAIL]` and GUIDs\u002Frecord identifiers with `[REDACTED_ID]` unless the identifier is a non-sensitive local PID\u002Fport.\n5. Never persist Dataverse\u002Fconnector response bodies or arbitrary `[TRACE]` object values. Persist only status, source\u002Fconfig table or column names, counts, error codes, and a bounded error message.\n6. Scan the sanitized result again. If any sensitive pattern remains, persist `[REDACTION_BLOCKED: diagnostic omitted]` instead.\n\nRun the bundled verifier for every candidate diagnostic before writing:\n\n```bash\nprintf '%s' \"$DIAGNOSTIC_SUMMARY\" | node \\\n   \"${PLUGIN_ROOT}\u002Fscripts\u002Fredact-debug-diagnostic.js\" \\\n  --working-dir '\u003Cworking_dir>'\n```\n\nPersist only the verifier's stdout. Build `DIAGNOSTIC_SUMMARY` from minimal fields first; do not pass a full Metro window or response body and rely on redaction to make it safe.\n\nStore `logPath` in `metro-cursor.json` relative to `\u003Cworking_dir>` and resolve it against `\u003Cworking_dir>` when reading. This gate is required even though `.powernative` logs are already sanitized.\n\n### 0.2 Verify Metro bundled and the app is running\n\n**Telemetry checkpoint: `validate_metro_session`**\n\nRead a bounded baseline window and return a real byte cursor:\n\n```bash\nnode - \"$LOG_PATH\" 262144 \u003C\u003C'NODE'\nconst fs = require('node:fs');\nconst [file, maxText] = process.argv.slice(2);\nconst maxBytes = Number(maxText);\nconst size = fs.statSync(file).size;\nconst start = Math.max(0, size - maxBytes);\nconst fd = fs.openSync(file, 'r');\nconst buffer = Buffer.alloc(size - start);\nconst bytesRead = fs.readSync(fd, buffer, 0, buffer.length, start);\nfs.closeSync(fd);\nprocess.stdout.write(JSON.stringify({\n   cursor: start,\n   nextCursor: start + bytesRead,\n   truncated: start > 0,\n   output: buffer.subarray(0, bytesRead).toString('utf8')\n}, null, 2));\nNODE\n```\n\nThe logger initially writes `port-unknown` and may atomically rename that file to the numeric port. If the baseline read gets `ENOENT`, rediscover once before reporting failure. When the same filename timestamp and PID now exist with a numeric port, update `LOG_PATH` and `port` to that file and retry the bounded read once; do not process both names as separate sessions.\n\nParse `output`, `cursor`, `nextCursor`, and `truncated`; use the `pid`, `port`, and `logPath` resolved in Phase 0.0. Scan `output`:\n\n- Most recent error-class line is `SyntaxError`, `Unable to resolve module`, `transform failed`, or `error: Bundling failed` → bundle is broken. Treat as a Step B \"Import \u002F Bundle\" critical error and route through Step D immediately. Do NOT enter the steady-state loop until the bundle is healthy.\n- Output contains `Bundling complete` \u002F `iOS Bundled` \u002F `Android Bundled` with no later error-class line → Metro is healthy. Proceed.\n- Output contains a Metro banner (`Metro waiting on`, `Logs for your project`, or `› Metro:`) but no native `Bundled` \u002F `bundling` lines yet → Metro is up but no native client has connected. Tell the user:\n  > **Metro is running but no app is connected yet.**\n  Enter startup diagnostics for a reported QR\u002Fopening problem, or ask the user\n  to open the native client. If they cannot verify it now, return\n  `verification-pending`; no reinstall merely because the client has not connected.\n- Output contains only the logger startup line while the selected PID\u002Fport session remains live → Metro has not emitted enough state yet. Tell the user to wait for the native URL, then re-run `\u002Fdebug-app`; do not guess readiness.\n\nIf `truncated: true`, the baseline covers only the latest 256 KiB. Record that older history was omitted; do not claim the full session history was inspected.\n\nBefore initializing the cursor, pass **all** classifiable entries in this initial\nwindow through Step B, including JS runtime errors, React warnings, network\u002FAPI\nfailures, native errors, and host diagnostics. Do not advance past a prior error\njust because it is not a bundle error. This preserves the promise that users can\n\"play around, then debug\" after a symptom already occurred.\n\n### 0.2.1 Supersession — never re-fix an error the log already shows resolved\n\nThe baseline window is **history, not current state**. It can contain errors that\nwere already fixed, that the user resolved themselves, or that were transient.\nFixing those is worse than doing nothing: it edits working code to chase a\nsymptom that no longer exists, and the \"fix\" is unverifiable because the error\ncannot reproduce.\n\nSo every error found in the **baseline window only** (not in later polls) is\ntreated as *unconfirmed* until checked for supersession. Scan forward from the\nerror line to the end of the window:\n\n| Error class | Superseded when a later line shows |\n|---|---|\n| Import \u002F Bundle | `Bundling complete`, `iOS Bundled`, or `Android Bundled` |\n| Network \u002F API | a 2xx for the same route\u002Fresource that previously failed |\n| JS runtime \u002F React | a later app reload or successful bundle, and the error does not reappear after it |\n| Host diagnostic (`[AuthProvider]`, `[bridge]`, …) | a later success from the same subsystem (e.g. a token acquired after `acquireTokenSilent failed`) |\n\nThen:\n\n- **Superseded** → do NOT fix. Record it and move on:\n  ```\n  [\u003CHH:MM:SS>] Observed (already resolved, not fixed) — \u003Cerror summary> — superseded by \u003Cevidence line>\n  ```\n- **Not superseded** → the error is live. Fix it normally through Step D.\n- **Ambiguous** (no clear supersession evidence either way) → do NOT edit code yet. Ask the user whether they still see it, or wait for it to reappear in the next poll. An error that recurs after the cursor advances is confirmed live.\n\nThis applies to the baseline window only. Anything appearing in a later\n`tail --cursor` poll is by definition new output and needs no supersession check.\n\n**Symptom mode overrides this.** If the user supplied a symptom, that is\nfirst-hand evidence the problem is current, so a matching baseline error is\ntreated as live even when a later line would otherwise look like supersession.\n\n### 0.3 Capture baseline\n\n**Telemetry checkpoint: `capture_runtime_baseline`**\n\nUse the output from Phase 0.2. Note the most recently bundled native platform (iOS \u002F Android) and any recent runtime log lines. Append to `fixes.md`:\n```\n[\u003CHH:MM:SS>] Baseline — last Metro activity: \u003C1-line summary of most recent lines>\n```\n\n### 0.4 Initialize the durable byte cursor\n\nWrite `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` using structured JSON:\n\n```json\n{\n   \"logPath\": \".powernative\u002Fmetro-logs\u002Fmetro-\u003Ctimestamp>-pid-12345-port-8081.log\",\n   \"pid\": 12345,\n   \"port\": 8081,\n   \"project\": \"My Mobile App\",\n   \"platform\": \"ios\",\n   \"startedAt\": \"2026-08-27T12:41:32.050Z\",\n   \"monitorStartedAt\": \"\u003CISO timestamp>\",\n   \"monitorConfig\": {\n      \"port\": null,\n      \"platform\": null,\n      \"targetCleanCycles\": 3,\n      \"timeoutSeconds\": 300,\n      \"noFix\": false\n   },\n   \"cursor\": 12345,\n   \"updatedAt\": \"\u003CISO timestamp>\"\n}\n```\n\nSet project-relative `logPath`, plus `pid`, `port`, `project`, `platform`, and `startedAt` from Phase 0.0. Set `monitorStartedAt` and `monitorConfig` from the current invocation, and set `cursor` to `nextCursor` from Phase 0.2. Resolve `logPath` against `\u003Cworking_dir>` before file access. A new invocation always replaces the prior monitoring configuration and start time. On later invocations:\n\n- Parse an existing cursor only when it is nonempty valid JSON with the expected field types. Treat a missing, empty, malformed, or shape-invalid file as no saved cursor, append a sanitized reset warning to `fixes.md`, and initialize from the selected session's bounded baseline. Never fail startup solely because prior debug state is partial.\n\n- Same `logPath`, `pid`, and `port`, with the process still owning the port → reuse the saved cursor so old errors are not processed again.\n- Multiple valid sessions → ask which session to monitor. Default to the saved session when it remains valid.\n- A different session is explicitly selected, or the saved session is no longer valid → discard the old cursor and initialize from the selected session's latest log window.\n- `rotationLost: true` from Step A → accept the returned reset cursor and record the file shrink\u002Freplacement in `fixes.md`.\n\n---\n\n## Phase 0.5 — Symptom-driven setup (only when `$ARGUMENTS` is a symptom string)\n\nSkip this entire phase if no symptom was provided. The standard log-polling loop alone is good at *visible* errors but blind to *silent* ones: an empty list because the connector wasn't added, a blank screen because `useFocusEffect` wasn't wired, blank rows because column names don't match the model. Phase 0.5 closes that gap.\n\n**`--no-fix` behavior:** Parse the symptom and ask the user to reproduce it, but do not inject `[INJECTED-TRACE]` logs or edit any file. Read only new Metro output. If the symptom is silent and produces no classifiable output, write `pending` to `symptom-state`, append `watch-only: traces not injected` to `unresolved.md`, then enter the standard loop.\n\n### 0.5.1 Parse the symptom\n\nExtract three signals from the user's text:\n\n| Signal | How to derive |\n|---|---|\n| **Affected screen** | Match keywords against route filenames in `app\u002F` (e.g., `\"todos\"` → `app\u002F(tabs)\u002Ftodos.tsx`, `app\u002Ftodos\u002Findex.tsx`, `app\u002F(tabs)\u002Findex.tsx`). Use `Glob` to enumerate `app\u002F**\u002F*.tsx`; pick the closest substring match. If multiple, ask once. |\n| **Affected entity \u002F service** | Same keyword against `src\u002Fgenerated\u002Fservices\u002F*Service.ts` and `src\u002Fgenerated\u002Fmodels\u002F*Model.ts` (e.g., `\"todos\"` → `TodosService`, `Todo` model). Use `Glob`. |\n| **Symptom class** | Map the text to one of: `empty-list`, `blank-screen`, `wrong-data`, `unresponsive-control`, `stale-data`, `wrong-navigation`, `crash`, `pdf-viewer`, `pdf-report`, `pen-input`, `geolocation`, `dataverse-upload`. Default for \"PDF won't open \u002F preview PDF fails\": `pdf-viewer`. Default for \"report PDF not generated \u002F print report fails\": `pdf-report`. Default for \"signature \u002F pen \u002F ink fails\": `pen-input`. Default for \"location not tracking \u002F GPS not updating \u002F background location stopped \u002F breadcrumb gaps \u002F route not consistent\": `geolocation`. Default for \"signature\u002Freport saved but missing\", or \"location rows not reaching Dataverse\": `dataverse-upload`. Default for \"not appearing \u002F not showing \u002F nothing here \u002F missing\": `empty-list`. Default for \"doesn't load \u002F freezes \u002F spinner forever\": `blank-screen`. |\n\nAppend to `fixes.md`:\n```\n[\u003CHH:MM:SS>] Symptom — class=\u003Cclass> screen=\u003Cpath> entity=\u003Cservice>\n```\n\nIf no screen\u002Fentity match: keep `screen=unknown` \u002F `entity=unknown` and proceed — Phase 0.5 still injects diagnostic logs and reads the terminal from whatever data path is most likely based on the symptom text.\n\n### 0.5.2 Ask the user to navigate to the affected screen\n\nThe dev-player has no automation API for navigation. Ask the user:\n> \"Please open the `\u003Cscreen>` screen on the device\u002Fsimulator, then reply `ready`.\"\n\nWait for the user to confirm before proceeding.\n\n### 0.5.3 Inject diagnostic console.log statements and read terminal\n\nInject targeted `console.log` statements at the boundaries of the suspected data path so the Metro terminal reveals what's happening.\n\n**Injection sites — choose the minimum set that covers the symptom class:**\n\n| Symptom class | Inject at |\n|---|---|\n| `empty-list` | (a) entry point of the data-fetching hook, logging `[TRACE items]` the raw response length; (b) the screen component, logging `[TRACE render]` the `items` array length before the list renders |\n| `blank-screen` | Entry point of the screen component, logging `[TRACE mount]` with a timestamp plus only booleans or counts that describe whether required auth\u002Fdata props are present |\n| `wrong-data` \u002F `stale-data` | The hook that calls the generated service (NOT inside `src\u002Fgenerated\u002F`), logging `[TRACE service-response]` with an allowlisted summary: result count, error presence, bounded error code\u002Fstatus, and expected-field presence booleans |\n| `unresponsive-control` | The event handler (`onPress`, `onSubmit`, etc.) logging `[TRACE handler-called]` before any async work |\n| `crash` | Skip injection — jump to the monitor loop (Step A), crash stacks appear in the terminal |\n\n**Console.log injection pattern — all injected lines MUST use this exact format:**\n\n```ts\nconsole.log('[TRACE \u003Ctag>]', \u003Cvalue>); \u002F\u002F [INJECTED-TRACE]\n```\n\n- `\u003Ctag>` — short unique label for this site (e.g., `items`, `render`, `service-response`)\n- `\u002F\u002F [INJECTED-TRACE]` trailing comment on the SAME LINE — this is the cleanup grep key\n- Log only primitives or a newly constructed allowlisted summary of counts, booleans, bounded error\u002Fstatus codes, and configured table\u002Fcolumn names. `JSON.stringify` is allowed only for that constructed summary.\n- Never log raw records, response bodies, arbitrary objects, field values, user-entered text, auth\u002Fdata prop values, identifiers, URLs, headers, or credentials. The host logger removes credential-like lines, but it cannot prove arbitrary app data is free of sensitive information.\n- **Never inject inside `src\u002Fgenerated\u002F`** — inject in the hook\u002Fscreen that calls into it\n\nRecord every injection in `.powernative\u002Fdebug-app\u002Finjected-logs.md`:\n```\n[\u003CHH:MM:SS>] Injected [INJECTED-TRACE] at \u003Cfile>:\u003Cline> — tag=\u003Ctag>\n```\n\nThen tell the user:\n> \"I've added diagnostic console.log statements. Fast Refresh should apply them automatically. Navigate to `\u003Cscreen>` and trigger the symptom (for example, scroll the list or tap the button). If the app does not refresh, reload it from the native dev-client menu. Reply `done` when finished.\"\n\nWait for the user to reply, then run the Step A `tail --cursor` procedure, persist `nextCursor`, and filter the returned `output` for `[TRACE` lines.\n\n### 0.5.4 Walk the data path from terminal output\n\nUse the `[TRACE` lines to walk the chain:\n\n1. **Screen TSX** (`app\u002F\u003Croute>.tsx`)\n   - Find the `useListData(...)` \u002F `use*Data(...)` call.\n   - Check service-call options — a stray `top: 0`, an over-strict `filter`, a `search: query` bound to a never-cleared input, or `orderBy` on a missing column can each silently return zero rows.\n   - Check any client-side `.filter(...)` after the data lands.\n\n2. **Data hook** (`src\u002Fhooks\u002FuseListData.ts` or sibling)\n   - **Critical:** the template hook has TWO mock-fallback paths:\n     - **Error path**: service returns `{ error }` → hook substitutes mock AND may call `setError`. **Silent** if the screen ignores `error`.\n     - **Empty-result path**: service returns `{ data: [] }` (no error) → hook silently substitutes mock. Always invisible without a `[TRACE]` log.\n   - Detect: `Grep` for `MOCK_` imports in the screen file. If present, mock data is wired in.\n   - Confirm `useFocusEffect` is used (not `useEffect`) — `useEffect` won't re-run on back-navigate.\n\n3. **Generated service** (`src\u002Fgenerated\u002Fservices\u002F\u003CName>Service.ts`)\n   - If a TODO stub or file missing → route to `\u002Fadd-connector` or `\u002Fadd-dataverse`. Do NOT edit `src\u002Fgenerated\u002F`.\n   - If it exists and the `[TRACE service-response]` summary shows an error → use its bounded status\u002Ferror code; 401\u002F403 = auth issue; 404 = wrong resource name. Use separately emitted, already-sanitized host diagnostics for message context; do not add a raw error trace.\n\n4. **Generated model** (`src\u002Fgenerated\u002Fmodels\u002F\u003CName>Model.ts`)\n   - Confirm field names match what the screen references. `item.title` vs `cr3e9_title` produces blank rows.\n\n5. **`power.config.json`**\n   - Confirm the `datasources` array contains the suspected entity \u002F connector. If absent, `pa app add data-source` was never run for it.\n\n6. **Auth state** (`src\u002FplayerConfig.ts`, `app.config.js`, `auth.config.json`, `useAuth()` hook)\n   - 401 from the service wrapped as `{ error }` — the `[TRACE service-response]` summary surfaces the status without persisting the error object or message.\n   - **OAuth deeplink handoff**: verify `app.config.js` → `expo.scheme` matches `src\u002FplayerConfig.ts` → `connectorOAuthRedirectUri`, AND the same redirect URI is in `auth.config.json` and the Entra ID registration. If the app registration is missing, route the user to the Power Apps Wrap page via `\u002Fset-app-registration-native`.\n\n**Classify the `[TRACE` output:**\n\n| Output | Meaning | Next step |\n|---|---|---|\n| `[TRACE items] 0` or `[]` — no error field | Service returned empty — check filter\u002Fquery or data not seeded | Fix the query; if no records exist, seed sample data |\n| `[TRACE items] undefined` | Hook never received a response — likely service stub or missing datasource | Route to `\u002Fadd-connector` or `\u002Fadd-dataverse` |\n| `[TRACE service-response]` shows an error status\u002Fcode | Service threw — 401\u002F403 = auth; 404 = wrong resource | Fix auth config or re-run `pa app add data-source` |\n| `[TRACE render]` N > 0 but list looks empty | Field name mismatch between model and screen | Fix screen field references to match the model |\n| `[TRACE handler-called]` never appears | `onPress` not wired or component not mounted | Read TSX, fix the event binding |\n| No `[TRACE` lines at all | Metro may have cached the old bundle | Ask the user to stop Metro, rerun `npm run dev -- --clear`, then reload the native app |\n\nRecord the outcome in `.powernative\u002Fdebug-app\u002Fsymptom-state` (single line: `resolved`, `flagged`, or `pending`).\n\n- **Fix is clear and local** → apply via Step D3 + D4 (type-check + reload + re-poll). After the fix, ask the user to interact with the screen again and read the terminal. If the `[TRACE items]` line shows N > 0, write `resolved`.\n- **Fix routes to another skill** → tell the user, log to `unresolved.md`. Write `flagged`.\n- **No obvious cause** → log a structured note to `unresolved.md`. Write `pending` and enter the monitor loop.\n\n### 0.5.5 Clean up injected console.log statements\n\nAfter the root cause is identified and a fix is applied (or Phase 0.5 concludes), remove ALL injected logs:\n\n```bash\nfind app src -type f \\( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \\) \\\n   ! -path 'src\u002Fgenerated\u002F*' -exec grep -nH 'INJECTED-TRACE' {} +\n```\n\nFor each matching file, edit out the `console.log(...); \u002F\u002F [INJECTED-TRACE]` lines. Verify with:\n```bash\nfind app src -type f \\( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \\) \\\n   ! -path 'src\u002Fgenerated\u002F*' -exec grep -nH 'INJECTED-TRACE' {} +  # must print zero matches\n```\n\nClear the tracking file:\n```bash\necho '' > .powernative\u002Fdebug-app\u002Finjected-logs.md\n```\n\nRun `npm run type-check` once after cleanup.\n\n> **Hard rule:** Never leave `[INJECTED-TRACE]` lines in code. Clean up before marking the session done, even if the symptom is `pending` or `flagged`.\n\n### 0.5.6 Re-enter the standard monitor loop\n\nAfter Phase 0.5 completes, fall through to the monitor loop (Step A). Count clean cycles normally, but let Step C choose the exit from the single-line `symptom-state`: `resolved` may exit green, while `flagged` and `pending` use their non-green exits after `targetCleanCycles`. Never report a green result for a flagged or pending symptom.\n\n---\n\n## Monitor Loop\n\nRepeat until **`targetCleanCycles` consecutive clean cycles**, `timeoutSeconds` elapses, the user types `stop`, OR the escalation rule trips.\n\nBefore every collection cycle and immediately after any fix verification, compare the current time with `monitorStartedAt`. When elapsed time is greater than or equal to `timeoutSeconds`:\n\n1. Clean up all `[INJECTED-TRACE]` lines before exit.\n2. Append the elapsed time, cycle count, clean count, active session identity, and unresolved issue count to `fixes.md`.\n3. Exit without stopping Metro:\n   ```text\n   ⚠ Monitoring timeout reached after \u003Cduration>.\n     Session: \u003Cproject> — \u003Cplatform> — port \u003Cport> — pid \u003Cpid>\n     Clean checks: \u003Cclean>\u002F\u003CtargetCleanCycles>\n   Details: .powernative\u002Fdebug-app\u002Ffixes.md\n   ```\n\n### Step A — Collect logs\n\n**Telemetry checkpoint: `collect_runtime_logs`**\n\nRead `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` and rediscover all live `.powernative` sessions using Phase 0.0's validation logic.\n\n- If the saved `logPath` + `pid` + `port` is still valid, keep monitoring it even when a newer valid session has appeared. Do not interrupt the current run or jump ports.\n- If the saved session is no longer valid and exactly one valid session remains, select that session and return to Phase 0.2 for a new baseline.\n- If the saved session is no longer valid and multiple valid sessions remain, show the session choices and ask which one to monitor, then return to Phase 0.2.\n- If no valid session remains, stop with the applicable Phase 0.0 failure instead of reading a stale log.\n\nOtherwise collect newly appended bytes from the pinned session. When no bytes are already waiting, this foreground collector watches the log directory until that file changes or a full 5-second observation interval completes:\n\n```bash\nnode - \"$LOG_PATH\" \u003Csaved-cursor> 262144 5000 \u003C\u003C'NODE'\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst [file, cursorText, maxText, observationText] = process.argv.slice(2);\nconst cursor = Number(cursorText);\nconst maxBytes = Number(maxText);\nconst observationMs = Number(observationText);\nconst observedAt = Date.now();\nlet watcher;\nlet timer;\nlet finished = false;\n\nfunction snapshot(observation) {\n   try {\n      const size = fs.statSync(file).size;\n      const start = Number.isInteger(cursor) && cursor >= 0 && cursor \u003C= size ? cursor : 0;\n      const fd = fs.openSync(file, 'r');\n      const buffer = Buffer.alloc(Math.min(maxBytes, Math.max(0, size - start)));\n      let bytesRead;\n      try {\n         bytesRead = fs.readSync(fd, buffer, 0, buffer.length, start);\n      } finally {\n         fs.closeSync(fd);\n      }\n      return {\n         cursor: start,\n         nextCursor: start + bytesRead,\n         rotationLost: start !== cursor,\n         truncated: start + bytesRead \u003C size,\n         fileMissing: false,\n         readError: null,\n         observation,\n         observedMs: Date.now() - observedAt,\n         output: buffer.subarray(0, bytesRead).toString('utf8'),\n      };\n   } catch (error) {\n      return {\n         cursor,\n         nextCursor: cursor,\n         rotationLost: false,\n         truncated: false,\n         fileMissing: error && error.code === 'ENOENT',\n         readError: error && typeof error.code === 'string' ? error.code : 'UNKNOWN',\n         observation,\n         observedMs: Date.now() - observedAt,\n         output: '',\n      };\n   }\n}\n\nfunction finish(observation) {\n   if (finished) return;\n   finished = true;\n   if (watcher) watcher.close();\n   if (timer) clearTimeout(timer);\n   process.stdout.write(JSON.stringify(snapshot(observation), null, 2));\n}\n\nconst initial = snapshot('initial');\nif (initial.readError || initial.rotationLost || initial.truncated || initial.output) {\n   process.stdout.write(JSON.stringify(initial, null, 2));\n} else {\n   try {\n      watcher = fs.watch(path.dirname(file), (_event, changedFile) => {\n         if (!changedFile || String(changedFile) === path.basename(file)) finish('change');\n      });\n      watcher.on('error', () => finish('watch-error'));\n      timer = setTimeout(() => finish('interval'), observationMs);\n   } catch {\n      finish('watch-error');\n   }\n}\nNODE\n```\n\nUse only the returned `output` for this cycle. `fileMissing: true` means the logger may have renamed `port-unknown`; rediscover sessions instead of advancing the cursor. Any other non-null `readError`, or `observation: watch-error`, is not a clean cycle: report the bounded error code and stop rather than polling rapidly. Otherwise immediately persist the current `logPath`, `pid`, `port`, `nextCursor`, and a new `updatedAt` to `metro-cursor.json`, even when `output` is empty or contains an error; this prevents duplicate processing after interruption and handles file replacement safely.\n\nCount a clean cycle only when `readError` is null, `observation: interval`, `observedMs >= 5000`, and `output` is empty or contains no classifiable error. An early `change` observation with informational output is not yet a full clean interval; process it and start the next collection cycle. If the log file changes, the PID\u002Fport check becomes contradictory, or the cursor resets because the file shrank\u002Frotated, never count that cycle as clean.\n\nIf `truncated: true`, never count the result as clean. Process any nonempty output, then issue at most three additional tail calls from the returned cursor in the same cycle. If `rotationLost: true`, record an explicit rotation warning in `fixes.md` and require a fresh full observation interval before incrementing the clean counter. If data remains truncated after four chunks, record a backlog warning and continue next cycle rather than consuming unbounded context.\n\nIn the new output, surface as classifiable signal and update the matching `health.json` domain:\n- Runtime ` ERROR ` \u002F ` WARN ` \u002F ` LOG ` prefixes\n- Host diagnostic lines with prefixes like `[PAHost]`, `[bridge]`, `[AuthProvider]`, `[AuthContext]`, `[useConnectionRefs]`, `[useConnectionSetup]`, `[addAadAppToConnectionAcl]`, `[PAHost][ErrorBoundary]`\n- Stack frames (`at \u003Cfn> (\u003Cfile>:\u003Cline>:\u003Ccol>)`)\n- Bundle-class errors (`Unable to resolve module`, `SyntaxError`, `transform failed`) — re-classify as Step B \"Import \u002F Bundle\" Critical and route through Step D\n- HTTP method + status from Metro's request log (e.g., `\"GET \u002Findex.bundle?platform=ios&dev=true ...\" 500 -`) — non-200 on `.bundle` is a bundle\u002Ftransform failure; non-2xx on connector \u002F Dataverse hosts feeds Step B \"Network \u002F API\"\n- Lines containing `Bundling complete` \u002F `iOS Bundled` \u002F `Android Bundled` are informational — log to `fixes.md` at debug volume but do NOT classify as an issue\n- `[TRACE` prefixed lines from injected trace statements — classify under the symptom walk (Phase 0.5.4), not as errors\n\nInterpretation rule for host diagnostic lines:\n- Treat as classifiable signal only when lines match emitted host strings such as:\n   - `[AuthProvider] MSAL init failed:`\n   - `[AuthProvider] Intune enrollment failed:`\n   - `[AuthContext] acquireTokenSilent failed for scopes:`\n   - `[AuthProvider] Intune unenroll failed:`\n   - `[bridge] unhandled plugin call`\n   - `[bridge] fetch THREW for`\n   - `[bridge] HTTP \u003Cstatus> for`\n   - `[addAadAppToConnectionAcl] failed HTTP \u003Cstatus> for connection`\n   - `[addAadAppToConnectionAcl] error:`\n   - `[useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required`\n   - `[useConnectionRefs] Failed to load connections:`\n   - `[useConnectionSetup] could not grant connection ACL: missing Power Apps token or user OID`\n   - `[PAHost] getConnectorToken: acquireToken threw for apiId=\"...\":`\n   - `[PAHost] getConnectorToken: acquireToken returned null for apiId=\"...\"`\n   - `[PAHost] getDataverseToken: acquireToken threw for orgUrl=\"...\":`\n   - `[PAHost] getDataverseToken: acquireToken returned null for orgUrl=\"...\"`\n   - `[PAHost][ErrorBoundary] Unhandled JS error:`\n   - `[PAHost][ErrorBoundary] Error stack:`\n   - `[PAHost][ErrorBoundary] Component stack:`\n- Treat as informational when lines are lifecycle\u002Fstatus-only, such as bridge setup\u002Fready, token acquisition start\u002Fsuccess, bridge registration, and connection-setup screen visibility.\n\n### Step B — Classify each new log entry\n\n**Telemetry checkpoint: `classify_runtime_failures`**\n\nApply the 8-category table. Treat each unique stack trace \u002F error message as one issue.\n\n| Priority | Pattern | Category |\n|---|---|---|\n| Critical | Uncaught exception, unhandled promise rejection, app crash | JS Runtime |\n| Critical | `Unable to resolve module`, `Cannot find module` | Import \u002F Bundle |\n| Critical | `SyntaxError`, `Unexpected token`, `transform failed` (multi-line block from Metro terminal, primary mode only) | Import \u002F Bundle |\n| Critical | `Cannot read properties of undefined`, `is not a function` | JS Runtime |\n| High | `NATIVE_MODULE_MISSING` from `pdfViewer` or `penInput` wrapper | Native |\n| High | `NATIVE_MODULE_MISSING`, `PERMISSION_DENIED`, or `TRACKING_FAILED` from `geolocation` wrapper | Native |\n| High | `INVALID_URL` from `pdfViewer`, or logs mentioning `content:\u002F\u002F`, `blob:`, or `http:\u002F\u002F` PDF viewer input | JS Runtime |\n| High | `VIEWER_FAILED` or `CAPTURE_FAILED` from PDF\u002Fpen wrapper | Native |\n| High | `ERROR` level runtime log | JS Runtime |\n| High | HTTP 4xx \u002F 5xx surfaced in logs | Network \u002F API |\n| High | Native module or bridge error | Native |\n| Medium | React `Warning:` component error | React |\n| Low | `WARN` level log that is not known noise | General |\n\n**Parsing the multi-line bundle\u002Ftransform block (primary mode):** Metro prints these as a banner (e.g., `error: Bundling failed`, `iOS Bundling failed`) followed by an indented block. Unlike runtime stacks, the file:line is on the **first non-banner line of the block**, formatted as `\u003Cabsolute or relative path>:\u003Cline>:\u003Ccol>`. There are usually **no** `at \u003Cfn>` stack frames. Example to recognize:\n```\niOS Bundling failed 412ms\nSyntaxError: \u002FUsers\u002F...\u002Fapp\u002F(tabs)\u002Ftodos.tsx: Unexpected token (47:12)\n  45 |   return (\n  46 |     \u003CYStack>\n> 47 |       \u003CText>{title\u003C\u002FText>\n     |             ^\n  48 |     \u003C\u002FYStack>\n  49 |   );\n```\nTake `app\u002F(tabs)\u002Ftodos.tsx:47:12` as the fix site. The recipes in D3.1 below operate on this format.\n\n**Ignore known-noisy lines:**\n- `Require cycle:` warnings from Metro\n- `VirtualizedList: You have a large list…` without an associated crash\n- Expo SDK informational banners (`Starting Metro…`, `Connecting to…`)\n- React Navigation development warnings about non-serializable params (unless tied to a crash)\n- `USER_CANCELLED` from pen input when the screen leaves state unchanged and does not show an error\n- Host lifecycle\u002Finfo lines with no failure indicator, for example `[bridge] setupNativeHost: bridge ready`, `[PAHost] bridge registered`, `[PAHost] render: waiting for connection resolution (spinner)`\n\n### Step C — If NO issues found\n\n**Telemetry checkpoint: `confirm_runtime_health`**\n\nIncrement the consecutive-clean-cycle counter.\n\n**Before exiting at `targetCleanCycles`, check the symptom guard.** Read `.powernative\u002Fdebug-app\u002Fsymptom-state` and pick the matching exit path below. (If no symptom-driven mode was used this session, Phase 0.1 cleared the file at startup, so the \"file missing\" branch fires.)\n\nBefore every clean, flagged, pending, timeout, iteration-cap, or escalation exit, print this sanitized health table from `health.json`:\n\n```text\nHealth\nBundle             \u003Cstatus>  \u003Csummary>\nRuntime            \u003Cstatus>  \u003Csummary>\nAuthentication     \u003Cstatus>  \u003Csummary>\nDataverse          \u003Cstatus>  \u003Csummary>\nConnector          \u003Cstatus>  \u003Csummary>\nOffline            \u003Cstatus>  \u003Csummary>\nNavigation         \u003Cstatus>  \u003Csummary>\nNative capability  \u003Cstatus>  \u003Csummary>\n```\n\nKeep `unknown` when no evidence was observed and `not-configured` only when configuration absence was positively detected. Apply the persistence redaction gate to every summary. A clean log interval does not make all unknown domains healthy.\n\n**`resolved`** OR file missing (no symptom mode this session):\n\n```\n✓ App is running cleanly — no errors detected across \u003CtargetCleanCycles> consecutive log checks.\n  Symptom verification: \u003CPASS | n\u002Fa — no symptom provided>.\n   Session summary written to .powernative\u002Fdebug-app\u002Ffixes.md.\n\n  To resume monitoring, run \u002Fdebug-app again.\n```\n\n**`flagged`** (Phase 0.5 found a real problem that needs another skill):\n\n```\n⚠ Logs are clean BUT the symptom isn't fixed — it requires another skill.\n  Symptom: \u003Cclass> on \u003Cscreen>\n  Next step: \u003Cskill route recorded in unresolved.md by Phase 0.5> (e.g., run \u002Fadd-connector)\n   Details: .powernative\u002Fdebug-app\u002Funresolved.md\n\n  Re-run \u002Fdebug-app \"\u003Csymptom>\" after taking that step to verify the fix.\n```\n\nDo NOT print the green ✓ — the app is technically log-clean but the user-visible problem persists, and the user needs to act before re-running.\n\n**`pending`** (still active after `targetCleanCycles` clean log cycles):\n\nAppend to `unresolved.md` with the Phase 0.5 chain findings, then print:\n\n> \"⚠ Symptom `\u003Cclass>` on `\u003Cscreen>` still active after `\u003CtargetCleanCycles>` clean log cycles. The runtime is quiet but the user-visible problem persists — likely a swallowed data-path error. See `.powernative\u002Fdebug-app\u002Funresolved.md` for the chain walk. Suggested next step: \u003Cderived from the walk>.\"\n\n---\n\nExit the loop. Do NOT auto-resume.\n\n**Iteration cap (applies in both modes):** independent of the clean-cycle counter and timeout, the loop exits after **50 total cycles**. Track `cycle: \u003CN>` at the top of `fixes.md` and increment per cycle. On cap-hit, exit with:\n\n> \"⚠ Loop reached the iteration cap (50 cycles). Symptom may be intermittent OR a fix is regressing on every reload. See `.powernative\u002Fdebug-app\u002Ffixes.md` for the per-cycle log. Suggested next step: review the last 3 fixes for circular regressions, or re-run with a more specific symptom.\"\n\nIf counter is below `targetCleanCycles` and the cap has not tripped, return to Step A. Its foreground file watcher provides the observation interval; do not add shell `sleep`, a host-specific wait command, or a rapid polling loop.\n\n### Step D — If issues ARE found\n\n**Telemetry checkpoint: `repair_and_verify_runtime_issue`**\n\nReset the consecutive-clean counter to 0. For each issue, work through the sequence below **one at a time** before moving to the next.\n\n#### D0. Watch-only branch (`--no-fix`)\n\nWhen `noFix=true`, do not continue to D1–D4 for mutation:\n\n1. Record the category, a minimal sanitized error summary, the project-relative top user-code frame when available, and the fix recipe or handoff that would have been used. Apply the persistence redaction gate before writing.\n2. Append:\n   ```text\n   [\u003CHH:MM:SS>] Observed (no-fix) — \u003Ccategory> — \u003Cfile:line|no user frame> — \u003Csummary>\n     Would do: \u003Cinline fix recipe | skill handoff | manual native action>\n   ```\n3. Do not edit project source\u002Fconfiguration, inject traces, type-check, reload, install, regenerate, switch accounts, or invoke another skill. Updating `.powernative\u002Fdebug-app\u002F` cursor, audit, and health files is allowed.\n4. Continue to the next issue, then return to Step A. New output is still monitored until the clean target, timeout, stop, or iteration cap is reached.\n\n#### D1. Gather context\n\nUse the current Step A `output` block. Note whether the log shows:\n- A crash with a full stack trace (app is crashing)\n- A React error boundary message (component threw)\n- A network error or HTTP status (API\u002Fconnector failure)\n- Empty response with no error (silent failure — consider injecting a `[INJECTED-TRACE]` console.log; see Phase 0.5.3 for the pattern)\n\nFor JS Runtime \u002F React errors, the stack trace in the terminal IS the context. Read the topmost user-code frame to locate the file.\n\nFor crashes or blank screens with no terminal output: ask the user:\n> \"Do you see anything on screen — error boundary, blank white, or loading spinner? Please copy any visible error text.\"\n\n#### D2. Root-cause analysis\n\nRead the relevant source file(s). Identify:\n- The exact file and line causing the error. For runtime errors (JS Runtime, React, Network\u002FAPI), pick the topmost user-code frame from the stack trace (skip `node_modules\u002F` and `src\u002Fgenerated\u002F`). For bundle \u002F transform errors (Import \u002F Bundle category, primary mode), use the file:line on the first non-banner line of the Metro error block — see Step B's parsing note.\n- Whether the fix touches the data layer, UI layer, routing, or schema.\n- Whether the fix could regress other screens.\n\n**Dataverse \u002F Power Platform diagnostic sequence (before handoff):**\n\n1. Read [skills\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md](..\u002Fadd-dataverse\u002Freferences\u002Fdataverse-reference.md). Use `memory-bank.md` and the relevant `native-app-plan.md` sections when present.\n2. Read `power.config.json`; take `environmentId` from it before any other source. Inspect the relevant generated service\u002Fmodel and `connectorSchemas.ts`.\n3. Resolve the environment read-only:\n   ```bash\n   node \"${PLUGIN_ROOT}\u002Fscripts\u002Fresolve-environment.js\" \"\u003CenvironmentId-or-url>\"\n   ```\n   If resolution fails, run `$PA auth status --json`. Never switch accounts, log out, or open login from `\u002Fdebug-app` without user confirmation.\n4. When environment resolution succeeds and live evidence is required, use only read-only `GET` requests through:\n   ```bash\n   node \"${PLUGIN_ROOT}\u002Fscripts\u002Fdataverse-request.js\" \u003CenvUrl> GET \u003CapiPath> \\\n     --tenant-id '\u003Cresolved-tenant-id>'\n   ```\n   Start with `WhoAmI` when authentication\u002Ftenant identity is in question. Use bounded metadata\u002Fentity reads to confirm table and column names. Do not create, update, delete, publish, seed, flood, or intentionally invalidate credentials from `\u002Fdebug-app`.\n5. App runtime data fixes must continue to use generated `\u003CTable>Service` calls. Never replace them with direct `fetch`\u002F`axios` Dataverse calls.\n6. If OData syntax, lookup behavior, choice\u002Fvirtual\u002Ffile\u002Fimage fields, authentication, throttling, or error shape remains uncertain, query Microsoft Learn with the exact error\u002Ftoken before forming a fix.\n\nOnly after this sequence proves that a table\u002Fcolumn\u002Fservice\u002Fschema artifact is missing or incompatible should D3 route to `\u002Fadd-dataverse`.\n\n**Expo \u002F Expo Router \u002F React Native diagnostic sequence:**\n\n1. Read the cited app file plus `package.json`, `app.json`\u002F`app.config.js`, and route layout only as relevant.\n2. Prefer installed package types\u002Freadmes for the exact version.\n3. If behavior remains uncertain, use a targeted `WebFetch` against official `https:\u002F\u002Fdocs.expo.dev\u002F` documentation (Expo Router pages for routing; SDK pages for native modules). Do not query Microsoft Learn for Expo\u002FReact Native behavior.\n\n**First-party native package ownership gate:**\n\nApply this gate before D3 whenever the failing stack, module, or export involves an installed package whose name matches `@microsoft\u002Fpower-apps-native-*`.\n\n1. Treat a `node_modules\u002F` frame as a lead only. Read the app call site, the installed package's public types\u002Freadme\u002Fexports, and the declared and lockfile-resolved package version. Check that the app uses a documented API with supported inputs and configuration.\n2. Classify the problem as customer code when correcting the caller, input, or supported configuration resolves the contract violation. Apply the normal D3 route in that case.\n3. Classify the problem as package-owned only when the supported app call is valid and the failure is caused by package-internal implementation, a missing\u002Fbroken advertised export, or an internal package import. If ownership remains uncertain, do not patch either side; record the uncertainty and escalate.\n4. For a confirmed package-owned defect, stop automated fix attempts for that issue. Do not change app source, configuration, dependency resolution, or installed package contents to compensate. Capture only the package name, declared\u002Fresolved version, platform, minimal reproduction, expected\u002Factual behavior, and a sanitized bounded stack\u002Ferror summary. Then route the user to `\u002Freport-issue`; mention an official published fix or documented workaround when one is known, but do not apply it from `\u002Fdebug-app`.\n\n#### D3. Apply the fix\n\n**For Import \u002F Bundle category errors, jump to D3.1 first** — those have specific recipes that pre-empt the generic routing table below. For everything else (JS Runtime, Network\u002FAPI, React, etc.), use the routing table:\n\n| Error location \u002F category | Action |\n|---|---|\n| `app\u002F` screen file, `_layout.tsx`, route segment | Inline edit via `Edit` tool |\n| `src\u002Fcomponents\u002F` | Inline edit via `Edit` tool |\n| `src\u002Fhooks\u002F`, `src\u002Fservices\u002F` | Inline edit via `Edit` tool |\n| `src\u002Fgenerated\u002F` | **Do not edit.** Hand off service\u002Fmodel repair to the owning data-source skill using CLI refresh; `npm run generate-schemas` only regenerates the runtime connector map. Do not re-add an intentionally retired source. |\n| Dataverse schema (column\u002Ftable missing) | Run D2's read-only Dataverse diagnostic sequence first. If live metadata\u002Fgenerated artifacts confirm the schema or service is missing, **hand off** to `\u002Fadd-dataverse`. Do not mutate Dataverse or edit generated files from `\u002Fdebug-app`. |\n| Auth \u002F MSAL (`AADSTS65001`, `AADSTS50011`) | **Hand-off:** route user to the Power Apps Wrap page via `\u002Fset-app-registration-native`. Do not auto-edit registrations. |\n| Connection \u002F connector reference missing | **Hand-off:** route user to `\u002Flist-connections` or `\u002Fadd-connector`. |\n| Confirmed defect inside `@microsoft\u002Fpower-apps-native-*` | **Do not fix in the customer project.** Emit the package-defect report below and route to `\u002Freport-issue`. This route takes precedence over native, import\u002Fbundle, and unrecognized-error recipes. |\n| Native module, `app.config.js`, `app.plugin.js`, `Podfile`, `build.gradle` | **Inform the user.** Do NOT auto-edit native config — print the error + suggested action and skip to next issue. |\n| Unrecognized error pattern | **Best-effort autonomous fix** — see D3.2 below. The skill attempts a single named hypothesis instead of stopping; the existing 2-attempt escalation rule is the safety net. |\n\nPDF\u002Fpen\u002Fgeolocation-specific routing:\n- `INVALID_URL` for PDF viewer input is an inline screen\u002Fwrapper fix. Allow `https:\u002F\u002F` and non-empty `file:\u002F\u002F` inputs with viewer 0.2.9+. Never add support for `content:\u002F\u002F`, `blob:`, or `http:\u002F\u002F` in the native viewer path.\n- A generated PDF local `file:\u002F\u002F` URI may be opened by native PDF viewer 0.2.9+.\n- `NATIVE_MODULE_MISSING` for PDF viewer or pen input means the native extension is not in the running build. Do not install packages or edit native config from debug; route to `\u002Fadd-native pdf-viewer` or `\u002Fadd-native pen-input` to verify wrapper\u002Fpackage state, then tell the user a native rebuild\u002Ftemplate update is needed if the package is absent from the app build.\n- For `geolocation`, debug the actual failure dimension: can tracking start (`startTracking`, permissions, native module), are rows reaching Dataverse (default `msdyn_locationrecords` exists, native upload\u002Fauth errors, no JS upload path), and does behavior match the user expectation (background, restart persistence, breadcrumb\u002Froute continuity). Fix visible screen handling inline; if the native module\u002Ftable is missing, block use and route to the relevant geolocation setup path, not `\u002Fadd-dataverse`.\n- `USER_CANCELLED` from pen input is not a bug unless the screen renders it as an error. Inline fix screens that show cancellation as failure.\n- Dataverse artifact writes are local app fixes only when the schema\u002Fservice already exists. If File\u002FImage columns are missing, route to `\u002Fadd-dataverse`.\n\nFor inline edits, keep the change minimal and surgical. Do not refactor surrounding code, rename symbols, or change component contracts.\n\nFor a confirmed first-party native package defect, do not append a successful fix entry. Pass this report through the persistence redaction gate, append it to `.powernative\u002Fdebug-app\u002Funresolved.md`, clean up injected traces, and stop the loop so `\u002Freport-issue` can run:\n\n```text\nConfirmed first-party native package defect — no customer-project workaround applied\nPackage: \u003C@microsoft\u002Fpower-apps-native-*>\nDeclared\u002Fresolved version: \u003Cdeclared> \u002F \u003Cresolved>\nPlatform: \u003Cios|android>\nReproduction: \u003Cminimal sanitized steps>\nExpected: \u003Cbounded behavior>\nActual: \u003Cbounded error\u002Fstatus>\nOwnership evidence: \u003Cwhy the documented caller contract is satisfied and the failure is package-internal>\nNext step: \u002Freport-issue \"\u003Cpackage>: \u003Csanitized summary>\"\n```\n\nAppend to `.powernative\u002Fdebug-app\u002Ffixes.md`:\n```\n[\u003CHH:MM:SS>] \u003Ccategory> — \u003Cfile>:\u003Cline> — \u003Cone-line description of fix>\n```\n\n#### D3.1 Bundle \u002F transform error fix recipes (Import \u002F Bundle category)\n\nThese recipes apply to errors classified as \"Import \u002F Bundle\" in Step B. They are read from the persisted `.powernative` Metro log. Each recipe is opinionated: take the action listed if its precondition matches, otherwise fall through to the next.\n\nBefore applying any recipe, run the first-party native package ownership gate when the cited source\u002Fimporter or failed internal import is under `node_modules\u002F@microsoft\u002Fpower-apps-native-*`. A confirmed package-owned defect routes to `\u002Freport-issue`; never repair it with a resolver alias, copied source, patch, postinstall rewrite, or replacement dependency.\n\n| Error pattern | Precondition | Action |\n|---|---|---|\n| `SyntaxError: \u003Cfile>:\u003Cline>:\u003Ccol>` in `app\u002F`, `src\u002Fcomponents\u002F`, `src\u002Fhooks\u002F`, `src\u002Fservices\u002F` | The cited line is in editable user code (NOT `src\u002Fgenerated\u002F`, NOT `node_modules\u002F`) | `Read` the file around the cited line (±10 lines), identify the syntactic issue (unclosed JSX tag, missing closing brace\u002Fparen, stray comma, missing `from` in import, unterminated string, missing semicolon between statements), apply a single minimal `Edit`. Do NOT reformat surrounding code. |\n| `SyntaxError` in `src\u002Fgenerated\u002F` | Cited file is under `src\u002Fgenerated\u002F` | **Do not edit.** For `connectorSchemas.ts`, regenerate the runtime map. For services\u002Fmodels, resolve the existing registration and hand off to `\u002Fadd-connector` or `\u002Fadd-dataverse` with `--refresh --data-source-name \"\u003Cregistered-name>\"`, the absolute app root, and approved scope for targeted CLI refresh and validation. Check the approved plan first: a removed source needs consumer cleanup through `\u002Fedit-app`, not re-registration. Missing\u002Fambiguous registrations block refresh; do not fall back to addition. |\n| `Unable to resolve module \u003Cname>` from `\u003Cimporter>` | `\u003Cname>` starts with `.` or `..` (relative import) | `Glob` the importer's directory for files matching `\u003Cname>` with any extension (`.ts`, `.tsx`, `.js`, `.jsx`, `.json`). If found with a different extension → fix the import to drop the extension OR match the actual one. If found with a typo (Levenshtein ≤ 2) → fix the typo. If not found at all → the file genuinely doesn't exist; surface to user and ask whether to create it or remove the import. |\n| `Unable to resolve module \u003Cname>` | `\u003Cname>` is a bare package AND not present in `package.json` `dependencies` \u002F `devDependencies` | Follow [`shared\u002Freferences\u002Fjavascript-dependency-planning.md`](${PLUGIN_ROOT}\u002Fshared\u002Freferences\u002Fjavascript-dependency-planning.md) to classify the published package by contents, not its name. If native-bound and absent from the template, report that a template\u002Fruntime update is required. If verified pure JavaScript, ask consent for the exact version, install with `npm install --save-exact`, validate, and retry. Do NOT install without consent. |\n| `Unable to resolve module \u003Cname>` | `\u003Cname>` IS in `package.json` but the bundle still fails | Run the targeted startup inspection before blaming cache: compare locked\u002Finstalled versions and resolve the exact entry point. Restore only with approval when installation is broken; unsupported exports or native build mismatches need different remedies. |\n| `transform failed` referencing a babel plugin (e.g., `[BABEL] ... unknown plugin \"react-native-reanimated\u002Fplugin\"`) | Error references `babel.config.js` | **Hand-off.** `babel.config.js` is project config (same constraint that protects `app.config.js`). Print the cited plugin and suggested fix order (e.g., \"`react-native-reanimated\u002Fplugin` MUST be the LAST plugin in `babel.config.js` `plugins` array\"); skip to next issue. |\n| `transform failed` without a babel reference | Generic transform failure (often a TS feature Metro's transformer can't handle) | Read the cited file, look for syntax that requires a specific TS lib (e.g., decorators, top-level await). If the issue is a known-bad pattern, surface and ask before fixing. Otherwise hand-off. |\n| `predev` script failure (e.g., `npm run generate-schemas` errored before `expo start` ran) | Output shows failure before Metro started | Use startup diagnostics to identify the failed stage (installation, config, schema generation, or type-check). Do not assume a connector problem or edit `power.config.json` directly. |\n| `[BABEL] ... You're trying to use the @babel\u002Fplugin-X plugin twice` | Duplicate babel plugin entries | **Hand-off** for the same reason as above — `babel.config.js` is project config. Surface the duplicate; let the user dedupe. |\n\nAfter applying any inline edit (rows 1, 3, 4 above), Metro auto-detects the file save and re-bundles. Skip directly to D4 — do NOT manually trigger a reload. The verify step picks up Metro's `Bundling complete` (or the next error block) automatically.\n\nAppend to `.powernative\u002Fdebug-app\u002Ffixes.md`:\n```\n[\u003CHH:MM:SS>] Import\u002FBundle — \u003Cfile>:\u003Cline> — \u003Crecipe applied>\n```\n\n#### D3.2 Best-effort fix recipe for uncategorized errors\n\nWhen an error falls through every row of Step B's classification table AND every row of D3.1's bundle recipes, the skill still attempts a fix instead of stopping. The discipline below keeps best-effort from degrading into wild guessing.\n\n**Step 1 — Locate the cite.** Try in order; stop at the first that yields a file:line in editable user code:\n\n1. **Stack trace top user-frame** — walk the stack from the top, skip frames in `node_modules\u002F`, `src\u002Fgenerated\u002F`, and React\u002FHermes internals (`react-native\u002F`, `hermes-engine\u002F`, `metro\u002F`). First remaining frame is the cite.\n2. **Multi-line bundle block** — see Step B's parsing note (file:line on the first non-banner line).\n3. **Verbatim grep across the repo** — `Grep` for the exact error message text (or its most distinctive 4–6 word phrase, with regex special chars escaped) across `app\u002F`, `src\u002Fcomponents\u002F`, `src\u002Fhooks\u002F`, `src\u002Fservices\u002F`. A match at a `throw new Error('...')` site IS the cite.\n4. **Module + symbol grep** — if the error mentions a function or component name (e.g., `useFoo is not a function`), `Grep` for the symbol; the unique declaration site is the cite.\n\nIf no cite can be located by step 4: log a structured note to `.powernative\u002Fdebug-app\u002Funresolved.md` (minimal sanitized error summary + which lookup attempts ran), surface to the user, advance to next issue. **Do not guess at a file.** Best-effort still requires a target.\n\n**Step 2 — Enrich understanding (do not skip).**\n\n- If the error contains a Microsoft-stack token (`AADSTS\\d+`, `Dataverse`, `Power Platform`, `MSAL`, `Entra`, `Graph API`): first run D2's project\u002Freference\u002Fread-only diagnostic sequence, then query `mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search` with the exact code or token when behavior remains uncertain.\n- If the error concerns Expo, Expo Router, an Expo SDK module, or React Native behavior: inspect the installed version and local package documentation, then use targeted `WebFetch` against `https:\u002F\u002Fdocs.expo.dev\u002F`. Do not use Microsoft Learn for these errors.\n- If the error involves `@microsoft\u002Fpower-apps-native-*`, run D2's first-party native package ownership gate. A confirmed package-owned defect is not eligible for best-effort editing.\n- Read the cited file ±15 lines for surrounding context. Note recent imports, the function signature, and any nearby `try\u002Fcatch` or `useEffect` deps.\n- If the error mentions a third-party module (anything in `node_modules\u002F` from the stack), one targeted `WebFetch` against the module's npm page or GitHub README is acceptable; do NOT do open-ended web searches in the loop.\n\n**Step 3 — Form ONE named hypothesis.** Write it to `.powernative\u002Fdebug-app\u002Ffixes.md` BEFORE editing, in this format:\n\n```\n[\u003CHH:MM:SS>] Hypothesis (best-effort) — \u003Cfile>:\u003Cline> — \u003Cone-sentence theory>\n   Evidence: \u003Csanitized error code\u002Fsummary + what in the cited code led you here>\n  Planned change: \u003Cwhat you'll edit, in 1 line>\n```\n\nExamples of acceptable hypotheses:\n- \"`\u003CUserAvatar>` reads `user.profile.image` but `user` can be undefined during the first render — add a null guard\"\n- \"The `useEffect` at line 42 captures a stale `userId` because `userId` isn't in its deps array\"\n- \"`AsyncStorage.getItem` returns null for missing keys, but the caller assumes JSON-parseable string\"\n\nNOT acceptable (refuse to apply, escalate instead):\n- \"Something is wrong with state management\" (vague — no specific change implied)\n- \"Try wrapping in try\u002Fcatch\" (mask, not fix — silently swallows the real bug)\n- \"Maybe also update X, Y, and Z\" (multi-armed — violates one-fix-at-a-time)\n\n**Step 4 — Apply a single minimal edit.** One `Edit` call, smallest possible diff that implements the planned change. Do NOT change unrelated code, rename symbols, or refactor surrounding structure. Re-confirm the file path is in editable user code (NOT under `src\u002Fgenerated\u002F`, `node_modules\u002F`, or any path in the Constraints section's protected list).\n\n**Step 5 — Defer to D4 verify.** The existing verify cycle (type-check + reload + re-poll) decides whether the hypothesis was right. Do NOT preemptively try a second hypothesis \"just in case.\"\n\n**Step 6 — On verify failure, ONE alternative is allowed.** If D4 shows the same error reappearing, you may form ONE alternative hypothesis (this counts as fix attempt #2 against the original error). If THAT also fails, the existing Escalation rule trips and the skill stops on this error — surface to the user, append to `unresolved.md`, advance to the next issue. Do NOT chain a third hypothesis.\n\n**Constraint reminder for best-effort mode (no exceptions):**\n- Never edit `src\u002Fgenerated\u002F`, `node_modules\u002F`, `app.config.js`, `app.plugin.js`, `babel.config.js`, `metro.config.js`, `Podfile`, `build.gradle`, `gradle.properties`, `power.config.json`, `auth.config.json`.\n- Never run `npm install \u003Cpkg>`, `npm uninstall \u003Cpkg>`, `npx expo install \u003Cpkg>`, or any command that mutates `package.json` \u002F `package-lock.json` without explicit user consent (same gate as D3.1's bare-package recipe).\n- Never restart Metro from a runtime repair recipe or run `expo prebuild`.\n  Only the separately approved, bounded startup retry in the startup reference\n  may start\u002Frestart the selected app's Metro session.\n- If the only plausible hypothesis violates one of these constraints, treat the error as out-of-scope: hand-off to the user with a one-line explanation and advance.\n\n#### D4. Verify the fix\n\nAfter the fix is applied:\n\n1. **Type-check:**\n   ```bash\n   npm run type-check\n   ```\n   If TS errors exist, fix them before continuing. Do not advance until type-check exits 0.\n\n2. **Wait for Metro to re-bundle (Import\u002FBundle fix only):**\n   For inline edits applied via D3.1, Metro auto-watches the file and triggers a re-bundle on save. Re-run the Step A cursored tail procedure for a bounded set of checks, watching for one of:\n   - `Bundling complete` \u002F `iOS Bundled` \u002F `Android Bundled` → success, proceed to step 4.\n   - A new bundle error block (different file:line, or different message) → treat as a NEW issue and return to Step B.\n   - Same error repeats → the fix didn't take. Treat as fix attempt #2 against the same error (Escalation rule applies after 2).\n   - 30s elapsed with no bundling activity → Metro may be paused\u002Fwedged; surface to user, do NOT auto-restart Metro (Constraints).\n\n3. **Reload the app (all other fixes — JS Runtime, Network\u002FAPI, React, etc.):**\n   Fast Refresh should apply most inline edits. If no new bundle\u002Fruntime activity appears, instruct the user:\n   > \"Please reload the app from the native dev-client menu, then trigger the workflow again.\"\n\n   After the user confirms, run the Step A cursored tail procedure to check only new output.\n\n4. **Confirm the fix via persisted output.** If the previous error pattern is absent from newly appended log bytes and no new errors appear, the fix held. If any `[INJECTED-TRACE]` lines are relevant, use them to confirm the data path is healthy. After confirming, clean up injected logs (Phase 0.5.5).\n\n5. **Reset clean-cycle counter to 0** and return to Step A.\n\n---\n\n## Escalation\n\nIf the same error persists after **2 fix attempts**, stop and report:\n\n```\n⚠ Unresolved after 2 attempts: \u003Cerror summary>\n  File:           \u003Cpath>\n   Log:            \u003Csanitized bounded error summary>\n  Last fix tried: \u003Cone-line description>\n  Suggested next step: \u003Cmanual action>\n```\n\nPass the block through the persistence redaction gate, append only the verifier's output to `.powernative\u002Fdebug-app\u002Funresolved.md`, and clean up any `[INJECTED-TRACE]` logs before exiting (Phase 0.5.5 procedure).\n\nDo NOT attempt a third automated fix for the same error. Wait for user guidance.\n\n---\n\n## Constraints\n\n- **Never fix native config files** (`app.config.js`, `app.plugin.js`, `Podfile`, `build.gradle`, `gradle.properties`) — report the error to the user with the exact line and a suggested manual action.\n- **Startup restoration is not an upgrade.** Only the approved same-lock restore\n  and bounded Metro retry in the startup reference are allowed exceptions.\n  No blind upgrades, lockfile deletion, Node installation, or host\u002FMSAL patches.\n- **Never modify `src\u002Fgenerated\u002F`** — these files are auto-generated. The owning\n  data-source skill uses CLI add\u002Frefresh\u002Fremove for models\u002Fservices and config;\n  `npm run generate-schemas` only rebuilds the runtime map afterward. Preserve\n  the approved source inventory; do not resurrect retired sources during repair.\n- **Never patch or fork first-party native packages in a customer project** — for confirmed defects in `@microsoft\u002Fpower-apps-native-*`, do not edit `node_modules\u002F`, generate `patch-package` artifacts or postinstall rewrites, vendor\u002Fcopy package source, generate or install a fork, replace the dependency with a git\u002Ftarball\u002Flocal path, or add resolver aliases\u002Fshims that shadow the package. Route the sanitized evidence to `\u002Freport-issue`.\n- **Dataverse diagnosis is read-only** — `\u002Fdebug-app` may resolve the configured environment and issue bounded Dataverse `GET` requests through the bundled scripts. It must never perform metadata\u002Fdata writes, publish, seed records, intentionally trigger throttling, invalidate tokens, switch CLI accounts, or replace generated services with direct HTTP.\n- **Do not ask the user about errors mid-cycle** — investigate autonomously using the tools above. Only surface to the user when:\n  1. The fix requires a native config change.\n  2. The fix requires a tenant admin action (e.g., AAD consent).\n  3. You have attempted a fix twice and the same error persists (escalation).\n  4. The fix routes to another skill (`\u002Fadd-dataverse`, `\u002Fset-app-registration-native`, `\u002Flist-connections`).\n  5. Startup restoration\u002Frestart needs explicit approval or device verification.\n- **One fix at a time** — fully resolve one issue (including type-check + reload + log verification) before starting the next.\n- **Always clean up injected logs** — any `\u002F\u002F [INJECTED-TRACE]` line added during a session MUST be removed before the session ends, even if the symptom is `pending` or `flagged`. Use the Phase 0.5.5 `find` scan across editable `app\u002F` and `src\u002F` files, excluding `src\u002Fgenerated\u002F`, to find them.\n- **Preserve existing behavior** — fixes must be minimal and surgical. Do not refactor, rename, or change component contracts as a side effect of a bug fix.\n- **Bounded polling** — do not busy-loop. Every poll advances a persisted byte cursor and each cycle processes at most four 256 KiB chunks.\n- **Log every action** — before each tool call, print a one-line description of what you're about to do and why, so the user can follow along.\n\n---\n\n## Failure Modes\n\n| Symptom | Likely cause | Fix |\n|---|---|---|\n| Phase 0 reports `not-started` or `stopped` | No live `.powernative` Metro log exists | Run the bounded startup diagnosis; offer approved restoration\u002Fretry only when supported by evidence |\n| Phase 0 sees recent failure lines | Expo\u002FMetro exited during startup or runtime | If no live session remains, correlate the failed launch in startup diagnostics; otherwise use the runtime baseline\u002Fsupersession check before fixing |\n| Phase 0 reports \"Metro running but no app connected\" | Device\u002Fplayer\u002FQR\u002Fnetwork issue, or the user has not opened the app | Diagnose the opening symptom without reinstalling by default; require user retry and fresh evidence |\n| Loop appears stuck | Fix taking longer than expected (e.g., type-check on large project) | Wait — log lines should still print as the fix runs. Type `stop` to exit. |\n| Loop exits with \"iteration cap reached\" | Symptom is intermittent OR a fix is regressing on every reload | Inspect the last 3 entries in `fixes.md` for circularity; re-run with a more specific symptom or fix manually |\n| Same error keeps recurring after fix | Fast Refresh didn't apply the change, or the fix targeted the wrong file | Verify with `git status`; reload from the native dev-client menu; re-run |\n| Same error persists after fix AND `git status` shows the change saved AND type-check is clean | Stale Metro transform cache | Ask the user to stop Metro, rerun `npm run dev -- --clear`, reload, then rerun `\u002Fdebug-app` |\n| Escalation triggered immediately | Error pattern is in a category we hand-off (auth, schema, native) | Take the suggested manual action, then re-run `\u002Fdebug-app` |\n| `.powernative\u002Fdebug-app\u002Ffixes.md` not appearing | Phase 0 didn't run \u002F state directory not created | Run `mkdir -p .powernative\u002Fdebug-app` manually, re-run skill |\n| \"App is running cleanly\" but the user still sees the problem | Symptom-driven mode was not used — log polling alone is blind to silent failures | Re-run as `\u002Fdebug-app \"\u003Cdescribe what you see>\"` to trigger Phase 0.5 (console.log injection) |\n| Phase 0.5 reports `screen=unknown` | Symptom text didn't match any route filename | Re-run with a more specific symptom (`\u002Fdebug-app \"todos screen empty\"` not `\"data is broken\"`), OR navigate to the broken screen first then re-run |\n| No `[TRACE` lines after reload | Metro cached the old bundle | Ask the user to stop Metro, rerun `npm run dev -- --clear`, then reload the app |\n| `[INJECTED-TRACE]` lines left in code after session | Cleanup step was skipped | Run the Phase 0.5.5 `find` scan and remove each matching line |\n\n---\n\n## Notes\n\n- **Designed to be re-run** — every invocation is idempotent. `.powernative\u002Fdebug-app\u002Fmetro-cursor.json` advances past previously seen bytes and resets safely when a new Metro session or rotated log is detected.\n- **Honest about limits** — startup diagnosis can precede a running app, but runtime\n  monitoring is still a bounded foreground loop. It does not wake an idle agent\n  when an unrelated terminal fails. Type `stop` to leave the monitor.\n- **No specialist agents** — upstream's `app-debugger.agent.md` delegates to `screen-builder`, `component-author`, `api-integration`, `dataverse-data-modeler` agents. We don't have all those agents in this plugin, so this skill fixes inline OR routes to skills (`\u002Fadd-dataverse`, `\u002Fset-app-registration-native`, `\u002Flist-connections`, `\u002Fadd-connector`). Behavior is equivalent for the categories we cover.\n- **Host diagnostics caveat** — host-prefixed diagnostics (`[PAHost]`, `[bridge]`, `[AuthProvider]`, etc.) are expected in dev-player sessions and should be treated as first-class telemetry. If these lines are absent in non-dev-player builds, that is expected and not itself a bug.\n- **Upstream parity table:**\n\n  | Behavior | Upstream | This skill |\n  |---|---|---|\n   | Log-driven monitor loop | yes | yes — project-local sanitized Metro log is authoritative; host terminal APIs are optional only |\n  | 8-category classification | yes | yes |\n  | Verification cycle (type-check + reload + re-poll) | yes | yes |\n  | Escalation after 2 attempts | yes | yes |\n   | Bounded polling | yes | yes — durable byte cursor, bounded chunks |\n  | Configurable consecutive-clean exit | fixed at 3 | yes — default 3, configurable with `--cycles`, and gated on symptom resolution |\n  | Specialist agent delegation | yes | replaced with skill routing |\n   | Working-dir audit log | no | yes (additional — `.powernative\u002Fdebug-app\u002Ffixes.md`, `injected-logs.md`) |\n  | MS Learn fallback for unknown errors | no | yes (additional) |\n   | Persisted Metro\u002Fapp log source (bundler errors + Hermes console + HTTP request log) | no | yes — survives host restarts; no MCP fallback |\n  | Bundle \u002F transform error fix recipes (D3.1) | no | yes (additional) |\n  | Bundle-aware verify (poll Metro for `Bundling complete`) | no | yes (additional) |\n  | Best-effort autonomous fix for uncategorized errors (D3.2) | no | yes (additional) |\n  | Symptom-driven mode — console.log injection + terminal read + data-path walk | no | yes (additional — catches silent failures invisible to log polling; injects `[INJECTED-TRACE]` logs, reads terminal, cleans up logs after root cause found) |\n",{"name":5,"model":56,"description":7,"allowed-tools":57,"user-invocable":58},"sonnet","Read, Edit, Write, Grep, Glob, Bash, AskUserQuestion, WebFetch, mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search",true,"main","0a55a88fa2855404029d1e5450faf92878baf763","plugins\u002Fmobile-apps\u002Fskills\u002Fdebug-app",232,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills","https:\u002F\u002Fmicrosoft.github.io\u002Fpower-platform-skills\u002F","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-14 21:46:39",{"source":8,"skillName":5,"commands":70,"prompt":80,"zipAvailable":58},[71,74,77],{"tool":72,"command":73},"npx","npx skills add microsoft\u002Fpower-platform-skills --skill debug-app",{"tool":75,"command":76},"bunx","bunx skills add microsoft\u002Fpower-platform-skills --skill debug-app",{"tool":78,"command":79},"pnpm","pnpm dlx skills add microsoft\u002Fpower-platform-skills --skill debug-app","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fmobile-apps\u002Fskills\u002Fdebug-app\u002FSKILL.md",[82],{"path":83,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":86,"sourceHtmlUrl":87},"references\u002Fstartup-diagnostics.md","REFERENCE","参考文档",18758,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fmobile-apps\u002Fskills\u002Fdebug-app\u002Freferences\u002Fstartup-diagnostics.md",[89,111,132,150,164,174],{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":51},"01M699WVHX0XN59EPBTTPEKYPG","setup","Use when Process Intelligence needs building, explicit cloud\u002Faccount\u002Fenvironment configuration, sign-in, connection diagnostics, or recovery from an authentication error.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fsetup\u002FSKILL.md",[],[91,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110],"read","when","connection","error","sign","intelligence","configuration","use","process","diagnostics","environment","authentication","cloud","recovery","Bash",{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":120,"publishedAt":51},"01M699WSR9EX55YY1WD9J22FEG","report-issue","Use when the user wants a Process Intelligence bug-report draft or support summary for a failed operation.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Freport-issue\u002FSKILL.md",[117],{"categoryNo":118,"categoryName":119,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000034","行政与办公人员",[121,122,123,124,125,104,103,126,127,101,128,129,130,97,131],"report issue","report","issue","support","user","bug","summary","draft","operation","for","bug-report",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":138,"publishedAt":51},"01M699WR26YQ9Q21KE6MJF5B2G","investigate-process","Use when a broad Process Mining business question, observed pattern or competing explanation needs investigation across analytical perspectives.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Finvestigate-process\u002FSKILL.md",[],[104,139,140,141,97,142,143,144,145,96,146,103,147,148,149],"investigate","investigate process","mining","process mining","investigation","perspectives","question","business","pattern","across","analytical",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":51},"01M699WP9SDG5ZR12P8VYNXKTN","derive-metric","Use when a requested measure is missing, a saved custom metric needs reuse, or an ephemeral formula or derived scalar is needed.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fderive-metric\u002FSKILL.md",[],[157,158,96,103,159,160,161,162,163,97],"metric","derive metric","formula","missing","reuse","saved","custom",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":170,"publishedAt":51},"01M699WMG5R8P6SMTDAS1TKF9E","compare-cohorts","Use when comparing process cohorts, departments, periods or before-and-after results under matched definitions.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fcompare-cohorts\u002FSKILL.md",[],[171,172,97,103,104,173,96],"compare","compare cohorts","results",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":180,"publishedAt":51},"01M699WJWNVTMP9XK3NCJHV14D","analyze-variants","Use when investigating common or slow variants, repeated work, unusual paths, or a specific Process Mining case.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fanalyze-variants\u002FSKILL.md",[],[181,182,183,142,97,141,184,185,103,104,96,186,187],"analyze","variants","analyze variants","case","paths","work","common"]