Crop Mapping Evaluation under Sampling Bias
Government agencies use crop maps to estimate production, monitor food security, and set agricultural policy. These crop maps are usually validated against field labels, but these labels are rarely a random sample of the area the map covers. Field teams tend to label parcels near roads and skip ones that are small or hard to reach, so performance measured on held-out labels mainly describes the places they visited. We call the difference between this reported performance and performance over the whole mapped region the deployment performance gap. To estimate performance over the whole region, we use a weighted form of prediction-powered inference (PPI). The classifier's predictions on unlabeled points across the region give a first estimate, and its errors on the labeled points correct that estimate, with more weight on labels from under-sampled conditions. We test this in five European regions where crop registers label every declared parcel, so the true performance is known. Simulating six documented collection practices there produces gaps of up to 0.20 macro-F1. On the collection rule that creates the largest gap in each region, 5 km block cross-validation still overestimates macro-F1 by as much as 0.18, while PPI with weights estimated from satellite embeddings reduces the largest error across regions to 0.07. Importance-weighted cross-validation with the same weights does almost as well, so most of the improvement comes from the weights themselves. We also apply the method to three Kenyan datasets that have no region-wide reference labels. For a roadside dataset collected with helmet-mounted cameras, the estimated macro-F1 falls from 0.93 under random cross-validation to 0.61, although the correction relies on a small number of heavily weighted labels. Our code is available at microsoft/pappi.
Comments: 17 pages, 4 figures, 5 tables. Code: microsoft/PaPPI
Microsoft.UI.Reactorを学習する
Microsoft.UI.Reactorとは
Microsoft.UI.Reactor は、C#で WinUI アプリを宣言的に作る実験的なフレームワークです。
※2026/11/01時点で 0.1.0-preview.16 版です。
試す
プロジェクトを作成する
winget install Microsoft.WinAppCli
winapp new -t reactor -n Kashin777.UI.Reactor
cd Kashin777.UI.Reactor
構成
!image.png
csproj(抜粋)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Windows GUI アプリとしてビルド -->
<OutputType>WinExe</OutputType>
<!-- .NET 10 と Windows SDK 10.0.26100.0 を対象にする -->
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
<!-- サポートする Windows の最低バージョン -->
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
<!-- WinUI アプリとしてビルドし、MSIX のビルド機能を有効にする -->
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<!-- C# の基本設定 -->
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<!-- Windows アプリのビルドに必要なパッケージ -->
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="*" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="*" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools.WinApp" Version="*" />
<!-- Microsoft.UI.Reactor -->
<PackageReference Include="Microsoft.UI.Reactor" Version="0.1.0-preview.16" />
</ItemGroup>
</Project>
App.cs
using Microsoft.UI.Reactor;
using Microsoft.UI.Reactor.Core;
using Microsoft.UI.Reactor.Layout;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using static Microsoft.UI.Reactor.Factories;
// To learn more about Reactor, the Reactor project structure, and more about
// our project templates, see: https://github.com/microsoft/microsoft-ui-reactor
ReactorApp.Run<App>("Kashin777.UI.Reactor");
class App : Component
{
public override Element Render()
{
var titleBar = TitleBar("Kashin777.UI.Reactor")
.Flex(shrink: 0);
// This is the main content area of your application.
// Add your UI elements here.
var content = Border(Empty()).Flex(grow: 1, basis: 0);
return FlexColumn(titleBar, content)
.Backdrop(BackdropKind.Mica);
}
}
とりあえず実行
dotnet run
!image.png
画面を実装する
公式ドキュメントのCounter Example に従い、App.cs を修正してみます。
public override Element Render()
{
var titleBar = TitleBar("Kashin777.UI.Reactor")
.Flex(shrink: 0);
var (count, setCount) = UseState(0); // countプロパティとsetterを作成
var content = VStack(spacing: 12, // Vertical StackElement
TextBlock($"Count: {count}").FontSize(20).SemiBold(), // element[0] TextBlock
HStack(spacing : 8, // element[1] Horizontal StackElement
Button("- 1", () => setCount(count - 1)), // 1デクリメント
Button("Reset", () => setCount(0)), // リセット
Button("+ 1", () => setCount(count + 1)) // 1インクリメント
)
).Padding(24);
return FlexColumn(titleBar, content)
.Backdrop(BackdropKind.Mica);
}
dotnet run
!image.png
基礎
フック
フック
インタラクティブなUIには必ず状態が必要です。Reactorでは、状態はUseState時間とともに変化する値を管理するための主要なフックです。
コンポーネントは複数回呼び出すことができUseState、各呼び出しは独立した値を追跡します。
var (count, setCount) = UseState(0);
var (firstName, setFirstName) = UseState("");
var (fontSize, setFontSize) = UseState(16.0);
| フック | 戻り値 | 目的 |
|--|--|--|
| UseState | (T value, Action<T> set) | リアクティブな状態 — set 時に再レンダリングされます。 |
| UseReducer | (T value, Action<Func<T,T>> update) または (TState, Action<TAction>) | 関数型または Redux スタイルの更新。 |
| UseEffect | void | コミット後の副作用。Func<Action> オーバーロードを使用すると、次のエフェクトの実行前およびアンマウント時にクリーンアップが実行されます。 |
| UseMemo | T | 計算結果のキャッシュ。依存項目のいずれかが不等となった場合に再実行されます。 |
| UseRef | Ref<T>(mutable .Current 付き) | 変更時でも再レンダリングを行わずに、レンダリング間を通じて状態を保持します。 |
| UseCallback | Action | レンダリング間を通じて安定したデリゲート識別子。 |
| UseContext | T | 周囲の Context 値を読み取ります。 |
| UseObservable | T | 追跡対象の INotifyPropertyChanged ソースが変更を発生させた際に再レンダリングを行います。 |
| UseExternalStore | TSnapshot | subscribe/getSnapshot ストアを Reactor にブリッジし、スナップショットが変更された場合にのみ再レンダリングします。 |
| UseResource | AsyncValue<T> | キャッシュされた非同期読み取り(「非同期リソース」を参照)。 |
| UsePersisted | (T, Action<T>) | プロセス内のアンマウント/リマウント後も存続する UseState — メモリ内、終了時にクリアされます(「永続性」を参照)。 |
レイアウト
レイアウト
| 要素 | 目的 |
|--|--|
| VStack | 縦積み(上から下へ子要素を配置)
| HStack | 水平スタック(左から右へ)
| Grid | 行/列グリッド(比例サイズ)
| ScrollView | オーバーフローコンテンツ用のスクロール可能なラッパー
| Border | 背景、角丸、ストローク付きコンテナ
コントロール
コントロールカタログ
| カテゴリ | 中身は? |
|--|--|
| フォーム | テキスト入力、ピッカー、ボタン、検証プリミティブ |
| コレクション | リスト、グリッド、仮想化リスト、リピーター |
| テキストとメディア | 見出し、リッチテキスト、画像、メディアプレーヤー |
| ステータスと情報 | 進捗状況、情報バー、バッジ、指導のヒント |
| レイアウトとコンテナ | スタック、グリッド、境界線、スクロールホスト、ペイン |
| ナビゲーション | ナビゲーションビュー、フレーム、タブ、パンくずリスト、ピボット |
| 図形とアイコン | 長方形、楕円、線、パス、アイコンのソース |
| ダイアログとフライアウト | コンテンツダイアログ、メニューフライアウト、コマンドバーフライアウト |
| データシステム | DataGrid、列、データソース、ページング |
| チャート作成 | 線グラフ、棒グラフ、面積グラフ、円グラフ、力グラフ |
ホットリロード
ホットリード
dotnet watch run
アプリを起動したまま、ボタンのラベルを変更して保存したら
PS C:\Users\Kashin777\source2\repos\Kashin777.UI.Reactor> dotnet watch run
dotnet watch 🔥 Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload.
dotnet watch 💡 Press Ctrl+R to restart.
復元が完了しました (0.0 秒)
0.1 秒後に 成功しました をビルド
info NETSDK1057: プレビュー版の .NET を使用しています。https://aka.ms/dotnet-support-policy をご覧ください
Kashin777.UI.Reactor net10.0-windows10.0.26100.0 win-x64 成功しました (0.4秒) → bin\Debug\net10.0-windows10.0.26100.0\win-x64\Kashin777.UI.Reactor.dll
0.5 秒後に 成功しました をビルド
dotnet watch ⌚ Loading projects ...
dotnet watch ⌚ Loaded 1 project(s) in 0.5s.
C:\Users\Kashin777\source2\repos\Kashin777.UI.Reactor\Properties\launchSettings.json からの起動設定を使用中...
⠼ Launching packaged application...
✅ 43A37F59-B43C-4C5A-9E09-1DE873E18ECA_1z32rh13vfry6 launched (PID: 22536)
dotnet watch ⌚ File updated: .\App.cs
dotnet watch ⚠ [Kashin777.UI.Reactor (net10.0-windows10.0.26100.0)] Further changes won't be applied to this process.
ドキュメントに従い dotnet watch run で起動したのですが、App.cs の変更は検知されるもののリロードされず...
Reverse Engineering Block Blast
Block Blast looks like a puzzle game. A decompile of the app suggests it's closer to a per-player ad pricing engine with a puzzle attached. Three tree-based models run on your phone, a bandit experiment tunes when you lose, and a rule decides your next three pieces based on what ad is sitting in memory.
The Problem It's Solving
The game is free and has no ad-free purchase, so revenue depends on rewarded and full-screen ads. Sensor Tower estimates put its ad revenue at roughly $127 million for January to May 2026, ahead of Candy Crush Saga at $81.1 million.
Ad value varies a lot per player (country, device, history), and the best moment to show a rewarded ad is right after a loss. Making that work needs per-player prediction, per-deal control of the pieces, and the ability to change both without shipping an app update.
How the System Is Built
The research is Ayo Omolewa's breakdown of Android 10.8.2 and iOS 7.4.9, using jadx and Ghidra. The store APK holds very little. Logic ships as "traits" (modules with variants called arms), and at launch the server tells the app which arm of which trait you get. His config named about 700 traits, selected 254, and 101 were fetched after install as XXTEA-encrypted, Brotli-compressed JavaScript. Two players can run different games, and the studio can change yours silently.
The Models
| Model | Size and inputs | What it decides |
|---|---|---|
| XGBoost regression (xgboost_regression_model111.json) | 59 trees, depth up to 8, 27 inputs (18 about ads) | finalEcpm: your estimated ad value |
| XGBoost classifier (predict_travel_difficulty_dead) | 500 trees, 52 inputs | Where in a level the lethal puzzle lands |
| LightGBM | 1,000 trees, 93 inputs | Whether you'll be less active tomorrow |
The ad value model. The inputs are mostly money-related: prices of ads loaded today and yesterday, country, phone model, RAM, install date, and how your first game went. The trees lean hardest on first score, latest ad price, RAM, phone model and country. The inference code is a plain loop: start each tree at the root, go left or right on a feature threshold (missing values follow a default direction), add the leaf weight to a running sum starting at the base score. Omolewa's port reproduces the game's outputs to the last decimal. Changing one input on a made-up US player on an iPhone 15 gives:
| Change | Ad value (eCPM) |
|---|---|
| Baseline (US, first score 1,000) | 25.48 |
| Brazil | 8.08 |
| India | 5.59 |
| First score 500 / 2,000 / 10,000 | 25.79 / 21.12 / 20.34 |
The same US baseline on Android scores 48.96. The output feeds other rules. One compares your rewarded and full-screen prices and, if rewarded is worth at least twice full-screen in the shipped version, grants an extra revive (which plays a rewarded ad). Others add a full-screen ad when your price is high or skip full-screen ads when you're worth almost nothing.
The "where do you lose" model. The game scores 12 candidate options (4 values of a sw_process setting times 3 difficulty levels) and keeps the argmax. Inputs are mostly about your history: current level, attempts, games finished this week, time since install. The winning sw_process maps to a stretch of the level (first 30%, 30 to 80%, last 20%). On reaching it, players who usually accept revives (above 75%) get an extra one, and from the fourth deal after that the game requests the lethal puzzle. Other rules read the same pick the opposite way and make the level easier when it lands on the fourth option.
The churn model. If the LightGBM score is 0.69 or higher, a pink revive button replaces the normal one and skips the ad, once a day. It leans on app age, high score, RAM and average score.
Server-side models. Rules also call models named for churn, LTV, revive-click and xDeepFM. Those weights never reach the phone, so the only visible part is the request. One call to /v1/ecpm_prediction sends 40 fields, including carrier, storage, hour of day and recent ad prices.
The Rules That Act on the Predictions
These are hand-written, not learned.
RewardHighValueAdHarvestTrait fires when you finished your last three rewarded ads, the ad currently loaded is worth at least 3.5 times your last one (read from AppLovin MAX eCPM), and you're 1,000 points past your high score (500 or 750 in other arms). It then requests generator ZHI_SI_TI. The generator picks two pieces that fit and one that doesn't, searches every order and placement including line clears, and keeps the set only if nothing works. The code labels the pieces "lethal puzzle" in Chinese.
PersonalMarginBreakTrait gives every deal a 20% chance of the same hand once you're 10% past your record. MultiClearBoostThenKillTrait sends your user ID to two server endpoints, and for the tiers labelled "not sensitive to being forced to die," waits for a big clear, then requests the lethal puzzle a few rounds later once the game reaches roughly your usual length. FastHandPunishTrait asks for hard pieces when your last six sets averaged under 4.2 seconds and you're past 93% of your high score. MaturityDevelopmentV2Trait scores habit, skill and ad history (10.98, 14.66 and 19.27 in the live test), and when the total (44.91) is under 65 it swaps hard puzzles for easy fills. AdPlusMinusStrategyTrait adds a random bonus of up to 10% of your high score after one type of revive.
MABXiBaiTrait is a six-arm experiment on how soon the lethal puzzle may be requested: never, or after 4, 6, 10, about 17 or 30 minutes. Per arm it logs whether you started a new game within 15 minutes and the share of revive offers you accepted.
Why This Is a Bigger Deal Than It Looks
The ML itself is cheap: tree ensembles walked in a loop over JSON, no GPU, runs on a low-end phone and offline. The engineering is the delivery layer. Server-assigned arms, encrypted hot-loaded JavaScript and per-player A/B tests make this a feature-flag platform with bandit tuning, which is why it can be changed daily. Because the lethal-puzzle rule needs a rewarded ad loaded, it can't fire offline or with a phone-wide DNS blocker, while ad-independent rules keep running.
Apple permits JavaScript updates that don't change what the app is. Whether this qualifies is Apple's call.
The usual caveat applies: this is one researcher's analysis. mobilegamer.biz reported no reply from Hungry Studio, and TechRadar noted that independent verification matters. The evidence bundles (decoded rules, test scripts, hashes) are public at Ayoships if you want to run the checks yourself.
Availability and Access
The game is on Google Play and iOS. The decryption key and the steps for getting past the apps' protection aren't published.
If a free puzzle game ships three on-device models and a bandit experiment, the real question for developers isn't whether consumer apps use ML. It's how much of their behavior now lives in a config server instead of the binary.
Follow for more coverage on MCP, agentic AI, and AI infrastructure.
Inspired to write this by @StompnWorldfan's video on YouTube: watch it here.
7 reactions
Mentions
VS Code 拡張の Marketplace 公開を承認付きのまま PAT なしで自動化した 検証環境: GitHub Actions(ubuntu-latest) @vscode/vsce 4.1.0 対象: vscode-line-ref-copy(Marketplace) 変更: PR #45 背景 自作の VS Code 拡張を Marketplace に出している。v0.1.0〜0.1.2 は VSIX を作って、Marketplace の管理画面にドラッグ&ドロップで上げていた。 この手作業をやめたい、というのが出発点だ。 公開をわざと手動にしていた理由もある。リポジトリのリリース方針(release.md)で「公開は毎回 kyto が承認する」と決めていた。だから publish 用のワークフローは置かず、自動化は Issue #6(Open VSX / VS Code Marketplace への公開検討)の先送り扱いにしていた。 認証についても release.md に「PAT で公開する。長期の Marketplace PAT は 2026-12-01 に廃止予定と Microsoft が告知している」と書いていた。公式ドキュメントでも、Azure DevOps のグローバル PAT は 2026-12-01 に廃止とされている。 結論 承認を残すために手動にする必要はなかった。GitHub の environment に Required reviewers を付ければ、毎回の承認と自動化を両立できる。 Marketplace の Trusted Publishing(vsce publish --oidc)を使えば、PAT もシークレットもリポジトリに置かずに GitHub Actions から公開できる。 --oidc は vsce 4.0.0 では使えず、4.1.0 に上げたら通った。 ポリシーにはワークフローのファイル名まで登録するので、ファイル名は固定。private リポジトリだとポリシー作成から 48 時間以内に初回実行が必要なので、作るタイミングにも気をつける。 v0.1.3 をこの仕組みで初めて公開し、ワークフローは成功した(2026-10-29 15:23 JST 起動)。 旅路 承認ゲートは environment で作れる 手動にしていたのは「人が承認してから出す」を守るためだった。 でも GitHub Actions の environment に Required reviewers を設定すれば、その environment を使うジョブは承認されるまで始まらない。承認は残したまま、アップロードの手作業だけを消せる。 Marketplace 側の設定 publisher の管理画面 → Trusted Publishing → Create で、次を登録する。 Repository owner: kyto64 Repository: vscode-line-ref-copy Workflow: publish.yml Environment: release ワークフローのファイル名がポリシーに入るので、後から名前を変えないこと。publish.yml の先頭にもその旨をコメントで書いた。 公式ドキュメントによると、private リポジトリの場合はポリシー作成から 48 時間以内に設定したワークフローを走らせる必要がある。最初のトークン交換が成功すると、ポリシーが恒久的に有効になる。 今回は次の version(v0.1.3)の準備ができてからポリシーを作った。 GitHub 側の設定 Settings → Environments に release を作り、Required reviewers に自分(kyto64)を入れる。 タグを打っても、承認するまで公開ジョブは止まる。 ワークフロー 要点だけ書く。 on: push: tags: ["v*"] workflow_dispatch: inputs: tag: required: true permissions: contents: read jobs: publish: environment: release permissions: contents: read id-token: write steps: refs/tags/<tag> を checkout(persist-credentials: false) lint → テスト(xvfb-run)→ compile package.json の version とタグの一致、Marketplace に同じ version が無いことを確認 - run: npx @vscode/vsce publish --oidc 権限はトップレベルが contents: read だけ。id-token: write は publish ジョブだけに付ける。 タグ(refs/tags/<tag>)を checkout する。ブランチの HEAD からは公開しない。タグが無ければ落ちる。 package.json の version とタグ名が違えば落とす。 Marketplace に同じ version がすでにあれば落とす。vsce publish 自体も同じ version では失敗するが、その前に止める。 concurrency(cancel-in-progress: false)で同時に公開が走らないようにする。 vsce のバージョンで詰まる 最初は vsce 4.0.0 のままで、--oidc に対応していなかった。4.1.0 に上げて解決した。 devDependencies で 4.1.0 に固定している。 リリースの流れ version と CHANGELOG.md を更新した PR をマージする。 GitHub Release を作り、v0.1.3 タグを push する。 Publish ワークフローが起動し、release environment の承認待ちで止まる。 自分で承認する。 Marketplace に公開される。 v0.1.3 は 2026-10-29 15:23 JST に起動し、承認後の 15:30 JST ごろに公開まで終わった。 備考 今回は Marketplace のみ。Open VSX は namespace 未作成なので後回し。 手動で VSIX を作って上げる手順は、フォールバックとして残している。 個人開発の private リポジトリでは、この方法はそのまま使えない。GitHub Free / Pro / Team だと Required reviewers は public リポジトリでしか使えない。 実装は AI 開発ボット経由で、公開前の承認だけ自分でやっている。 参考 Publishing Extensions(VS Code Extension API) Publish Visual Studio Marketplace extensions securely with Trusted Publishing(Microsoft for Developers) Retirement of Global Personal Access Tokens in Azure DevOps(Sprint 270 Update) microsoft/vscode-vsce: Trusted publishing vsce v4.1.0 リリース Deployments and environments(GitHub Docs)
GraphRAG論文を実装目線で読む:事前要約とGlobal Searchの境界 GraphRAGを実装目線で読むと、気になるのはグラフの形だけでなく、質問前に何を作り、質問時に何をモデルへ渡すのかです。 この記事では、Darren EdgeらのFrom Local to Global: A GraphRAG Approach to Query-Focused Summarization v2とMicrosoftの公式資料を基に、この境界を整理します。原論文の中心であるGlobal Searchと、公式実装のLocal Searchを区別して扱います。 RAG(検索した外部情報を生成モデルの回答に使う方法)の基本は、ブログのRAGと外部知識の解説を参照してください。以下は資料読解による技術メモで、ライブラリの実行や性能測定はしていません。 通常のRAGとの違いを架空の案件資料から追う説明や、用語ごとの図解は、ブログのGraphRAG解説にまとめています。ここでは中間成果物と検索処理の設計に焦点を当てます。 検索上位の文章は、資料全体の代表とは限らない 「案件Aの担当者は誰か」なら、該当する文章を取得する構成が自然です。一方、「全案件に共通する遅延要因は何か」では、質問に似た文章を上位から取得しても、別の種類の要因が抜ける可能性があります。 GraphRAGの原論文が扱うのは、このような資料全体の理解を要する質問です。関連性だけで選んだ断片に依存せず、関係のまとまりから事前に作った要約を回答の材料にします。 ただし、比較対象は原論文のベクトル検索によるRAGです。複数回の検索や多様性を考慮した取得など、あらゆるRAG構成に対する優位性を示したものではありません。 中間成果物を、役割ごとに分けて読む Microsoftの標準的な索引作成処理は、LLM(大規模言語モデル)で対象や関係を抽出し、そのまとまりを要約します。以下は、公式のDataflowを読むために整理した表です。列名や保存形式を固定する実装仕様ではありません。 成果物 主に保持するもの 設計上、確認したい点 Text units 分割した元の文章 元資料の位置へ戻れるか Entities 人物・組織などの対象と説明 表記違いや同名対象をどう扱うか Relationships 対象間の関係と説明 元資料に記載された関係か、抽出時の誤りか Communities 関係の密な対象のまとまりと階層 分類の粒度が用途に合うか Community reports まとまりごとの内容を整理した要約 元の説明や重要な例外が落ちていないか コミュニティは、元ファイルを部署別に分類したものとは限りません。グラフ上の対象をまとめるため、一つの資料から複数のまとまりに関係する情報が得られることもあります。 原論文と公式資料の概念を基に独自作成した架空例です。実際の検出結果ではなく、階層構造も省略しています。 この区別は更新処理を考えるときにも役立ちます。元資料を修正したら、その文章だけでなく、影響を受けた対象の説明や要約まで古くなり得ます。具体的にどこまで再計算するかは実装によりますが、元資料と派生した情報の対応を追えることを評価項目にしたいところです。 なお、現行資料ではClaims(資料中の主張)の抽出は任意です。論文の概念図に登場するものを、すべての設定で必須の処理だと解釈しないようにします。 Global Search:事前要約と部分回答は別の成果物 Global Searchでは、指定した階層のコミュニティレポートを利用します。概念上の流れは次のとおりです。 レポート集合を、処理できる長さの要約群へ分割する。 各要約群と同じ質問をモデルへ渡し、質問に対する部分回答を作る。 有用性を評価して内容を絞り込み、最終回答の文脈に収める。 選んだ部分回答を使って全体の回答を生成する。 これはMap-Reduce(分割処理した結果を統合する方法)の構成です。実装では、要約群を作る処理、部分回答の生成、選別、最終生成を分けて読むと、どこで情報が落ちたかを追いやすくなります。 原論文と公式Global Searchを基にした独自模式図です。各部分回答には、同じ質問と異なる要約群の両方が入力されます。 事前要約は資料を整理したもので、部分回答は今回の質問に依存します。そのため、質問を変えると部分回答も変わりますが、資料・抽出設定・要約設定が同じなら事前要約を再利用する設計ができます。 ここで注意したいのは、グラフ全体をそのまま最終生成モデルへ渡すわけではないことです。レポートの分割、部分回答の選別、最終文脈の長さという段階ごとの制約があります。情報を広く扱うための構成でも、全事実が回答に残る保証はありません。 公式資料では、細かな階層のレポートほど詳細な回答につながり得る一方、レポート数に応じて処理時間やモデル利用量が増える可能性を説明しています。公式Global Search Local Searchとの違いは、取得の入口にもある Local Searchは、質問と意味の近いエンティティを入口にし、関連する対象・関係・元の文章などを集めます。Global Searchの処理を、対象の数だけ少なくしたものと考えると、この違いを見落とします。公式Local Search 比較軸 Local Search Global Search 入口 質問に関連する対象 指定階層のコミュニティレポート 主な文脈 対象の関係情報と関連文章など 要約群から作る部分回答 向く質問の例 特定の案件に関わる部署と役割 案件群全体で繰り返される課題 確認したい失敗 入口となる対象の取り違え 要約・選別での重要論点の脱落 GraphRAGでも意味の近さによる検索は使われます。「ベクトル検索かグラフか」の二択より、どの情報を入口に、何を組み合わせるかを見るほうが設計を理解しやすいと感じます。 評価では、グラフなしの全体要約も比較する 原論文v2は、ニュースとポッドキャストの二つの資料群に対して、LLMで作った各125問の全体理解を問う質問を使っています。包括性と多様性ではベクトルRAGに対する改善を報告していますが、簡潔で直接的な回答ではベクトルRAGが優位でした。 さらに、グラフを作らず元の文章を分割して要約・統合する方法も比較しています。この比較は、全体を扱った効果と、グラフを使った効果を考えるうえで重要です。 自分の用途で試すなら、以下の比較を置きたいと考えます。これは筆者の評価案です。 比較対象 確かめたいこと 負担・弱点 関連文章を取得するRAG 小範囲の根拠で答えられるか 全体の論点が抜ける可能性 元文章の分割要約と統合 グラフなしでも全体質問に答えられるか 質問ごとに広い文章範囲を処理する負担 GraphRAGのGlobal Search 事前要約の再利用と回答品質が両立するか 抽出・要約の準備と更新管理 評価点も一つにまとめず、根拠との一致、論点の取りこぼし、応答時間、初回準備、資料更新時の負担を分けます。包括性の評価が高いことを、そのまま事実の正確性や捏造率の改善とは扱えません。原論文も一般化や捏造率の比較に追加検証が必要だとしています。原論文v2・評価と限界 所感:モデルの前に、文脈を作る処理を設計する この論文で参考になるのは、全体を問う質問のために、検索時に渡す文脈を事前処理から設計している点です。グラフを作っただけで回答が良くなるというより、関係をまとめた要約を、質問ごとの部分回答へ変換する構成に意味があります。 採用判断では、その構成が手元の質問に必要かを確かめたいです。担当者や日付を取り出す用途と、複数資料を横断する調査では、比較すべき品質も許容できる負担も変わります。 実装を利用する場合、公式READMEは索引作成が高コストになり得るため、小さく始めるよう案内しています。また、2026年9月14日の確認時点では保守中心の方針が記載されており、新機能追加や新しいプルリクエストの受け付けは行わないとされています。Microsoftが正式にサポートする製品ではないことも明記されています。Microsoft GraphRAG公式リポジトリ 参考資料 Darren Edgeほか:From Local to Global: A GraphRAG Approach to Query-Focused Summarization v2(CC BY 4.0) Microsoft GraphRAG:Dataflow Microsoft GraphRAG:Global Search Microsoft GraphRAG:Local Search Microsoft GraphRAG:公式リポジトリ
AIエージェントのMCP承認。許可リストに無いツールは承認なしだった Microsoft Agent Framework(PythonでAIエージェントを作るMicrosoftのライブラリ)で、ローカルのMCPサーバーをつなぐ人向けの話です。10月30日公開のpython-1.24.0(リリースノート記載)で、MCPツールの承認設定に default が加わりました。always_require_approval と never_require_approval のどちらにも書かないツールは、これまでどう扱われていたのか。そこが気になって試しました。 そこで、読み取り用2つと削除用1つのツールを持つMCPサーバーを用意し、承認設定を5通りに変えて、ツールごとの承認モードを出力しました。never_require_approval に読み取り系だけを書くと、書いていない削除ツールの承認モードも never_require になりました。 ! 2026-11-04、macOS・Python 3.13・agent-framework-core 1.24.0・mcp 2.3.0で確認しました。見たのは、接続後に各ツールへ付く承認モード(approval_mode)の値です。LLMを載せたエージェント実行で承認の確認が実際に出る様子までは見ていません。 試した構成 MCPサーバーはPythonのFastMCPで作りました。ツールは read_note、search_notes、delete_note の3つです。これを MCPStdioTool で接続し、接続後の functions から各ツールの approval_mode を読みます。承認の設定だけを変えて5条件を並べました。 A=指定なし、B=neverだけ、C=Bにdefaultを追加、D=alwaysだけ、E=同じツールをalwaysとneverの両方へ。画像は端末風に整形したものです。 結果。Bの設定では、delete_noteも承認なしでした 出力が次の画像です。各条件の delete_note の行に注目してください。 Bだけが FutureWarning を出し、delete_note は never_require のままです。 条件 設定 delete_note A 指定なし 承認なし B never_require_approval に読み取り2つ 承認なし(FutureWarning) C Bに default: always_require を追加 承認が必要 D always_require_approval に delete_note 承認が必要 E delete_note を always と never の両方に 承認が必要(always が優先) Bは「読み取りは自動で通し、ほかは確認する」という意図に見える設定です。ところが、どちらのリストにも名前がないツールは、承認なしで通ります。出るのは FutureWarning だけで、動作そのものは変わりません。PRの説明によると、この警告は、将来この既定値が変わるかもしれないことへの予告です。 解決順と、直し方 PR #9828 の説明とMicrosoft Learnには、同じ判定順が書かれていました。まず always_require_approval、次に never_require_approval、最後に default を見ます。どれにも該当しなければ承認なしです。実測でも、リストに無いツールの扱い(B・C)と、alwaysがneverより優先されること(E)を確認でき、どちらも上の順序どおりでした。 直し方は、default を明示することです。 approval_mode={ "never_require_approval": ["read_note", "search_notes"], "default": "always_require", } これで、あとからMCPサーバーに追加されたツールも、名前を挙げない限り承認が必要になります。PRの説明では、tools/list_changed のあとに見つかったツールにも default が効くとされています。この点は、私の環境では試していません。 明日試すなら 手元のMCPサーバーで、never_require_approval だけを書いている箇所を探してください。あれば default を足し、接続後の approval_mode を出力してみてください。足す前と後で違いが見えます。用意するのは pip install "agent-framework-core==1.24.0" と、接続後の functions を読む数行のコードです。Pythonは3.11以上が対象です。私の環境では、これに加えて tenacity も入れる必要がありました。 参考 microsoft/agent-framework python-1.24.0 リリースノート PR #9828: Add a default approval mode to MCP approval policies Microsoft Learn: Local MCP tools(Agent Framework)
Crop Mapping Evaluation under Sampling Bias Government agencies use crop maps to estimate production, monitor food security, and set agricultural policy. These crop maps are usually validated against field labels, but these labels are rarely a random sample of the area the map covers. Field teams tend to label parcels near roads and skip ones that are small or hard to reach, so performance measured on held-out labels mainly describes the places they visited. We call the difference between this reported performance and performance over the whole mapped region the deployment performance gap. To estimate performance over the whole region, we use a weighted form of prediction-powered inference (PPI). The classifier's predictions on unlabeled points across the region give a first estimate, and its errors on the labeled points correct that estimate, with more weight on labels from under-sampled conditions. We test this in five European regions where crop registers label every declared parcel, so the true performance is known. Simulating six documented collection practices there produces gaps of up to 0.20 macro-F1. On the collection rule that creates the largest gap in each region, 5 km block cross-validation still overestimates macro-F1 by as much as 0.18, while PPI with weights estimated from satellite embeddings reduces the largest error across regions to 0.07. Importance-weighted cross-validation with the same weights does almost as well, so most of the improvement comes from the weights themselves. We also apply the method to three Kenyan datasets that have no region-wide reference labels. For a roadside dataset collected with helmet-mounted cameras, the estimated macro-F1 falls from 0.93 under random cross-validation to 0.61, although the correction relies on a small number of heavily weighted labels. Our code is available at microsoft/pappi. Comments: 17 pages, 4 figures, 5 tables. Code: microsoft/PaPPI
.NET 8・.NET 9のサポート終了は2026年11月10日|同日終了の理由と.NET 10への移行ガイド Microsoftは標準期間サポート(STS)の期間を18か月から24か月に延長しました。その結果、.NET 9は.NET 8と同じ2026年11月10日にサポートが終了します。本記事では、その理由と.NET 10へのアップグレード方法を解説します。 .NET 9のサポートは2026年11月10日に終了します。.NET 8も同じ日です。残りは3週間を切りました。.NET 8は2023年11月14日にリリースされた長期サポート(LTS)版、.NET 9はその1年後の2024年11月12日にリリースされた標準期間サポート(STS)版です。この2つが同じ日にサポート終了を迎えます。誤植ではありません。11月10日以降にサポートされるバージョンは.NET 10で、LTSとして2028年11月14日までサポートされます。 2026年11月10日に.NET 8と.NET 9で何が終わるのか? 終わるのはサービシング(保守提供)です。.NET BlogでRahul Bhandari氏が公表した告知によると、Microsoftは.NET 8と.NET 9に対する「サービシング更新、セキュリティ修正、技術サポート」を終了します。 アプリケーションは引き続き動作します。自動でアンインストールされることもありません。ランタイム、SDK、コンテナイメージもダウンロードできます。ただし、今後は修正が提供されなくなります。 11月10日はパッチ・チューズデーでもあります。Microsoftによると、既知の重大な問題がある場合に限り、.NET 8と.NET 9は同日に最後の更新を1回ずつ受け取る可能性があります。それ以降は、ランタイム、ASP.NET Core、基底クラスライブラリ(BCL)に影響する新たなCVEはすべて自己責任で対処することになります。 本記事執筆時点の最新パッチは8.0.32と9.0.21で、どちらも2026年10月13日にリリースされています。これらを適用していない場合は、期限を迎える前から対応が遅れている状態です。 ツール面にも影響があります。今後のVisual Studio 2022のサービシング更新で、.NET 8と.NET 9のコンポーネントがサポート終了として扱われるようになります。Visual Studioは更新時に、サポート終了のコンポーネントの削除を提案します。ビルドエージェントでこの設定を事前に確認しておきましょう。 なぜ.NET 9は.NET 8と同じ日にサポートが終わるのか? .NET 9のサポート期間中に、MicrosoftがSTSのライフサイクルを変更したためです。 旧ポリシーでは、STSのサポート期間は18か月でした。これは次のリリースから6か月後にあたります。.NET 9は2026年5月12日にサポートが終了する予定でした。 2025年9月16日、.NET BlogでJamshed Damkewala氏が、STSリリースのサポート期間を24か月に延長すると発表しました。.NET 9から適用されます。LTSは従来どおり3年です。これにより、.NET 9のサポート終了日は2026年5月12日から2026年11月10日に移り、.NET 8の終了日とちょうど重なりました。 STSを24か月に延ばしたことで、STSリリースの終了日は直前のLTSリリースと同じになります。STS版の依存関係を使っていても、LTS版アプリと同じ日にサポートが終わる形です。なお、.NET Aspireのようなアウトオブバンド(OOB)コンポーネントは独自のライフサイクルを持つため、別途確認が必要です。 実際の問題を解消する、妥当な見直しだと私は考えています。一方で、副作用として2つのリリースが同じ日にサポートカレンダーから外れることになりました。.NET 9の終了を2026年5月と見込んで計画していた方は、6か月の猶予が増えていたことに気づいていないかもしれません。 この構造は今後も繰り返されます。偶数番号のLTSは11月にリリースされ、3年間サポートされます。奇数番号のSTSは翌年の11月にリリースされ、新ポリシーでは2年間サポートされます。どちらも同じ11月に終了します。.NET 10と.NET 11も、2028年11月に同じ日にサポートが終わると私は見ています。今回は例外ではなく、これからの標準パターンです。 各.NETバージョンのサポート状況は? 出典: .NET and .NET Core Support Policy(2026年10月19日時点) どのバージョンにアップグレードすべきか? .NET 10です。 現行のLTSリリースで、2028年11月14日までサポートされます。24か月のSTSポリシーのもとでは、.NET 11を待っても猶予は延びません。得られるのは、同じ月にサポートが終わると私が見ている、より新しいリリースだけです。 .NET 9をお使いなら、.NET 10へは1バージョン上げるだけで、多くの場合は小規模な変更で済みます。.NET 8をお使いなら、2リリース分の破壊的変更をまたぐため、工数を多めに見込んでください。ASP.NET Coreアプリは、ASP.NET Core 9から10への移行ガイドも確認しておきましょう。 最も単純な場合、アップグレードは各プロジェクトファイルの1行の変更です。 net10.0 ただし、この1行で済むことはまれです。実際の作業は次のような部分に生じます。 - 互換リリースが必要なNuGetパッケージ - 古いSDKを固定しているglobal.json - mcr.microsoft.com/dotnet/aspnet:8.0を参照しているDockerfile - 新しいランタイムのインストールが必要なCI/CDパイプラインとホスティング環境 自社で運用していても開発はしていないサードパーティ製アプリケーションについては、ベンダーに.NET 10対応版のリリースを問い合わせてください。 GitHub Copilotで.NET 10にアップグレードするには? .NET Upgrade Assistantは使いません。Microsoftのドキュメントでは、「.NET Upgrade Assistant is officially deprecated.」と明記されています。サポート終了の告知にはまだリンクが残っていて紛らわしいのですが、このツールは後継に置き換えられています。 後継はGitHub Copilot upgrade agentです。ソースコードとプラグインはmicrosoft/upgrade-agent-pluginsにあります。Mika Dumont氏がModernize .NET Anywhere with GitHub Copilotで使い方を解説しています。 作業は3つの段階で進みます。各段階の成果物はリポジトリの.github/upgrades/配下にMarkdownファイルとして出力されるので、レビューやコミットが可能です。 1. 評価(Assess): プロジェクトと依存関係を調べ、assessment.mdを出力します。破壊的変更、API互換性の問題、非推奨パターンが一覧化されます。 2. 計画(Plan): plan.mdを出力します。アップグレード戦略、依存関係の順序、リスクが記載されます。 3. 実行(Execute): 計画をtasks.mdのタスクに分割して順に実行し、作業単位ごとにGitコミットを作成します。検証やロールバックを段階的に行えます。 利用できる環境は4つあります。普段使っているものを選んでください。 - Visual Studio: Visual Studio 2026、またはVisual Studio 2022 17.14.16以降で、ソリューションエクスプローラーのソリューションまたはプロジェクトを右クリックし、Modernizeを選択します。 - VS Code: GitHub Copilot upgrade extensionをインストールし、Copilot ChatのエージェントピッカーでUpgradeを選択します。 - GitHub Copilot CLI: 次のコマンドを実行します。 /plugin marketplace add microsoft/upgrade-agent-plugins /plugin install upgrade-agent@upgrade-agent-plugins /agent Upgradeを選び、「upgrade my solution to .NET 10」のように指示します。 - GitHub: Copilotクラウドエージェントとして追加すると、プルリクエストを自動で作成できます。手順はクラウドエージェントのREADMEを参照してください。この方法には、クラウドエージェントが使える有料のCopilotプランと、リポジトリへの書き込み権限が必要です。 どの方法を選ぶにしても、次の点をおすすめします。 - 最初は、モノリスではなく小さなライブラリやサービスから始めましょう。自社のコードベースでエージェントがどこでつまずくかを把握できます。 - 大規模なコードでは、ガイドモード(Guided)を使いましょう。「pause」でガイドモードに、「continue」で自動モードに戻せます。 - 最後にまとめてではなく、コミットごとにテストスイート全体を実行しましょう。タスクごとにコミットされるため、コストを抑えられます。 - 完了後は、次のコマンドで結果を確認しましょう。 dotnet --list-runtimes dotnet list package --outdated 大規模なレガシーソリューションでは、エージェントが自力で最後までやり遂げられるとは限りません。大きなアプリで処理が止まるという初期ユーザーの報告もあり、Microsoftがリポジトリでフィードバックを集めています。移行の全工程ではなく、非常に速い初回パスとして使ってください。 2026年11月10日までに.NET 8・.NET 9からアップグレードできない場合は? その場合は、運用中のバージョンにパッチを提供してくれる存在が必要です。 HeroDevsのNever-Ending Support(NES)for .NETは、.NET 6、.NET 8、.NET 9をそのまま置き換えられる、安全なドロップイン代替です。ランタイム、ASP.NET、Entity Framework、.NET SDK、WPF、WinFormsを対象とし、NES for .NET Containersを使えばコンテナイメージもカバーします。コードの変更は不要です。 HeroDevsは.NET Security Groupのメンバーです。そのため、.NETに影響する脆弱性の事前開示を受け、MicrosoftのパッチTuesdayのリリースと同時に、EOLバージョン向けの修正済みビルドを提供できます。 これは仮定の話ではありません。.NET 6は2024年11月12日のサポート終了以来、HeroDevsがパッチを提供し続けています。System.Net.MailのSMTPインジェクションの脆弱性であるCVE-2026-32178では、.NET 6に上流の修正が提供されませんでしたが、NESのお客様には修正が提供されました。2026年11月11日からは、.NET 8と.NET 9もこの対象に加わります。 NESは.NET 10への移行の代わりにはなりません。移行のスケジュールを、パッチ・チューズデーではなく、エンジニアリングチームが決められるようになるということです。 よくある質問(FAQ) .NET 8と.NET 9のサポートが終了するのは正確にいつですか? どちらも2026年11月10日です。この日はパッチ・チューズデーで、既知の重大な問題がある場合に限り、Microsoftが各バージョンに最後の更新を1回提供する可能性があります。 .NET 9は2026年5月にサポート終了の予定ではなかったですか? はい、旧ポリシー(STS 18か月)では2026年5月12日でした。Microsoftが2025年9月16日にSTSを24か月に延長し(.NET 9から適用)、終了日が2026年11月10日に移りました。 .NET 8や.NET 9のアプリケーションは動かなくなりますか? いいえ、引き続き動作します。ただし、Microsoftからのセキュリティ修正、バグ修正、技術サポートは提供されなくなります。 .NET Upgrade Assistantはまだサポートされていますか? いいえ。MicrosoftはGitHub Copilot upgrade agentに置き換える形で非推奨としました。後継はVisual Studio 2026とVisual Studio 2022 17.14.16以降に付属し、VS Code、Copilot CLI、GitHubでも利用できます。 .NET 10ではなく.NET 11を待つべきですか? いいえ。.NET 11はSTSリリースで、24か月ポリシーのもとでは.NET 10と同じ2028年11月ごろにサポートが終了する見込みです。.NET 10はすでに利用でき、より安全な移行先です。 HeroDevsは11月10日以降も.NET 9をサポートしますか? はい。NES for .NETは、.NET 6、.NET 8、.NET 9をカバーします。 11月10日の期限までにアップグレードが間に合わない場合 .NET 10への移行が2026年11月10日に間に合わないアプリケーションについては、NES for .NETが.NET 6、8、9にパッチを提供し続け、監査対応も維持します。その間に、慌てず適切に移行を進められます。保証範囲についてはHeroDevsにお問い合わせください(日本語で対応可能です)。 --- お問い合わせ 本記事の内容やHeroDevsのソリューション(NES等)について、日本語でのお問い合わせに対応しています。お気軽にHeroDevsお問い合わせページからご連絡ください。 --- 原文: herodevs.com (出典: herodevs.com)
GitHub Copilot App のサンドボックスで .NET アプリを開発するための設定を試してみた GitHub Copilot App のローカルサンドボックスが GA したらしいので、.NET の開発で使えそうかどうか見てみようと思います。 今回は Windows 環境で、コンソールアプリの作成・実行と NuGet パッケージの追加を試し、その後に Minimal API も動かしてみました。 コンソールアプリは動かせましたが、ファイルのアクセス許可を調整したり、NuGet のエラーを調べたりする必要がありました。Minimal API は起動したものの、エンドポイントへのアクセスがタイムアウトし、今回はそこで断念しました。 ワークツリーの保存先を変更している場合の注意 GitHub Copilot App のワークツリーの保存先を D ドライブなどに変更している場合は、デフォルトの C ドライブ配下の場所に戻す必要があります。 現在、Windows のサンドボックスでは、システムドライブ以外にあるフォルダーを作業場所にすると、シェルでフォルダーの一覧取得などができない問題が報告されているためです。以下の Issue でも、D ドライブなどではアクセス拒否になり、システムドライブの C ドライブでは動くことが確認されています。 copilot-cli#5207 コンソールアプリを作成して実行するための設定 GitHub Copilot App にコンソールアプリの作成と実行を依頼したところ、dotnet new console の実行時にアクセス拒否のエラーが出ました。.NET SDK やテンプレートが使うフォルダーへの読み書きを許可する必要がありました。 使ったのは .NET 10 で、global.json で SDK を 10.0.403 に指定しています。 アクセスを拒否されたのは次のパスです。 %USERPROFILE%.dotnet\10.0.403.toolpath.sentinel %USERPROFILE%.templateengine\dotnetcli\10.0.403 %USERPROFILE%.templateengine\packages.json そこで、GitHub Copilot App のサイドバーから Settings を開き、Repositories で対象のリポジトリを選びます。Sandbox にある Additional read/write の Add folder から、次のフォルダーを追加しました。 C:\Users<ユーザー名>.dotnet C:\Users<ユーザー名>.templateengine <ユーザー名> は自分の環境に合わせて置き換えてください。 設定を変更しただけでは実行中のセッションに反映されないので、/restart-session でセッションを再起動する必要があります。 docs.github.com 上記のフォルダーへのアクセスを許可してセッションを再起動した後、Copilot に再実行を依頼すると、dotnet new console でのアプリ作成と、dotnet run での Hello, World! の表示に成功しました。 NuGet パッケージの追加を試してみる コンソールアプリの作成と実行ができたので、続いて Copilot に ReactiveProperty の追加を依頼しました。Copilot が実行したのは次のコマンドです。 dotnet add .\HelloWorld\HelloWorld.csproj package ReactiveProperty ところが、パッケージの追加もアクセス拒否で失敗しました。エラーメッセージには、拒否されたパスが出ていません。 error: Access to the path is denied. NuGet のパッケージ保存先やキャッシュのフォルダーが怪しいと思い、Additional read/write に次の4つを追加しました。 C:\Users<ユーザー名>.nuget C:\Users<ユーザー名>\AppData\Local\Temp\NuGetScratch C:\Users<ユーザー名>\AppData\Roaming\NuGet C:\Users<ユーザー名>\AppData\Local\NuGet 設定を反映して Copilot に再実行を依頼しましたが、それでも Access to the path is denied. が解消しませんでした。 ログを確認すると、次の URL からパッケージの登録情報を取得する GET リクエストには 200 OK が返っていました。少なくとも、この通信には成功しています。 api.nuget.org そこで、Copilot に NUGET_SHOW_STACK を有効にして再実行してもらいました。スタックトレースでは、NuGet.Protocol.HttpCacheUtility.CreateCacheFileAsync から呼ばれた System.IO.FileSystem.MoveFile で失敗していました。登録情報の取得ではなく、キャッシュファイルの移動で止まっていることが分かりました。 フォルダーの許可を追加しても解決せず、ログからもアクセスを拒否されたパスが分からなかったので、Process Monitor で実際のアクセス先を調べることにしました。 Process Monitor で失敗した操作を見る エラーメッセージだけでは先に進めなかったので、Microsoft の Process Monitor(Procmon)を使って、もう一度パッケージ追加を実行したときのファイル操作を確認しました。 learn.microsoft.com そこで見つかったのは、次の場所にあるファイルのリネームの失敗でした。ユーザー名やサンドボックスごとに変わる部分は置き換えています。 %LOCALAPPDATA%\Packages\sandbox.{GUID}\AC\NuGet\v3-cache<source-cache-dir>\list_reactiveproperty_index.dat-new list_reactiveproperty_index.dat-new の名前を、同じディレクトリ内で list_reactiveproperty_index.dat に変えようとしたところ、アクセスを拒否されていました。Procmon では、このリネーム操作(SetRenameInformationFile)の結果が ACCESS DENIED と記録されていました。 実際のアクセス先が AppData\Local\Packages 配下だったので、Additional read/write に次のパスを追加しました。 C:\Users<ユーザー名>\AppData\Local\Packages セッションを再起動して Copilot にパッケージ追加を再実行してもらうと、ReactiveProperty 9.10.0 と依存パッケージの導入に成功しました。値の変更を Subscribe で受け取り、コンソールに出力する処理も動きました。 これで動くようになりました。ただ、ここまでにいくつかのフォルダーを許可しているので、全部必要だったかは確認していません。AppData\Local\Packages を丸ごと許可するのは範囲が広いので、もう少し絞れないかは気になるところです。 私の環境でコンソールアプリを実行できた設定例 試した結果、ユーザー設定の Additional read/write(Folders the sandbox may read and modify)に残っていた .NET 用のパスは次の 7 件です。 C:\Users<ユーザー名>.dotnet C:\Users<ユーザー名>.templateengine C:\Users<ユーザー名>.nuget C:\Users<ユーザー名>\AppData\Local\Temp\NuGetScratch C:\Users<ユーザー名>\AppData\Roaming\NuGet C:\Users<ユーザー名>\AppData\Local\NuGet C:\Users<ユーザー名>\AppData\Local\Packages 設定する場合は、C:\Users<ユーザー名> の部分を自分の環境の絶対パスに置き換えてください。ここでは設定画面で環境変数が展開されるかどうかは確認していないので、絶対パスで記載しています。 これとは別に、添付画像へアクセスするために追加したパスもありました。 C:\Users<ユーザー名>.copilot\workspaces こちらは .NET の実行用ではなく、添付画像へのアクセス用です。 私の環境では、この設定でコンソールアプリの作成・パッケージ追加・実行までできました。もう少し許可するフォルダーを減らせるかもしれませんが、そこまでは試していません。 特に AppData\Local\Packages は、広い範囲の読み書きを許可することになります。今回の実験で使った設定であって、全員にそのまま追加することを勧めるものではありません。どこまで権限を絞っても動くかは未確認です。 Minimal API も試してみる コンソールアプリが動いたので、次は Copilot に Minimal API の作成と実行を依頼しました。アプリは起動しましたが、エンドポイントにアクセスするとタイムアウトしてしまいました。 サンドボックス設定の Outbound internet と Local network は、セッション開始時からどちらも ON にしていました。それでも接続できなかったので、ネットワーク周りの制約を調べてみました。 調べていると、Microsoft の MXC の公開資料で、似た症状の既知の制約を見つけました。Windows の特定の構成では、ホストからサンドボックス内で起動したサーバーへの接続がタイムアウトするというものです。 github.com/microsoft/mxc/blob/main/docs/backends/… リンク先では、Windows build 26691.1002 で、サンドボックスから外への通信をプロキシー経由に限定して試していました。ホストとのループバック通信を許可しても、ホストからサンドボックス内のサーバーへの接続はタイムアウトしたそうです。一方、プロキシーを使わない別の構成では接続できたとのことでした。 今回もこの制約に当たったのかは分かりません。ただ、起動した API に接続できない状態では開発を進められないので、今回はここまでにしました。 まとめ 今回は、サンドボックスのアクセス許可を追加することで、コンソールアプリの作成から NuGet パッケージの追加、実行までできました。ただ、途中で Procmon を使ってアクセス先を調べる必要があり、Minimal API も接続できないところで止まってしまいました。 今回試した Windows のローカル環境では、現時点で自分の実開発に使うにはまだ厳しいと感じました。サンドボックス自体は重要だと思っているので、今後の改善も追っていきたいです。
Microsoft.UI.Reactorを学習する Microsoft.UI.Reactorとは Microsoft.UI.Reactor は、C#で WinUI アプリを宣言的に作る実験的なフレームワークです。 ※2026/11/01時点で 0.1.0-preview.16 版です。 試す プロジェクトを作成する winget install Microsoft.WinAppCli winapp new -t reactor -n Kashin777.UI.Reactor cd Kashin777.UI.Reactor 構成 !image.png csproj(抜粋) <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <!-- Windows GUI アプリとしてビルド --> <OutputType>WinExe</OutputType> <!-- .NET 10 と Windows SDK 10.0.26100.0 を対象にする --> <TargetFramework>net10.0-windows10.0.26100.0</TargetFramework> <!-- サポートする Windows の最低バージョン --> <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion> <SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion> <!-- WinUI アプリとしてビルドし、MSIX のビルド機能を有効にする --> <UseWinUI>true</UseWinUI> <EnableMsixTooling>true</EnableMsixTooling> <!-- C# の基本設定 --> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <!-- Windows アプリのビルドに必要なパッケージ --> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="*" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="*" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools.WinApp" Version="*" /> <!-- Microsoft.UI.Reactor --> <PackageReference Include="Microsoft.UI.Reactor" Version="0.1.0-preview.16" /> </ItemGroup> </Project> App.cs using Microsoft.UI.Reactor; using Microsoft.UI.Reactor.Core; using Microsoft.UI.Reactor.Layout; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using static Microsoft.UI.Reactor.Factories; // To learn more about Reactor, the Reactor project structure, and more about // our project templates, see: https://github.com/microsoft/microsoft-ui-reactor ReactorApp.Run<App>("Kashin777.UI.Reactor"); class App : Component { public override Element Render() { var titleBar = TitleBar("Kashin777.UI.Reactor") .Flex(shrink: 0); // This is the main content area of your application. // Add your UI elements here. var content = Border(Empty()).Flex(grow: 1, basis: 0); return FlexColumn(titleBar, content) .Backdrop(BackdropKind.Mica); } } とりあえず実行 dotnet run !image.png 画面を実装する 公式ドキュメントのCounter Example に従い、App.cs を修正してみます。 public override Element Render() { var titleBar = TitleBar("Kashin777.UI.Reactor") .Flex(shrink: 0); var (count, setCount) = UseState(0); // countプロパティとsetterを作成 var content = VStack(spacing: 12, // Vertical StackElement TextBlock($"Count: {count}").FontSize(20).SemiBold(), // element[0] TextBlock HStack(spacing : 8, // element[1] Horizontal StackElement Button("- 1", () => setCount(count - 1)), // 1デクリメント Button("Reset", () => setCount(0)), // リセット Button("+ 1", () => setCount(count + 1)) // 1インクリメント ) ).Padding(24); return FlexColumn(titleBar, content) .Backdrop(BackdropKind.Mica); } dotnet run !image.png 基礎 フック フック インタラクティブなUIには必ず状態が必要です。Reactorでは、状態はUseState時間とともに変化する値を管理するための主要なフックです。 コンポーネントは複数回呼び出すことができUseState、各呼び出しは独立した値を追跡します。 var (count, setCount) = UseState(0); var (firstName, setFirstName) = UseState(""); var (fontSize, setFontSize) = UseState(16.0); | フック | 戻り値 | 目的 | |--|--|--| | UseState | (T value, Action<T> set) | リアクティブな状態 — set 時に再レンダリングされます。 | | UseReducer | (T value, Action<Func<T,T>> update) または (TState, Action<TAction>) | 関数型または Redux スタイルの更新。 | | UseEffect | void | コミット後の副作用。Func<Action> オーバーロードを使用すると、次のエフェクトの実行前およびアンマウント時にクリーンアップが実行されます。 | | UseMemo | T | 計算結果のキャッシュ。依存項目のいずれかが不等となった場合に再実行されます。 | | UseRef | Ref<T>(mutable .Current 付き) | 変更時でも再レンダリングを行わずに、レンダリング間を通じて状態を保持します。 | | UseCallback | Action | レンダリング間を通じて安定したデリゲート識別子。 | | UseContext | T | 周囲の Context 値を読み取ります。 | | UseObservable | T | 追跡対象の INotifyPropertyChanged ソースが変更を発生させた際に再レンダリングを行います。 | | UseExternalStore | TSnapshot | subscribe/getSnapshot ストアを Reactor にブリッジし、スナップショットが変更された場合にのみ再レンダリングします。 | | UseResource | AsyncValue<T> | キャッシュされた非同期読み取り(「非同期リソース」を参照)。 | | UsePersisted | (T, Action<T>) | プロセス内のアンマウント/リマウント後も存続する UseState — メモリ内、終了時にクリアされます(「永続性」を参照)。 | レイアウト レイアウト | 要素 | 目的 | |--|--| | VStack | 縦積み(上から下へ子要素を配置) | HStack | 水平スタック(左から右へ) | Grid | 行/列グリッド(比例サイズ) | ScrollView | オーバーフローコンテンツ用のスクロール可能なラッパー | Border | 背景、角丸、ストローク付きコンテナ コントロール コントロールカタログ | カテゴリ | 中身は? | |--|--| | フォーム | テキスト入力、ピッカー、ボタン、検証プリミティブ | | コレクション | リスト、グリッド、仮想化リスト、リピーター | | テキストとメディア | 見出し、リッチテキスト、画像、メディアプレーヤー | | ステータスと情報 | 進捗状況、情報バー、バッジ、指導のヒント | | レイアウトとコンテナ | スタック、グリッド、境界線、スクロールホスト、ペイン | | ナビゲーション | ナビゲーションビュー、フレーム、タブ、パンくずリスト、ピボット | | 図形とアイコン | 長方形、楕円、線、パス、アイコンのソース | | ダイアログとフライアウト | コンテンツダイアログ、メニューフライアウト、コマンドバーフライアウト | | データシステム | DataGrid、列、データソース、ページング | | チャート作成 | 線グラフ、棒グラフ、面積グラフ、円グラフ、力グラフ | ホットリロード ホットリード dotnet watch run アプリを起動したまま、ボタンのラベルを変更して保存したら PS C:\Users\Kashin777\source2\repos\Kashin777.UI.Reactor> dotnet watch run dotnet watch 🔥 Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload. dotnet watch 💡 Press Ctrl+R to restart. 復元が完了しました (0.0 秒) 0.1 秒後に 成功しました をビルド info NETSDK1057: プレビュー版の .NET を使用しています。https://aka.ms/dotnet-support-policy をご覧ください Kashin777.UI.Reactor net10.0-windows10.0.26100.0 win-x64 成功しました (0.4秒) → bin\Debug\net10.0-windows10.0.26100.0\win-x64\Kashin777.UI.Reactor.dll 0.5 秒後に 成功しました をビルド dotnet watch ⌚ Loading projects ... dotnet watch ⌚ Loaded 1 project(s) in 0.5s. C:\Users\Kashin777\source2\repos\Kashin777.UI.Reactor\Properties\launchSettings.json からの起動設定を使用中... ⠼ Launching packaged application... ✅ 43A37F59-B43C-4C5A-9E09-1DE873E18ECA_1z32rh13vfry6 launched (PID: 22536) dotnet watch ⌚ File updated: .\App.cs dotnet watch ⚠ [Kashin777.UI.Reactor (net10.0-windows10.0.26100.0)] Further changes won't be applied to this process. ドキュメントに従い dotnet watch run で起動したのですが、App.cs の変更は検知されるもののリロードされず...
u know i completely forgot i ever wrote this comment. what the hell TypeScript#33304
Would love everyone's opinion on microsoft/WindowsDeveloperConfig
Reverse Engineering Block Blast Block Blast looks like a puzzle game. A decompile of the app suggests it's closer to a per-player ad pricing engine with a puzzle attached. Three tree-based models run on your phone, a bandit experiment tunes when you lose, and a rule decides your next three pieces based on what ad is sitting in memory. The Problem It's Solving The game is free and has no ad-free purchase, so revenue depends on rewarded and full-screen ads. Sensor Tower estimates put its ad revenue at roughly $127 million for January to May 2026, ahead of Candy Crush Saga at $81.1 million. Ad value varies a lot per player (country, device, history), and the best moment to show a rewarded ad is right after a loss. Making that work needs per-player prediction, per-deal control of the pieces, and the ability to change both without shipping an app update. How the System Is Built The research is Ayo Omolewa's breakdown of Android 10.8.2 and iOS 7.4.9, using jadx and Ghidra. The store APK holds very little. Logic ships as "traits" (modules with variants called arms), and at launch the server tells the app which arm of which trait you get. His config named about 700 traits, selected 254, and 101 were fetched after install as XXTEA-encrypted, Brotli-compressed JavaScript. Two players can run different games, and the studio can change yours silently. The Models | Model | Size and inputs | What it decides | |---|---|---| | XGBoost regression (xgboost_regression_model111.json) | 59 trees, depth up to 8, 27 inputs (18 about ads) | finalEcpm: your estimated ad value | | XGBoost classifier (predict_travel_difficulty_dead) | 500 trees, 52 inputs | Where in a level the lethal puzzle lands | | LightGBM | 1,000 trees, 93 inputs | Whether you'll be less active tomorrow | The ad value model. The inputs are mostly money-related: prices of ads loaded today and yesterday, country, phone model, RAM, install date, and how your first game went. The trees lean hardest on first score, latest ad price, RAM, phone model and country. The inference code is a plain loop: start each tree at the root, go left or right on a feature threshold (missing values follow a default direction), add the leaf weight to a running sum starting at the base score. Omolewa's port reproduces the game's outputs to the last decimal. Changing one input on a made-up US player on an iPhone 15 gives: | Change | Ad value (eCPM) | |---|---| | Baseline (US, first score 1,000) | 25.48 | | Brazil | 8.08 | | India | 5.59 | | First score 500 / 2,000 / 10,000 | 25.79 / 21.12 / 20.34 | The same US baseline on Android scores 48.96. The output feeds other rules. One compares your rewarded and full-screen prices and, if rewarded is worth at least twice full-screen in the shipped version, grants an extra revive (which plays a rewarded ad). Others add a full-screen ad when your price is high or skip full-screen ads when you're worth almost nothing. The "where do you lose" model. The game scores 12 candidate options (4 values of a sw_process setting times 3 difficulty levels) and keeps the argmax. Inputs are mostly about your history: current level, attempts, games finished this week, time since install. The winning sw_process maps to a stretch of the level (first 30%, 30 to 80%, last 20%). On reaching it, players who usually accept revives (above 75%) get an extra one, and from the fourth deal after that the game requests the lethal puzzle. Other rules read the same pick the opposite way and make the level easier when it lands on the fourth option. The churn model. If the LightGBM score is 0.69 or higher, a pink revive button replaces the normal one and skips the ad, once a day. It leans on app age, high score, RAM and average score. Server-side models. Rules also call models named for churn, LTV, revive-click and xDeepFM. Those weights never reach the phone, so the only visible part is the request. One call to /v1/ecpm_prediction sends 40 fields, including carrier, storage, hour of day and recent ad prices. The Rules That Act on the Predictions These are hand-written, not learned. RewardHighValueAdHarvestTrait fires when you finished your last three rewarded ads, the ad currently loaded is worth at least 3.5 times your last one (read from AppLovin MAX eCPM), and you're 1,000 points past your high score (500 or 750 in other arms). It then requests generator ZHI_SI_TI. The generator picks two pieces that fit and one that doesn't, searches every order and placement including line clears, and keeps the set only if nothing works. The code labels the pieces "lethal puzzle" in Chinese. PersonalMarginBreakTrait gives every deal a 20% chance of the same hand once you're 10% past your record. MultiClearBoostThenKillTrait sends your user ID to two server endpoints, and for the tiers labelled "not sensitive to being forced to die," waits for a big clear, then requests the lethal puzzle a few rounds later once the game reaches roughly your usual length. FastHandPunishTrait asks for hard pieces when your last six sets averaged under 4.2 seconds and you're past 93% of your high score. MaturityDevelopmentV2Trait scores habit, skill and ad history (10.98, 14.66 and 19.27 in the live test), and when the total (44.91) is under 65 it swaps hard puzzles for easy fills. AdPlusMinusStrategyTrait adds a random bonus of up to 10% of your high score after one type of revive. MABXiBaiTrait is a six-arm experiment on how soon the lethal puzzle may be requested: never, or after 4, 6, 10, about 17 or 30 minutes. Per arm it logs whether you started a new game within 15 minutes and the share of revive offers you accepted. Why This Is a Bigger Deal Than It Looks The ML itself is cheap: tree ensembles walked in a loop over JSON, no GPU, runs on a low-end phone and offline. The engineering is the delivery layer. Server-assigned arms, encrypted hot-loaded JavaScript and per-player A/B tests make this a feature-flag platform with bandit tuning, which is why it can be changed daily. Because the lethal-puzzle rule needs a rewarded ad loaded, it can't fire offline or with a phone-wide DNS blocker, while ad-independent rules keep running. Apple permits JavaScript updates that don't change what the app is. Whether this qualifies is Apple's call. The usual caveat applies: this is one researcher's analysis. mobilegamer.biz reported no reply from Hungry Studio, and TechRadar noted that independent verification matters. The evidence bundles (decoded rules, test scripts, hashes) are public at Ayoships if you want to run the checks yourself. Availability and Access The game is on Google Play and iOS. The decryption key and the steps for getting past the apps' protection aren't published. If a free puzzle game ships three on-device models and a bandit experiment, the real question for developers isn't whether consumer apps use ML. It's how much of their behavior now lives in a config server instead of the binary. Follow for more coverage on MCP, agentic AI, and AI infrastructure. Inspired to write this by @StompnWorldfan's video on YouTube: watch it here.