setup-offline-profile について
Power Apps プロジェクト向けに Dataverse Mobile Offline Profile を設定するワークフロースキルです。作成や拡張、範囲と関連の確認を行い、ネイティブのオフラインアプリ用設定を保存します。
主な機能
- 01オフラインプロファイルの作成・拡張
- 02テーブルごとの行範囲設定
- 03列・関連・同期の設定
- 04プロファイルの検証と公開
- 05設定保存と処理の再開
活用シーン
- 01ネイティブ Power Apps アプリのオフラインデータ設定
- 02既存 Dataverse オフラインプロファイルの拡張
- 03中断後の設定作業の再開
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ microsoft/ power-platform-skills --skill setup-offline-profileインストール後、Claude Code で/setup-offline-profileを入力して読み込まれたか確認します。
詳細
プラグインの確認:
node "${PLUGIN_ROOT}/scripts/check-version.js"を実行します。メッセージが出力された場合は、続行する前にユーザーに表示してください。
共通の指示:shared-instructions.md — 最初に読みます。
参照資料:
- offline-profile-schema.md — Dataverse エンティティのフィールドマップ
- dataverse-offline-api.md — プロファイル/項目/関連付けの POST に関する Web API のレシピ
- offline-profile-reconciliation.md — このスキルが書き込む
schemaColumnsのベースラインと、それを使用するライフサイクルの差分チェック
オフラインプロファイルのセットアップ
アプリ(および互換性のある他の Power Apps クライアント)がオフラインアクセス用のデータをダウンロードするために使用できる、Dataverse Mobile Offline Profile を作成するためのエンドツーエンドのウィザードです。
v0 の範囲:構成のみです。このスキルは、既存の
Dataverse Mobile Offline Profile テーブル(mobileofflineprofile、
mobileofflineprofileitem、mobileofflineprofileitemassociation)にレコードを作成し、
プロファイルのメタデータ、テーブルごとのスコープ、一時的な SDK 回避策フィールドを含む
アプリレベルのオフライン構成全体を offline-profile.json に書き込みます。このスキルは
power.config.json を変更しません(このファイルは pa app init
が管理し、そのスキーマは上流で制御されます)。テンプレートにはすでに
@microsoft/power-apps-native-offline が含まれています。@microsoft/power-apps-native-host
はプロファイルを使用し、ローカルの SQLite アクセス、同期キュー、
再接続時の動作、状態の UX を管理します。このスキルでは、アプリが所有するオフラインのランタイムコードを重複してスキャフォールディングしません。
v0 の対象外:
- カスタムフィルターモード(
recorddistributioncriteria=3、savedquery ピッカー)— v0.5 まで延期 - ユーザー/チームへのメンバー割り当て —
/assign-offline-profileに分割 - 行数に基づくダウンロード量の推定 —
/preview-offline-scopeに分割
アプリルートのバインド
ウィザードに入る前、およびプロジェクトの読み取りやコマンド実行を行う前に、
app-working-directory.md を実行します。
絶対パスの working_dir を 1 つ解決します。子呼び出しの所有者ルートを引き継ぐか、
契約に従って、直接の呼び出しに明示された --working-dir/初期 cwd を使用します。
子コンテキストが不足または競合している場合は、起動時の cwd にフォールバックせず、
NEEDS_CONTEXT を返します。参照資料や再試行を含むすべてのシェル呼び出しとファイルツールを
このルートにバインドします。ファイルツールでは、絶対パスの <working_dir>/... を使用します。
選択した環境 ID/URL/テナントと、指定された回答を呼び出しコンテキストとして保持します。
新しい呼び出しのたびに、絶対パスの PLUGIN_ROOT と必要な値を再指定します。
以前のシェル変数は引き継がれません。アーキテクトと前提条件ヘルパーにも、
同じルートと ID 情報を渡します。開始の承認があっても、ウィザードのオフラインゲートを省略できるわけではありません。
--plan-only または計画フェーズの呼び出し元は、この変更を伴うウィザードに入る前に、
NEEDS_CONTEXT: offline setup requires an implementation-phase invocation を返します。
ワークフロー
- プロジェクトと認証を確認 → 2. モードを解決(作成か拡張か) → 3. アーキテクトエージェントを起動 → ゲート 1(テーブルの前提条件)→ 4. 必要に応じて内部の
enable-tables-offlineワークフローを実行 → 5. プロファイルのシェルを POST → ゲート 2(テーブルごとの行スコープ)→ 6. プロファイル項目を POST → ゲート 3(リレーションシップ+列+同期)→ 7. 関連付けを POST → 8. 検証と公開 → 9. 成果物を保存 → 10. まとめ
ステップ 1 — プロジェクトと認証を確認する
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
if [ ! -f power.config.json ] || [ ! -f app.config.js ]; then
echo "BLOCKED: working_dir is not an initialized app" >&2
exit 1
fi
environment_id=$(node -p "require('./power.config.json').environmentId || ''") || {
echo "BLOCKED: unreadable power.config.json" >&2; exit 1;
}
if [ -z "$environment_id" ]; then
echo "NEEDS_CONTEXT: selected app has no environmentId" >&2; exit 1;
fi
node "${PLUGIN_ROOT}/scripts/resolve-environment.js" "$environment_id" --no-cache --require-tenant
解決された環境 ID、HTTPS URL、テナントが、指定されたオーナーコンテキストと一致することを確認します。これらを <selected-environment-id>、<envUrl>、<tenantId> として記録します。一致しない場合は NEEDS_CONTEXT を返し、処理を続けるために環境やアカウントを切り替えてはいけません。コピーした参照コマンドや再試行を含め、すべての Dataverse リクエストに --tenant-id "<tenantId>" を渡してください。
絶対パスを扱えるファイルツールを使って、<working_dir>/.datamodel-manifest.json または <working_dir>/docs/plan-artifacts/.datamodel-manifest.json を特定します。選択した絶対パスを、アーキテクト(ステップ 3)と成果物の更新(ステップ 9)で使用するため、呼び出しコンテキストに保持してください。別のアプリを検索してはいけません。
Web 専用ターゲットの検出 — モバイル オフライン プロファイルは、ネイティブターゲット(iOS/Android)にのみ適用されます。プロジェクトが Web 専用の場合、プロファイルは Dataverse に作成されますが、生成されたアプリで使用されることはありません。
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
# Inspect platforms declared in app.config.js
node -e "
const c = require('./app.config.js');
const platforms = c?.expo?.platforms ?? [];
const hasNative = platforms.includes('ios') || platforms.includes('android');
console.log(JSON.stringify({ platforms, hasNative }));
"
hasNative | アクション |
|---|---|
true(ios および/または android がある) | 通常どおり続行します |
false(Web 専用、またはプラットフォームなし) | 次のメッセージを表示します:⚠ This project only targets web — Mobile Offline Profiles don't apply (they require iOS/Android). Continuing will create the profile in Dataverse but no app will use it. AskUserQuestion で「続行しますか?」と尋ねます。デフォルトは「いいえ」です。 |
解析エラー/app.config.js にキーがない | 警告しますが、ネイティブとみなします(パーサーの問題で処理をブロックしないでください) |
停止条件:
power.config.jsonがない → 「まず/create-mobile-appを実行してください。」.datamodel-manifest.jsonとdocs/plan-artifacts/.datamodel-manifest.jsonのどちらもない → 「まず/add-dataverseを実行してください。オフライン プロファイルにはデータモデルが必要です。」- 環境の解決に失敗 → 標準の認証復旧手順(
az login --tenant <env-tenant>を実行するか、環境 URL を直接指定します。shared-instructions.md を参照してください)。 - Web 専用で、ユーザーが上書きを拒否 → 停止します。次のメッセージを表示します:
Offline profile creation skipped — no native target.
ステップ 1a — 環境の整合性チェック
/add-dataverse のステップ 3a と同じです。power.config.json が解決されること、および az が対象テナントのトークンを取得できることを確認します。取得できない場合は停止します。ユーザーは az login --tenant <env-tenant> で再認証する必要があります。
Step 1b — 再開の確認
memory-bank.md の ## Offline profile ブロックを読み、status に基づいて判断します。
status の値 | アクション |
|---|---|
(セクションが存在しない)または status: none | 初回実行です。Step 2 に進みます。 |
status: not-applicable | ユーザーは以前、/create-mobile-app のオフラインプロファイル設定中にオプトアウトしています(「オフラインサポートは不要」)。再確認します:「Memory-bank では、このアプリにオフライン機能は不要となっています。これを上書きして続行しますか?(y/N)」。デフォルトの N ではここで停止します。 |
status: done かつ profileId に一致するプロファイルが環境にまだ存在する | 完了済みです。memory-bank ブロックの概要を表示し、/edit-offline-profile(v0.2)を実行するか、そのまま終了するかをユーザーに尋ねます。 |
status: done だが、GET /mobileofflineprofiles(<profileId>) が 404 を返す | プロファイルが外部(maker portal または別の環境)で削除されています。none として扱い、セクションをクリアして Step 2 に進みます。 |
status: in-progress かつプロファイルが環境に存在する | 再開フロー — 以下を参照してください。 |
status: in-progress だが、プロファイルが環境に存在しない | Memory-bank の情報が古くなっています。自動クリーンアップを行い、セクションをクリアして recovered from stale in-progress state を記録し、新規実行として Step 2 に進みます。 |
再開フロー — memory-bank の status: in-progress で、プロファイルがまだ存在する場合:
-
GET /mobileofflineprofiles(<profileId>)?$expand=MobileOfflineProfile_MobileOfflineProfileItemを実行して、実際にコミットされた内容を確認します。- アイテムが 0 件 → プロファイルのシェルは存在しますが、アイテムはまだ POST されていません。Step 6 から再開します。
- アイテムが 1 件以上あり、manifest の一部が欠けている → Step 6 から再開し、すでに存在するアイテムはスキップします。
- すべてのアイテムが存在し、1 件以上で
selectedcolumnsが空 → Step 7(PATCH)から再開します。 - すべてのアイテムが存在し、すべてに
selectedcolumnsがある → Step 8(Publish)から再開します。 componentstate=0(Published)→ memory-bank の情報は誤りです。doneとして扱います。
-
1 回の AskUserQuestion で、まとめてユーザーに尋ねます(ステップごとの承認は求めません)。
Resume from <computed step> on profile "<name>" (<profileId>)? Items already committed: <N> of <M> PATCHes already applied: <K> Published: <yes|no> Options: - Resume from where it left off (recommended) - Start fresh — delete the half-built profile and re-run from Step 5 - Cancel -
Resumeを選択した場合 → 算出されたステップに進みます。selectedentitytypecodeを照合し、すでにコミットされたアイテムはスキップします。 -
Start freshを選択した場合 →DELETE /mobileofflineprofiles(<profileId>)を実行します(アイテムと関連付けを連鎖削除)。memory-bank のセクションをクリアし、新規として Step 2 に進みます。 -
Cancelを選択した場合 → 停止し、memory-bank は変更しません。
Memory-bank チェックポイントの契約: このスキルは、Step 5 の直後(プロファイルシェルの POST 後)に status: in-progress と profileId を書き込みます。それ以降の各ステップでは lastSuccessfulStep: フィールドを更新し、再開時にどこから再開するかがわかるようにします。いずれかのステップで BLOCKED: となった場合、スキルは status: in-progress のままにします。DONE の場合は、Step 9c で status: done を書き込みます。
POST 再試行時の冪等性: Step 6 で、同じ親プロファイルに対し同じ selectedentitytypecode のアイテムを再度 POST すると、Dataverse が 409 Conflict(「重複」)を返すことがあります。ラッパーの dataverse-request.js は looksLikeDuplicate ロジックによってこれを通知なしの成功として扱うため、安全に再試行できます。
Step 2 — モードの解決(新規作成、拡張、または調整)
テレメトリチェックポイント:resolve_offline_profile_mode
開始前に表示:
「→ 環境内に既存のオフラインプロファイルがあるか確認しています…」
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"mobileofflineprofiles?\$select=mobileofflineprofileid,name,description,publishedon" \
--tenant-id "<tenantId>"
決定ツリー — 次の順に評価します。
| # | 条件 | アクション |
|---|---|---|
| 1 | Step 1b ですでに memory-bank 内に status: in-progress が検出されている | フローを再開します(Step 1b で処理済み)。ここでは再評価しません。 |
| 2 | offline-profile.json にトップレベルの profileId: <X> があり、プロファイル <X> が環境内にまだ存在する | 競合ケース — ユーザーに確認します。 AskUserQuestion で尋ねます。(a)固定済みプロファイルを拡張する(現在のデータモデルに合わせて再設計し、必要に応じて項目を追加/PATCH する)、(b)固定済みプロファイルを削除して新規作成する(取り消し不可 — 項目、関連付け、メンバーシップをカスケード削除する)、(c)キャンセルする。デフォルト = (a)拡張。黙って削除することは絶対にしません。 |
| 3 | offline-profile.json にトップレベルの profileId: <X> があるが、プロファイル <X> は存在しない(GET で 404 が返る) | offline-profile.json は古いファイルです(環境がリセットされた、またはプロファイルが手動で削除された)。ローカルファイルを削除し、4 行目に進みます。 |
| 4 | 環境内の既存プロファイルの name が、このアプリの名前と一致する(power.config.appDisplayName またはディレクトリ名に対して、大文字と小文字を区別しない部分文字列一致) | ユーザーに確認します。 AskUserQuestion で尋ねます。(a)名前が一致するプロファイルを拡張する、(b)新しいプロファイルを作成する(名前が一致するプロファイルは別のアプリに属している可能性があります。判断はユーザーに委ねます)、(c)キャンセルする。デフォルトなし — どちらも妥当な選択です。 |
| 5 | 環境内にプロファイルがない | モード = create-new。Step 3 に進みます。 |
| 6 | 環境内に 1 つ以上のプロファイルがあるが、名前が一致するものも固定されたプロファイルもない | モード = create-new(環境内に無関係なプロファイルがあります)。Step 3 に進みます。1 行の注記を表示します:↷ 環境内に無関係なプロファイルが <N> 件あります。拡張はしません。管理するには /edit-offline-profile を参照してください。 |
2 行目が重要な理由(2026-05-25 の実証結果):chanel-rm と FCB Tracker のテスト実行でこのケースが発生しました。この確認がなければ、スキルは固定済みプロファイルを黙ってカスケード削除していました。このパッチの適用後は、ユーザーに明確な 3 つの選択肢が提示され、
deleteは常に明示的な操作になります。
拡張モード(2a、4a 行目)の実装:
Mode: extend, existingProfileId: <X>を指定してアーキテクトを再起動します。アーキテクトは現在の提案をサーバー上の項目および関連付けと比較し、3 つのリストを出力します:(i)追加する項目、(ii)PATCH する項目(スコープ/列/同期の差分)、(iii)削除する項目(サーバー上にあるが現在のデータモデルにないもの)。Gate 2 でユーザーに提示します。承認後、スキルは増分書き込みを実行します。プロファイルのシェルを POST することはありません。
Step 3 — アーキテクトエージェントの起動
テレメトリチェックポイント:design_offline_profile_scope
開始前に表示:
「→ プロファイルを設計するため、mobile-app:offline-profile-architect エージェントを読み取り専用で起動しています…」
Task で起動します:
agent: mobile-app:offline-profile-architect
prompt:
Owner: setup-offline-profile
Phase: planning
Working directory: <working_dir>
Plugin root: ${PLUGIN_ROOT}
Environment ID: <selected-environment-id>
Environment URL: <envUrl>
Tenant ID: <tenantId>
Manifest path: <absolute manifest path within working_dir>
Proposal output: <working_dir>/_offline_section.md
Publisher prefix: <prefix>
Mode: default
エージェントは作業ディレクトリに _offline_section.md を返します。これを読み込み、1 行目のステータスコードを解析します。
DONE→ 続行しますDONE_WITH_CONCERNS: <list>→ 該当する場合は Gate 2 / Gate 3 で懸念事項を提示し、続行しますNEEDS_CONTEXT: <missing>→ 不足しているコンテキストを解決し(多くの場合、データモデルファイルがありません)、もう一度起動します(最大 2 回の再試行)。それでも失敗した場合は、エージェントの理由を示して停止します。BLOCKED: <reason>→ 停止し、ユーザーに提示します。黙って再試行しません。
Step 3.5 — 設定のレビュー(対話型 AskUserQuestion フロー)
テレメトリチェックポイント:review_offline_profile_configuration
開始前に表示:
「→ 提案されたオフラインプロファイル設定を提示しています。選択肢をタップして承認、調整、またはキャンセルしてください。入力する必要はありません。」
スキルは提案を 1 画面の要約(読み取り専用のコンテキスト)として表示し、その後、構造化された AskUserQuestion プロンプトを通じて選択を進めます。これは /create-mobile-app が 4 つの計画ゲートで使用するのと同じクリック式のパターンです。以前の「accept と入力/平易な英語で編集内容を入力/cancel と入力」という返信フローは、パーサーが認識できない内容をユーザーが入力すると、うまく機能しないことがあったため、これに置き換えます。
Step 3.5a — 概要を表示する(情報提供のみ)
_offline_section.md とアーキテクトの出力から実際の値を代入します。
══════════════════════════════════════════════════════════════════════
Mobile Offline Profile — Proposed Configuration
══════════════════════════════════════════════════════════════════════
PROFILE METADATA
Name : <proposed name>
Description : <proposed description, or "(none)">
Mode : create-new | extend existing (<profileId>)
TABLE PREREQUISITES (IsAvailableOffline + ChangeTrackingEnabled)
cr123_note ❌/❌ → will be enabled
cr123_visit ✅/❌ → ChangeTracking will be enabled
contact ✅/✅ → no change
PER-TABLE CONFIG
▸ cr123_note (Organization rows, User's rows)
Sync : every 10 min
Columns : 12 (cr123_title, cr123_body, cr123_visitid, …, modifiedon, createdon)
▸ cr123_visit (Related rows only)
Sync : every 10 min
Columns : 8 (cr123_name, cr123_date, …, modifiedon)
▸ contact (All records)
Sync : every 60 min
Columns : 5 (fullname, emailaddress1, …, modifiedon)
RELATIONSHIPS (will be POSTed as mobileofflineprofileitemassociation rows)
cr123_note → cr123_note_visit (links to cr123_visit)
cr123_note → cr123_note_image (includes image bytes)
══════════════════════════════════════════════════════════════════════
このテキストと一緒にプロンプトは表示されません。情報提供のコンテキストを示した直後に、以下の対話型プロンプトが表示されます。
Step 3.5b — 最上位の判断(AskUserQuestion を1回)
header : Offline profile
question : "Accept the proposed offline profile configuration and publish to Dataverse?"
options :
- Accept and publish (Recommended)
- Adjust before publishing
- Cancel — abort, nothing is mutated
結果:
| ユーザーの選択 | アクション |
|---|---|
| 承認して公開 | メモリバンクのチェックポイントを書き込み(下記参照)、Step 4(必要に応じて前提条件を有効化)→ Step 5(シェルを POST)→ Step 6(項目を POST)→ Step 7(選択した列を PATCH)→ Step 8(公開)→ Step 9(永続化)→ Step 9.5(検証)→ Step 10(概要)に進みます。問題が発生しない限り、これ以降プロンプトは表示されません。 |
| キャンセル | STOP。Dataverse の変更は行いません。成果物も書き込みません。memory-bank.md を status: cancelled-at-config-review に更新します。 |
| 公開前に調整 | Step 3.5c に進みます。 |
Step 3.5c — 調整する領域を選択する(AskUserQuestion を1回、multiSelect)
header : Adjust which
question : "Which sections of the proposal do you want to change?"
multiSelect: true
options :
- Profile name or description
- Per-table row scope (who's rows get synced)
- Per-table sync interval
- Per-table column selection
ユーザーの選択内容に応じて Step 3.5d を実行します。何も選択されなかった場合(ダイアログを閉じた場合)は、何も変更せず Step 3.5b に戻ります。
Step 3.5d — 領域ごとの詳細設定
3.5c でユーザーが選択した各領域について、対応するサブフローを実行します。進行中に編集内容をメモリ上の設定コピーに適用します。Step 3.5e までは Dataverse に反映されません。
プロファイル名または説明 — テキストプロンプト(自由入力。選択肢の列挙は不可):
「新しいプロファイル名を入力するか、
skipと入力して<current name>を維持してください。」続けて:「新しい説明を入力するか、
skipと入力して<current description>を維持してください。」
名前は100文字以下であることを検証し、空白をトリミングして、空の値は拒否します。
テーブルごとの行スコープ — テーブルごとに1回 AskUserQuestion を実行します(1回の呼び出しで最大4テーブルをまとめます。テーブルが5個以上の場合は複数回呼び出します)。
header : Scope <table>
question : "Row scope for `<table-logical-name>`?"
options :
- Related rows only (child of a parent table; default for pure children)
- All records (default for shared catalogs like product / contact)
- User's own rows (Organization-scoped + recordsownedbyme=true; default for personal transactional data)
- Organization's rows (Organization-scoped, all owners — broadest non-All)
回答を recordDistributionCriteria(0=関連、1=すべて、2=組織)と recordsownedby* サブフラグに対応付けます。ユーザーが「ユーザー自身の行」を選択した場合は recordsownedbyme=true を設定します。「組織の行」を選択した場合は、3つのサブフラグすべてを false のままにします。
テーブルごとの同期間隔 — テーブルごとに1回 AskUserQuestion を実行します。
header : Sync <table>
question : "How often should `<table-logical-name>` sync?"
options :
- Every 5 min — hot transactional data (Recommended for tables users edit live)
- Every 15 min — typical
- Every 30 min — slower-moving
- Every 60 min — static catalogs (lowest battery cost)
(サーバー側の範囲は5~1440分です。この4つ以外のカスタム値は、AskUserQuestion が常に提供する自由入力の Other オプションから入力します。5 ≤ N ≤ 1440 であることを検証してください。)
テーブルごとの列選択 — テキストで入力します(列の一覧は種類が多すぎるため、複数選択には適しません)。
「
<table>の列を変更する場合は、1行に1つずつ入力してください:exclude <column>で同期対象から列を除外include <column>で現在除外されている列を追加allですべての列をマニフェストの状態にリセットskipで列を変更せずに維持」
指定されたすべての列が .datamodel-manifest.json に存在することを検証します。入力ミスがあれば、最も近い候補の列を提案して拒否します。
Step 3.5e — 再確認
選択したすべてのサブフローの完了後、概要を再表示します(Step 3.5a の形式)。変更された行には、色を変えるか先頭に * を付けて → updated と表示します。その後、Step 3.5b を再実行します。同じ3つの選択肢を持つ AskUserQuestion を表示します。ユーザーは再度調整することも、承認することも、キャンセルすることもできます。
このループの上限は、明示的な回数ではなくユーザーの忍耐です。「調整」を繰り返し選択して「承認」も「キャンセル」もしない場合も、ユーザーの選択です。各ループは取り消し可能で、Dataverse にはまだ何も反映されていません。
ステップ 3.5f — メモリーバンクのチェックポイント(Accept and publish の後)
## Offline profile
status: in-progress
profileName: <name>
mode: create-new | extend
configReview: accepted
設計上の理由。 元のステップ 3.5 では、会話形式を維持するため、自由記述の返信(「
acceptと入力するか、英語で編集内容を説明してください」)を使用していました。実際には、ユーザーが正規表現パーサーで認識できない応答(change scope of contact to teamonly、set sync to 10など)を入力し、スキルが編集を黙って破棄したり、追加の混乱を招く確認質問をしたりしていました。上記のAskUserQuestionフローでは、列挙可能なフィールド(スコープ、同期間隔、最上位の判断)に関する解析リスクを排除しつつ、真に自由形式のフィールド(名前、説明、列リスト)については自由記述の経路を維持します。その結果、一般的な調整における曖昧なやり取りがなくなり、入力ミスによるエラーが減り、/create-mobile-appの計画承認 UX と同等になります。
ステップ 4 — 必要に応じて内部の enable-tables-offline ワークフローを実行する
テレメトリのチェックポイント:enable_dataverse_tables_offline
ゲート 1 で変更が必要なテーブルが特定された場合は、
${PLUGIN_ROOT}/skills/enable-tables-offline/SKILL.md を読み、承認済みのテーブル
リストと、以下の完全なスコープ付き引き継ぎ情報を使用して実行します。設定レビューはすでに承認済みである必要があります。保存済みのマニフェストも、テーブルリストだけの提示も承認にはなりません。
$ARGUMENTS: --working-dir '<working_dir>' <comma-separated approved logical names>
Context:
MOBILE_APP_ORCHESTRATING=1
orchestrator: setup-offline-profile
working_dir: <working_dir>
phase: implementation
approved_scope:
environmentId: <selected-environment-id>
environmentUrl: <envUrl>
tenantId: <tenantId>
tables: <exact Gate 1-approved prerequisite table allowlist>
operations: <approved IsAvailableOffline/ChangeTrackingEnabled changes>
publication: <approved targeted publication; broader fallback only if separately approved>
supplied_answers: <current offline gate responses>
処理が戻るまで待ち、文字どおりの1行目のステータスを解析します。DONE なら続行します。
DONE_WITH_CONCERNS の場合は、続行する前にその内容を提示する必要があります。NEEDS_CONTEXT の場合は、
この所有者の承認済みルート/スコープ内で不足しているコンテキストを解決するか、ブロッカーを返します。別のアプリで再ディスパッチしたり、承認を推測したりしてはいけません。
BLOCKED の場合は、ブロック状態を上位に伝えます — 停止します。
すべてのテーブルがすでに有効になっている場合は、このステップをスキップします。
ステップ 5 — プロファイルシェルを POST する
テレメトリのチェックポイント:create_offline_profile_shell
開始前に表示:
「→ MobileOfflineProfile レコード(Name と Description のみ)を作成しています…」
create-new モードの場合:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"mobileofflineprofiles" \
--tenant-id "<tenantId>" \
--body '{
"name": "<app name> Offline Profile",
"description": "<auto-generated description referencing app name + scope summary>"
}' \
--include-headers
OData-EntityId レスポンスヘッダーから mobileofflineprofileid を取得します(/add-dataverse のステップ 5b と同じパターンです)。
extend モードの場合:ステップ 2 の既存の mobileofflineprofileid を再利用します。
memory-bank.md に書き込みます:
## Offline profile
status: in-progress
profileId: <guid>
profileName: <name>
mode: create-new | extend
gate1: approved
(ゲート 2 — 削除済み、ステップ 3.5 に統合)
ステップ 6 — プロファイル項目を POST する
テレメトリのチェックポイント:add_tables_to_offline_profile
開始前に表示:
「→ MobileOfflineProfileItem レコードを 件作成しています(テーブルごとに1件、順次処理)…」
⚠️ 並行処理のルール。 プロファイル項目は、親プロファイルを介して相互に暗黙的に参照します。POST は一度に1件ずつ、順次実行してください。mobileofflineprofileitem エンティティは EntityMetadata が保持するメタデータロックを保持しませんが、各 POST の検証処理では隣接する項目が読み取られます。並行して POST すると、まれに 412 PreconditionFailed が返されます。順次処理が安全な方法です。
各テーブルについて、順番に実行します:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"mobileofflineprofileitems" \
--tenant-id "<tenantId>" \
--body '{
"name": "<table display name>",
"[email protected]": "/mobileofflineprofiles(<profileId>)",
"selectedentitytypecode": "<table-logicalname>",
"recorddistributioncriteria": <0|1|2>,
"recordsownedbyme": <bool>,
"recordsownedbymyteam": <bool>,
"recordsownedbymybusinessunit": <bool>,
"getrelatedentityrecords": true,
"syncintervalinminutes": 10
}' \
--include-headers
レスポンスヘッダーから各 mobileofflineprofileitemid を取得します。ステップ 7(関連付け)とステップ 9(offline-profile.json)で必要となるため、ローカルマップ tableLogicalName → itemId に保存します。
ここでは selectedcolumns は設定しません — ユーザーが列のサブセットを確認した後、ゲート 3/ステップ 7 で追加します。
各 2xx の後に ✓ <table> と表示します。
(ゲート 3 — 削除済み、ステップ 3.5 に統合)
ステップ 7 — 関連付けを POST し、selectedcolumns を PATCH する
テレメトリのチェックポイント:configure_offline_profile_associations
開始前に表示:
「→ 関連付けの行を作成し、各プロファイル項目の selectedcolumns を PATCH しています…」
ステップ 7a — mobileofflineprofileitemassociation 行を POST する
2026-05-24 および 2026-05-25 のメーカー ポータルでの実測キャプチャにより、関連付けの作成が可能になりました。手順(selectedrelationshipsschema フィールドは不要です。サーバーが設定します):
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"mobileofflineprofileitemassociations" \
--tenant-id "<tenantId>" \
--body '{
"name": "<relationshipSchemaName>",
"relationshipdisplayname": "<relationshipSchemaName>",
"relationshipid": "<MetadataId-of-1:N-relationship-from-architect>",
"[email protected]": "/mobileofflineprofileitems(<PARENT-item-id>)"
}' \
--include-headers
⚠️ 方向に関する重要なルール。
regardingobjectidはプロファイル項目の**親(1 側)**です。account → orderlineの 1:N 関係の場合、関連付けはaccountプロファイル項目にaccount_orderline関係とともに存在します(EntityDefinitions(LogicalName='account')/OneToManyRelationshipsから読み取ります)。orderline(子)側で POST すると、「この Related 専用テーブルには関係が指定されていません」を示す0x80071140によりPublishXmlが失敗します。これが典型的なバグです。アーキテクトのステップ 5 では、親をキーとする出力を生成するために、親のOneToManyRelationshipsを明示的にたどるようになりました。
アーキテクトの提案に含まれる各(親項目、子への 1:N 関係)ペアについて、以下を行います。
EntityDefinitions(LogicalName='<PARENT-table>')/OneToManyRelationshipsでSchemaName === <relationshipSchemaName>を条件に絞り込み、relationshipid(MetadataId GUID)を解決します。親テーブルごとに検索結果をキャッシュします。- 関連付けを POST します(順次実行してください。並列 POST は、まれに 412 PreconditionFailed を返します)。
OData-EntityId応答ヘッダーから、新しいmobileofflineprofileitemassociationidを取得します。
重複時のスキップルール。 親プロファイル項目の
recorddistributioncriteria=1(すべてのレコード)の場合、アーキテクトはその項目の関連付けを削除しているはずです(ステップ 5 の削除ルールに従います)。念のため、該当する関連付けが残っていた場合は POST 時にスキップします。次のように表示します:↷ Skipping <association> on All-records parent <table> — redundant, all rows download anyway
公開前の循環検出。 ステップ 8 で公開する前に、作成した関連付けから関係グラフを構築し、DFS で循環を検出します。循環(例:
account → task → account)がある場合は、ユーザーに関連付けを 1 つ削除して、該当するペアについてこのステップをやり直すよう促します。そうしないと、ステップ 8 で0x80071141が返されます。shared/references/dataverse-offline-api.md §6b を参照してください。
冪等性。 既存の(項目、関係)ペアを再度 POST すると
409 Conflictが返されますが、dataverse-request.jsのlooksLikeDuplicateによる復旧処理で成功として扱われます。一部失敗後の再実行も安全です。
アーキテクトの提案に関係が 1 つも含まれない場合は、ステップ 7a 全体をスキップしてください(まれなケースで、通常はフィクスチャー向けの単一テーブルプロファイルです)。
ステップ 7b — 各項目の selectedcolumns を PATCH する
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> PATCH \
"mobileofflineprofileitems(<itemId>)" \
--tenant-id "<tenantId>" \
--body '{
"selectedcolumns": "<JSON string — see below>"
}'
selectedcolumns の形式(メーカー ポータルで作成された既存のプロファイルを確認して検証済みです。注意事項については計画の既知のブロッカー §10 を参照してください):
{
"Columns": ["cr123_title","cr123_body","cr123_visitid","modifiedon","createdon","statecode"]
}
メモ フィールドに、文字列化した JSON として格納します。
ゲート 3 で syncintervalinminutes を編集した場合は、同じ PATCH に含めてください。
ステップ 8 — 公開する
テレメトリのチェックポイント:publish_offline_profile
開始前に表示:
"→ プロファイルを公開しています(対象を絞った PublishXml)…"
検証ステップは意図的にスキップします。 2026-05-17 の実測によると、ドキュメントに記載された
Validateアクションのリクエスト本文の形式はサーバーに拒否されます。メーカー ポータルもValidateを呼び出しません(2026-05-24 のキャプチャで確認済み)。公開時の検証は、PublishXml の一部としてサーバー側で実行されます。isvalidated=trueは個別の Validate ではなく、公開呼び出し自体によって設定されます。
対象を絞った PublishXml — メーカー ポータルのパターン(2026-05-24 の実測):
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"PublishXml" --tenant-id "<tenantId>" --body '{
"ParameterXml": "<publish><mobileofflineprofiles><mobileofflineprofile><profileId></mobileofflineprofile></mobileofflineprofiles></publish>"
}'
組織全体のカスタマイズではなく、このプロファイルのみを公開します。共有環境では、実測上 PublishAllXml より大幅に高速で、レート制限も受けにくくなります。
以下の修復ヘルパーを使用する場合は、orchestrator: setup-offline-profile、同じ絶対パスの working_dir、選択した環境/テナント/プロファイル、およびユーザーが明示的に承認した正確な修復範囲を指定して、調整リファレンスのスコープ指定ヘルパーの引き継ぎを使用してください。--working-dir '<working_dir>' と、選択したプロファイル/テーブルの引数を渡してください。元のプロファイル作成時の承認から、新たな修復の承認を推測してはなりません。
**400 / 0x80071141「循環関係」の場合:**プロファイルの関連付けグラフに循環があります(例:account → task → account)。エラーメッセージからパスを解析し、問題のある関連付けのうち1つを削除するようユーザーに確認します。次に、DELETE /mobileofflineprofileitemassociations(<id>) でその関連付け行を再度削除してから、公開を再試行します。shared/references/dataverse-offline-api.md §6bを参照してください。
**Related のみのテーブルで、400 / 0x80071140「関係が指定されていません」の場合:**プロファイル項目の recorddistributioncriteria=0 に対し、その項目を参照する関連付けがありません。エラーメッセージからテーブル名を解析し、次の2つの選択肢をユーザーに提示します。
/add-table-to-offline-profile --table <name> --add-associations— アーキテクトを再実行して関係を検出し、不足している関連付けをPOSTします。/edit-offline-profile --table <name> --scope 2 --me— スコープを組織の行 + ユーザーの行に変更します(アーキテクトのフォールバック)。
新規の /setup-offline-profile 実行では、ステップ7aでステップ8の公開前に関連付けをPOSTするため、このエラーは発生しないはずです。ただし、v0.1の古い「関連付けなし」手順で公開されたプロファイルを後から編集するレトロフィットのシナリオでは、このエラーが発生する可能性があります。Dataverseの公開バリデーターは、現在の未コミット状態ではなく、以前に公開されたスナップショットと比較しているようです。2026-05-24にchanel-rmで実証的に確認されています。
**フォールバック — PublishAllXml:**対象を指定した公開を完了できず、かつ環境内のすべての保留中のカスタマイズを公開することについて、ユーザーから別途承認を得た場合に限ります。プロファイルに限定された承認、タイムアウト、またはレート制限は、より広範な公開への同意を意味しません。それ以外の場合は、範囲を拡大せずに失敗を報告してください。
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"PublishAllXml" --tenant-id "<tenantId>" --body '{}'
タイムアウトしたが成功しているパターンに対処する — 共有環境で実証的に確認されています(CRM527116 と chanel-rm のデモ)。PublishAllXml は4回の再試行を伴う429のバックオフを発生させ、dataverse-request.js は約2分後にクライアント側でタイムアウトしますが、公開はサーバー側でコミットされています。対象を指定した PublishXml ではほとんどの場合これを回避できますが、フォールバック経路でもこのケースに対処する必要があります。
POST呼び出しの戻り後の手順:
-
ステータスが
204の場合 → 公開成功です。続行します。 -
ステータスが
0で、エラーにRequest timed outまたは429 rate-limitedが含まれる場合 → 失敗として扱ってはなりません。以下の確認用GETを実行します。cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; } node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \ "mobileofflineprofiles(<profileId>)?\$select=componentstate,publishedon" --tenant-id "<tenantId>"componentstate == 0かつpublishedonが直近5分以内のnullではないISO8601タイムスタンプの場合 → 成功として扱います。次のように出力します:↷ PublishAllXml client timed out but committed server-side (componentstate=0, publishedon=<ts>).続行します。componentstate == 1(未公開)の場合 → 公開は実際には反映されていません。進行中の環境公開が完了するのを待つため、30秒待機してから1回だけ再試行します。2回目も失敗した場合は、DONE_WITH_CONCERNS: publish timed out twice; profile saved but unpublished — re-run /setup-offline-profile or PublishAllXml manuallyを返します。
-
ステータスが
204以外のその他の値の場合 →BLOCKED: publish failed with <status>を返します。
成功を確認したら、プロファイルを再度GETし、成果物のステップで publishedon を確認します。
ステップ9 — 成果物を保存する
テレメトリチェックポイント:persist_offline_profile_snapshot
開始前に出力:
「→ offline-profile.json + memory-bank.md を書き込んでいます…」 重要:このスキルでは、
power.config.jsonを変更してはいけません。 このファイルはpa app initが所有し、スキーマは上流ツールによって管理されています。カスタムフィールドを追加すると、再初期化時に上書きされるおそれがあり、上流のスキーマが変更された場合に動作しなくなります。アプリレベルのオフライン設定はすべて、当方が管理するoffline-profile.jsonのappConfigブロックに記述します。
9a — プロジェクトのルートに offline-profile.json を書き込みます。正規スキーマ(scripts/verify-offline-profile.js の想定と一致している必要があります。このスクリプトは relationshipId を使って関連付けを比較します):
{
"profileId": "<guid>",
"name": "<name>",
"publishedOn": "<iso8601>",
"mode": "create-new | extend",
"appConfig": {
"enabled": true,
"serverRowLimit": 2000,
"/* BEGIN OFFLINE-CONFIG-WORKAROUND */": "remove when SDK gaps are fixed upstream — tracked in microsoft/power-platform-skills/plugins/mobile-apps/template#main (instanceUrl) + PowerApps-Client (useDda + entitiesIncluded). Bracket exists so the future cleanup diff is mechanical.",
"useDda": false,
"entitiesIncluded": ["<logicalName-1>", "<logicalName-2>", "..."],
"instanceUrl": "<envUrl>",
"/* END OFFLINE-CONFIG-WORKAROUND */": ""
},
"tables": [
{
"logicalName": "cr123_order",
"itemId": "<guid>",
"recordDistributionCriteria": 2,
"recordsOwnedByMe": true,
"recordsOwnedByMyTeam": false,
"recordsOwnedByMyBusinessUnit": false,
"syncIntervalInMinutes": 10,
"selectedColumns": ["cr123_ordernumber", "cr123_total", "..."],
"schemaColumns": ["cr123_ordernumber", "cr123_total", "cr123_notes", "..."],
"relationships": [
{
"schemaName": "cr123_order_cr123_orderline",
"relationshipId": "<MetadataId-guid-of-the-1:N-relationship>",
"targetEntity": "cr123_orderline",
"associationId": "<mobileofflineprofileitemassociationid-guid>"
}
]
}
]
}
スキーマの不変条件(検証スクリプトによって適用されます):
profileIdは、公開されるmobileofflineprofileidの信頼できる唯一の情報源です。ランタイムと/edit-offline-profile、/assign-offline-profileはここから値を読み取ります。power.config.jsonにも書き込んではいけません。appConfigには、起動時にランタイムが使用するアプリレベルのオフライン設定をすべて含めます。OFFLINE-CONFIG-WORKAROUNDで囲まれた3つのフィールドは一時的なもので、上流での削除に向けて追跡されています。将来のgit diffでクリーンアップの範囲がこのブロックだけになるよう、これらを連続して配置してください。relationships[]は 親 テーブルのエントリ(1:N 関係の1側のテーブル)に記述します。cr123_orderlineなどの子のみのテーブルでは、relationships: []とします。relationships[]の各エントリには、schemaName(EntityDefinitions メタデータの関係のSchemaName)、relationshipId(関係のMetadataIdGUID。正規の比較キーであり、サーバー側の relationshipname の書式に左右されません)、targetEntity(子エンティティの論理名)、associationId(作成されたmobileofflineprofileitemassociationid)を含めます。recordDistributionCriteria=1(すべてのレコード)の親には、常にrelationships: []を指定します。関連付けは冗長になるためです(アーキテクトのステップ5のプルーニング規則を参照)。schemaColumns[]は スキーマ調整のベースラインです。この項目の作成時点で存在していた、そのテーブルのスキーマ列の論理名一式(.datamodel-manifest.json由来)を記録します。selectedColumnsとは異なり、ランタイムが同期するために選んだ列だけではありません。schemaColumnsには、selectedColumnsから意図的に除外した列も含め、調整時点でスキーマに存在するすべての列を記録します。scripts/offline-profile-delta.jsは、後続のマニフェスト列とこのベースラインを比較し、意図的な除外を誤ってフラグ付けせずに、スキーマに 新たに追加された 列(manifest.columns − schemaColumns)を検出します。各テーブルのマニフェストエントリから値を設定してください。再利用されたテーブルについてマニフェストに列が記載されていない場合は、[]を記述します。offline-profile-reconciliation.md を参照してください。- JSON はコメントをサポートしていません。上記の
/* BEGIN/END OFFLINE-CONFIG-WORKAROUND */キーは、スキルの作成者向けの説明として示したものです。これらのキーをそのままoffline-profile.jsonに書き込んではいけません。 スキルが実際にファイルを修正するときは、appConfig内に実際のフィールド(useDda、entitiesIncluded、instanceUrl)だけを書き込み、これらを連続して配置してください。
Node スクリプトの例(ファイルを一度に書き込みます。power.config.json の読み取り・変更・書き戻しは行いません):
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node -e '
const fs = require("fs");
// Genuine app-level offline config (always written)
const appConfig = {
enabled: true,
serverRowLimit: 2000,
};
// BEGIN OFFLINE-CONFIG-WORKAROUND (remove when underlying SDK gaps are fixed
// upstream — tracked separately in plugins/mobile-apps/template and PowerApps-Client).
appConfig.useDda = false;
appConfig.entitiesIncluded = [/* logicalName for each table in the profile */];
appConfig.instanceUrl = "<envUrl>";
// END OFFLINE-CONFIG-WORKAROUND
const profile = {
profileId: "<guid-from-step-5>",
name: "<name>",
publishedOn: "<iso8601>",
mode: "create-new", // or "extend"
appConfig,
tables: [/* one entry per profile item — see schema above */],
};
fs.writeFileSync("offline-profile.json", JSON.stringify(profile, null, 2) + "\n");
'
各フィールドの理由:
| フィールド | レイヤー | 理由 |
|---|---|---|
profileId | A(本来の値) | Dataverse から公開された mobileofflineprofileid です。実行時に、このプロファイルのマニフェストが取得されます。offline-profile.json がこの値の唯一の信頼できる情報源です。 |
appConfig.enabled | A(本来の値) | プロジェクトがオフライン対応であることを示します。起動時に実行時環境によって使用されます。 |
appConfig.serverRowLimit | A(本来の値) | Image 2 の「Data row limit」フィールド(既定値は 2000)に対応します。v0 では設定のみの値であり、実行時の適用はレイヤー B の役割です。 |
appConfig.useDda | オフライン設定の回避策 | SDK の不具合のある shouldUseDda ゲート(エンティティセットと論理名の不一致)を回避します。@microsoft/react-native-dataverse-offline のゲートが調整されたら削除してください(PowerApps-Client で追跡中)。 |
appConfig.entitiesIncluded | オフライン設定の回避策 | SDK のオフライン初期化では、プロファイルに含まれるエンティティの論理名を把握するためにこのリストが読み込まれます。現在、SDK は実行時に公開済みプロファイルマニフェストからこのリストを導出しないため、必須です。プロファイル内の各テーブルにつき論理名を 1 つ指定してください(つまり、以下の各 tables[] エントリの logicalName フィールドです)。 |
appConfig.instanceUrl | オフライン設定の回避策 | オフライン中に api.powerplatform.com への往復通信を必要とせず、SDK に静的な組織名を渡すことで、オフラインでのコールドスタートを可能にします。値はステップ 1 で取得したものと同じ <envUrl> です(例:https://orgXXX.crm.dynamics.com)。以前は power.config.json.databaseReferences[*].databaseDetails.linkedEnvironmentMetadata.instanceUrl に書き込まれていましたが、現在、実行時環境はここにある appConfig.instanceUrl から読み取ります。上流では plugins/mobile-apps/template で追跡中です。 |
このスキルから
power.config.jsonを変更しないでください。 以前のドラフトでは、同じフィールドをpower.config.json.offline.*とdatabaseReferences[*].databaseDetails.linkedEnvironmentMetadata.instanceUrlに書き込んでいました。power.config.jsonはスキーマを管理していないpa app initによって生成されるため、これらの変更は元に戻されました。カスタムフィールドを追加すると、再初期化で消去されたり、上流のスキーマ変更によってこのスキルが壊れたりする可能性があります。ここにpower.config.jsonを変更するコードパスが残っている場合は、バグとして扱ってください。
9c — memory-bank.md の ## Offline profile を更新します:
status: done
profileId: <guid>
profileName: <name>
mode: create-new | extend
publishedOn: <iso8601>
gate1: approved
gate2: approved
gate3: approved
tablesCount: <N>
associationsCount: <M>
9d — native-app-plan.md に ## Offline Profile セクションを追加し、最終状態を要約します(データモデルのセクションのパターンに合わせます)。
ステップ 9.5 — 検証
テレメトリチェックポイント:verify_published_offline_profile
開始前に表示:
「→ サーバー上のプロファイルが offline-profile.json と一致するか確認しています…」
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/verify-offline-profile.js" <envUrl> \
--project-root '<working_dir>' --tenant-id "<tenantId>"
JSON 出力を確認します:
status | 対応 |
|---|---|
ok | すべてのチェックに合格しました。ステップ 10 に進みます。 |
drift | drift[] 配列をユーザーに提示します。新規作成直後に最もよく発生するドリフトは unpublished(公開処理の競合)です。§9 の公開をもう一度実行し、再検証してください。それ以外のドリフトは重大なバグを示します。黙って隠さず、すべてのドリフト項目を列挙して DONE_WITH_CONCERNS を返してください。 |
missing | offline-profile.json が書き込まれていません。ステップ 9a が失敗しても通知されなかったようです。停止して、再実行するようユーザーに依頼してください。 |
error | 認証またはネットワークの問題です。内容を提示して停止してください。 |
この検証スクリプトは /preview-offline-scope(v0.2)の基準実装でもあります。ここでステップとして実行することで、新規作成のたびに確実にテストできます。
ステップ 10 — 概要
次を表示します:
✓ Mobile Offline Profile created.
Profile name : <name>
Profile ID : <guid>
Tables : <N> (<M> required prereq enablement)
Relationships: <K> associations
Published : <iso8601>
Saved to project:
- offline-profile.json (profile metadata + appConfig + tables)
- memory-bank.md (## Offline profile section)
- native-app-plan.md (## Offline Profile section)
Note: power.config.json was NOT modified (owned by pa app init).
Next steps:
- /assign-offline-profile → assign users / teams to this profile (not yet implemented — v0.3)
- /preview-offline-scope → estimate download size before pushing the app (not yet implemented — v0.2)
- /edit-offline-profile <table> → re-scope one table (not yet implemented — v0.2)
Runtime: The template bundles @microsoft/power-apps-native-offline.
@microsoft/power-apps-native-host consumes the profile and owns local SQLite access,
queued synchronization, reconnect behavior, and status UX. This skill configures
that runtime; it does not scaffold a second app-owned store, queue, or sync engine.
ステータスコード(最終行)
DONE— プロファイルを作成して公開し、成果物を書き込みましたDONE_WITH_CONCERNS: <list>— 作成は完了しましたが、注意点があります(検証を省略、一部の列にフラグが設定、一部のテーブルをカスタマイズ不可)NEEDS_CONTEXT: <missing>— データモデルがない、環境 URL を解決できないなどBLOCKED: <reason>— 認証に失敗、PrivilegeCheckFailed、環境 URL に到達できない、またはサブスキル/enable-tables-offlineが BLOCKED を返した
障害からの復旧
各ステップで memory-bank.md にチェックポイントを書き込みます。フローの途中で失敗した場合:
| 失敗箇所 | 復旧方法 |
|---|---|
| Gate 1 / Step 4 | /setup-offline-profile を再実行します — Step 1b の再開処理が開始されます |
| Step 5 | 途中まで作成されたプロフィールをソフトデリートし、Step 5 から再試行します |
| Step 6(M 件中 N 件目) | N+1 件目から再開します。前の項目はすでに確定しています |
| Step 7(関連付け) | 再開します — 関連付けは追加型です。既存のペアを再度 POST すると 409 が返されます(無視してください) |
| Step 8(公開) | 公開を再実行します。プロフィールは公開しなくても機能しますが、maker ポータルには表示されません |
セッション終了後も memory-bank.md に status: in-progress のままのプロフィールを残さないでください。次のセッションの Step 1b で、再開するか削除するかを確認するプロンプトが表示されます。