"""Write the requested reports from preserved analysis outputs, not guessed counts."""
from analyze import *

def mdtable(headers,rows):
    clean=lambda v:str('NA' if v is None else v).replace('|','\\|').replace('\n',' ')
    return '| '+' | '.join(headers)+' |\n|'+'|'.join(['---']*len(headers))+'|\n'+''.join('| '+' | '.join(clean(v) for v in r)+' |\n' for r in rows)

def put(name,text):
    (ROOT/name).write_text(text.strip()+'\n')

def main():
    q=read(ROOT/'analysis/archive-inventory-coverage.json');fs=read(ROOT/'analysis/function-summary.json');cp=read(ROOT/'analysis/temporal-checkpoints.json')
    summary=read(ROOT/'analysis/summary.json');cases=read(ROOT/'analysis/cases.json');sh=read(ROOT/'analysis/cross-entry-transfer.json')
    es=lines(ROOT/'analysis/events.jsonl');events={(e['app']+'-'+e['rep'],e['transition_id']):e for e in es}
    head=read(ROOT/'evidence/code-provenance.json')['head']
    invtable=mdtable(['App / Rep','确认源访问','Selection','同GUI源树 / 比例','输入前已记录树','PARTIAL','INFERRED','EXACT / MISSING'],
        [(r['run'],r['confirmed_source_visits'],r['decision_points'],f"{r['same_GUI_source_visits']} / {r['same_GUI_source_fraction']:.2%}",r['GUI_logged_by_input'],r['source_PARTIAL'],r['source_INFERRED'],'0 / 0') for r in q])
    funcrows=lambda app:[r for r in fs if r['run'].startswith(app+'-')]
    functable=lambda rr:mdtable(['Run','冻结功能线索','入口次数','B边界已观察','关联新State / 首次ID转换 / 首次局部Concrete','最多相同完整路径','同GUI树'],
        [(r['run'],r['function'].split('.',1)[1],r['entry_executions'],r['complete_segments'],f"{r['native_new_state']} / {r['first_ID_only_model_transition']} / {r['first_local_concrete']}",r['max_repeated_complete_path'],r['functional_GUI_snapshots']) for r in rr])
    selected={'odkcollect.download','activitydiary.add-activity','activitydiary.edit-existing-activity','omninotes.settings','omninotes.search-notes','scarletnotes.create-note-empty-state','wikipedia.global-search'}
    cptable=mdtable(['Run / 功能','80%前入口数','最近≤5完成发生 S / T / C','后续入口','留出新S / 新ID-T / 新局部C','精确剩余C'],
        [(c['run']+' / '+c['function'].split('.',1)[1],c['past_entry_count'],f"{c['recent_metrics']['native_new_state']} / {c['recent_metrics']['first_ID_only_model_transition']} / {c['recent_metrics']['first_local_concrete']}",c['future_validation']['occurrences'],f"{c['future_validation']['native_new_state']} / {c['future_validation']['new_ID_only_model_transition_key']} / {c['future_validation']['new_concrete_key']}",None) for c in cp if c['fraction']==.8 and c['function'] in selected])
    sharingtable=mdtable(['Run','L1 有先前其他入口操作 / 未见过Target','L2 有先前其他入口操作 / 未见过Target'],
        [(r['run'],*[f"{len(xx)} / {sum(x['unseen_other_group_target'] for x in xx)}" for lev in ['L1','L2'] for xx in [[s for s in sh if s['run']==r['run'] and s['level']==lev]]]) for r in q])
    put('README.md',f'''# 功能入口、动作机会与历史结果：多 App 离线研究

**可以知道已确认尝试了哪些具体操作，现有归档不能完整知道当时还有哪些有效且可选择的 Concrete 操作。** APE 维护的是 State 的 ModelAction、当前匹配节点及每个模型动作的随机代表绑定，而不是一个已逐成员验证、经过全部策略枚举的 Concrete 库存。下一阶段应补齐被动 Shadow 观察，再检验充分性；本轮没有实现采集或禁用。

## 数据与研究范围

- 沿前四轮冻结入口与第五轮证据口径，复核五 App、十条 `COMPLETED_VALID` Pure；23,279 确认执行，23,971 Selection，2,280 份抽样原生 GUI Tree。
- 116 个既有探索性功能×run 入口组保留在 `analysis/frozen-entry-groups.*`，其中按本轮线索深审40组、1,967入口发生、160检查点、2,792条局部操作/结果账本。不是新发现功能数量。
- 全部归档路径、run/APK/JAR/seed/起止时间与SHA见 [白名单](evidence/archive-manifest.json)。Wikipedia Rep1有2条未确认转换，保留在总拓扑/事件校验，未计实际执行。
- 当前源码 HEAD `{head}`；源码SHA与摘录见 [source-index](evidence/source-index.json)、[关键源码摘录](evidence/source-excerpts.txt)。归档JAR有独立SHA，不把当前HEAD冒称每条归档二进制的逐字源码。
- 没有设备/模拟器/GPU/Provider调用，没有新实验、训练、Probe优化、Locator、SUPPRESS、Prompt或正式源码修改。只读白名单完成归档，不访问活动实验状态。

## 从哪里开始

1. [结论](conclusion.md) 回答六个问题。
2. [交互式查看器](visuals/index.html) 展示24个真实案例、十run入口发生、GUI、机会缺口与检查点。
3. [源码审计](ape-action-inventory-audit.md)、[库存完整性](archive-inventory-coverage.md)、[最小Shadow设计](shadow-capture-design.md)。
4. [五App对照](multi-app-analysis.md)、[时间验证](temporal-validation.md)、[共享分析](cross-entry-sharing.md)、[案例](representative-cases.md)。

## 复算与离线使用

在仓库根目录执行以下命令；脚本只写本研究目录，需要已有 Python/Pillow/Playwright，**不安装依赖、不触发Native**：

```bash
PYTHONDONTWRITEBYTECODE=1 python3 reports/region-action-opportunity-study-20261107/analysis/analyze.py
PYTHONDONTWRITEBYTECODE=1 python3 reports/region-action-opportunity-study-20261107/analysis/enrich.py
PYTHONDONTWRITEBYTECODE=1 python3 reports/region-action-opportunity-study-20261107/analysis/write_reports.py
PYTHONDONTWRITEBYTECODE=1 python3 reports/region-action-opportunity-study-20261107/analysis/build_viewer.py
PYTHONDONTWRITEBYTECODE=1 python3 reports/region-action-opportunity-study-20261107/analysis/verify.py
PYTHONDONTWRITEBYTECODE=1 python3 reports/region-action-opportunity-study-20261107/analysis/test_viewer.py
```

**将整个目录或便携ZIP复制到另一台电脑，解压后双击 `visuals/index.html`。** HTML、data脚本、图片和便携证据均是相对路径，不需启动Web服务、不请求CDN。单独复制HTML会缺少相邻资源。查看器中源码/Markdown在浏览器中可能作为文本下载，公共副本另转静态HTML。

## 指标与NA

Selection≠确认输入≠到达；入口发生≠功能Region。B表示已观察导航/页面分段，不认证完整功能边界；A2/5/10/20包括入口再加N个后续确认步骤。共享MainActivity会混杂其他页面，本轮明确保留，不把所有窗口新发现归因于功能。

局部Concrete键为 `(input_version, source State, input ModelAction, identity_digest)`；L2为 `(Activity, action type + Jev fullName)`，后者不要求同State。模型转换分别保留版本键与裸ID三元组敏感性；观察版本变化不能被偷偷合并成稳定身份。首执行/新转换均按整个run前缀计算。CSV空单元格为NA，JSON为null；从不以0代缺失库存。

角色分类与功能关联继承前轮离线推断，**未有人类金标**。图片来自归档原始像素，缩小JPEG；同State代表图不认证当次截图/框线对齐。所有前轮、Native及已有用户修改SHA已保护，验收见 `evidence/verification.json` 与 `browser-verification.json`。
''')
    put('ape-action-inventory-audit.md',f'''# APE 真实动作库存与选择机制审计

审计当前HEAD `{head}`。以下路径均相对 `native/src/com/android/commands/monkey/`；[含行号摘录与SHA](evidence/source-excerpts.txt)用于复核，不凭旧论文或最终UTG推导运行机制。

## 实际调用链

`MonkeySourceApe.generateEvents:425–474` 获取 top Activity 与 Accessibility root（源码承认不是原子观察） → `ApeAgent.updateState:278–292` → `StatefulAgent.buildAndValidateNewState:537–543` → `GUITreeBuilder/Naming/State` → `validateAllNewActions:833–837` → `adjustActionsByGUITree:859–860` → `SataAgent.selectNewActionInRound:399–473` → `Graph.markVisited`（输入前） → `ApeAgent.checkInput:175–185` → `MonkeySourceApe.generateEventsForAction:548–565` → 注入回执 → `JevRuntime.inputSummary:764–793` → 下一GUI观察形成 `NATIVE_TRANSITION`。

1. **保留树与理论GUI不同。** `tree/GUITreeBuilder:480–516` 根据 `excludeInvisibleNode/excludeEmptyChild/alwaysIgnoreWebView` 剪枝；`263–285,309–351` 应用XPathlets、父子click补丁、图像文本和WebView策略。`Config:79–104` 给默认值，不代表每个归档覆盖配置均已记录。可见但未暴露交互属性、被剪除或未映射的控件不自动成为动作；图像生成文本会改变原生Naming。
2. **State模型动作。** `model/State:50–65,210–216` 从 StateKey widgets 的 `NamerFactory.decodeActions` 建 `ModelAction[]`，并加无target Back。`naming/ActionPatchNamer:51–77` 对 clickable/checkable 建Click、longClickable建LongClick、scrollType建各方向Scroll；构造动作类型本身不先过滤disabled。`Naming.addNamedNode:212–242` 可过滤空/屏外节点。输入框没有独立的全字符串动作全集。
3. **每动作的控件匹配成员。** `tree/GUITree:198–209` 在当前Naming缓存 `currentNames/currentNodes` 中查Name，得到节点数组；`State.resolveAction:346–358` 从数组随机选**一个**代表。`ModelAction:35–43,208–228` 保存 `resolvedNodes`、`resolvedNode`、`resolvedTree`、timestamp和单个 `GUITreeAction`。所以不是“直到选中才第一次解析”：每个新模型动作会先解析，但也不是“所有Concrete已逐项验证”。
4. **有效性、enabled、优先级。** `StatefulAgent.validateNewAction:813–830` 可能复用同timestamp缓存，否则重解析随机代表；委托 `MonkeySourceApe.validateResolvedAction:338–375` 对该代表检查非空、与root相交（不是完整hit-test或业务成功）；Back有效。`AgentActionScorer:48–94` 依据代表节点设置enabled与priority，结合unvisited、别名数量及图上后继。`Action:59–86` 存enabled/valid，二者不是每个兄弟节点的表。未验证成员应记UNKNOWN，而不是复制代表valid。
5. **选择是一串策略，不是一个Concrete清单。** `SataAgent:399–473` 按buffer、Activity返回、早期/局部greedy、远程greedy、trivial、backward、epsilon、fallback尝试。`ActionFilter` 包含enabled-valid-unvisited/unsaturated集合。`SataAgent.getGreedyActions:599–621` 在useActionDiffer时调用 `model/StateActionDiffer:43–110`，比较相邻State的Name/Type和饱和；否则 `Graph.isActionUnvisitedByName:177–193` 查同Activity+抽象Name+Type历史。后者并非精确Concrete历史。档案未逐轮保存这些完整中间名单/未选原因，不能声称enabled-valid中的每个成员当轮都有被所有策略选择的机会。
6. **输入参数后置。** `ApeAgent.checkInput:175–185` 在模型动作选出后可能随机从 `StringCache` 选择输入文本；XPathlet也可预设（`GUITreeBuilder:129–145`）。`MonkeySourceApe:480–522` 用代表bounds生成click/longclick/scroll/Back；`MonkeySourceApeInput:80–130` 清文本、直接sendText、失败后key fallback。一次控件动作可包含多条低层事件/文本参数，不能按输入事件条数算Concrete执行，不能枚举无限文本组合为完整覆盖分母。

## 必须分开的五层集合

|集合|运行时载体|有无完整性|归档可证范围|
|---|---|---|---|
|GUI理论交互控件|Accessibility tree，经Native预处理后保留GUITree|仅保留树完整，不是全部App交互|2,280抽样树；不认证模型资格|
|State识别的ModelAction|`State.actions[]` + Back|当前State完整模型名单|23,971次有总数；2,131次可从unvisited IDs∪selected ID恢复全部ID，仍缺全属性|
|当前解析Concrete成员|各`ModelAction.resolvedNodes`，tree/timestamp必须一致|已解析成员数组，需标识缓存新鲜度|仅选中node及选中动作成员数量；全数组未记录|
|已验证有效Concrete|每动作的`resolvedNode`与action.valid/enabled|仅随机代表验证，无逐成员有效性全集|已确认选中输入事实，不是其他成员资格|
|策略实际可选动作|各策略局部列表、路径、当前代表绑定|顺序/随机/阶段相关，无统一物化全Concrete集合|仅选中策略/计数，没有每个未选动作的理由|

因此，回答Q1是：**有有限的模型动作与匹配控件缓存；没有一个可直接读出的“全部有效、策略可选、含全部输入实例”的完整Concrete库存。** 对控件层可做更好的被动采集，但仍须分别解释模型成员、缓存代表与策略实际触达。

## 历史与身份

- `GraphElement:25–88` 的visitedAt计数；`Graph.markVisited:508–527` 管理已访问ModelAction集合；`StatefulAgent:562` 在输入前加计数。`Model.appendToActionHistory:135–140` 是生成路径记录，不能仅凭它认证注入成功。
- `ModelAction.resolveAt:220–227`：单节点饱和由ModelAction是否visited决定；多节点为 `min(1, visitedCount/min(nodes.length,saturatedVisitedThreshold))`。这不是逐Concrete覆盖，更不是各参数/结果分支覆盖。
- `JevRuntime.inputSummary:764–793` 只有确认输入才进 `confirmedInputs`；执行成功不证明业务成功。`JevRegistry.confirmedHistory:311–341` 以当前映射的State/ModelAction组织历史，refinement会更改树/动作归属，须核对version与mapping完整性。
- 精确Concrete是 `ConcreteActionIdentity(actionType,JevIdentity.fullName(node))`；`JevIdentity:63–70` 只归一化有来源标记的图像hash文本，保留真实文本、祖先、index及交互patch。动态值会拆分，兄弟行语义又未必入fullName。
- `JevRegistry.hasExactExecution:359–366` 是当前State/action与Concrete；`hasRelatedConcreteExecution:369–386` 为同Activity+精确Concrete存在性，不能认证所有同业务入口或结果。旧的页面history池、related index与原生 `nameToActions` 是不同机制，不能混说为通用语义共享。

## 现有日志为何仍不够

`JevRuntime.stateTelemetry:1022–1062` 记录各类数量、unvisited IDs；`recordSelectionDecision:848–872` 记录选中类型/visit/饱和/fingerprint及resolvedNodeCount。`JevEvidenceAudit:203–239` 只对满足抽样条件的source/target保留树图；`input_event_inventory` 的“inventory”是**单个选中输入的低层事件数组**，不是当前页面动作库存。Pure未运行Region/审核候选机制，其context缺失不能靠决策组日志冒补。

详见 [字段完整性矩阵](analysis/inventory-field-coverage.csv) 和 [Shadow设计](shadow-capture-design.md)。本轮未运行Java重解析旧树，更没有把当前源码运行结果当作历史真实候选。
''')
    put('archive-inventory-coverage.md',f'''# 十条 Pure 的历史动作库存完整性

## 证据分母与等级

源访问以23,279次确认转换对应的source GUI/输入为分母；到达以同数target GUI为另一分母；决策为23,971次Selection，分别输出而不相加。只有10run的白名单完成归档，原始事件总数与确认位逐条核对。

- EXACT：同时记录完整Native动作成员、有效性与策略资格；本批为0。
- PARTIAL：至少记录真实选中的Concrete或同GUI的保留树；**可能只有一个控件**，不表示可恢复多数动作。
- INFERRED：仅有State/模型计数，无Concrete库存成员；主要是Back等无target输入。
- MISSING：没有上述两种证据；本批源访问整体为0，但“完整逐成员有效性”“未选原因”等字段在全部决策中缺失，见下表。

{invtable}

源访问PARTIAL共19,027、INFERRED 4,252；其中确认有目标Concrete为18,926次，额外101次只有保留树而非目标Concrete。2,253/23,279=9.68%源访问有同GUI树，**不是9.68%拥有完整可执行库存**。完整库存恢复率为0/23,279。2,280份树可能重复同GUI或是target/崩溃保留，不能直接除源访问数冒充覆盖。

`GUI_logged_by_input`仅1,225，剩余同GUI树在输入/目标/崩溃回收时才写出；可事后确认同缓存树节点，但不能算在当时在线特征中已记录。截图也非原子Tree+Bitmap。逐源记录在 [source-visit-inventory.csv](analysis/source-visit-inventory.csv)；选择、到达和维度缺失统计见JSON和 [inventory-field-coverage.csv](analysis/inventory-field-coverage.csv)。

## 字段级恢复

23,971次有ModelAction总数、enabled-valid计数、unvisited IDs及选中Action信息；在2,131次（8.89%），`unvisited IDs∪selected ID`个数恰等总数，可恢复当次**完整ID集合**。不能由此获得全部类型、target Name、节点成员或逐项valid。其余使用部分ID，不从最终图补齐。

共有2,268次决策选中ModelAction的resolved_node_count>1。日志只保存数量及随机代表，不保存那些非代表兄弟节点的完整身份/逐成员有效性。selected_model_action_visits是模型生成前历史，不等于已确认Concrete覆盖。

完整Concrete库存、当前有效未试Concrete数、操作/参数/结果覆盖分母均NA。最终StateGraph、STATE_FINAL、MODEL_ACTION_FINAL只可用于事后诊断/找代表图，未用于历史库存恢复。

## 哪些功能能初步分析、哪些最缺证据

- ODK Download两个Rep关联段同GUI树均0，表单列表相关段也0；已有输入/计数足以证实重复路径与晚期首次Checkbox，不足以证明机会耗尽。Settings分别5/9份树，仍无Naming-成员-资格映射。
- ActivityDiary Add/Edit有共享控件确认与少量/较多树；可验证字段/颜色/Save样例，不能将Save的不同对象结果当覆盖完成。
- Omni Settings、Search、附件、提醒存在不均衡抽样；提醒的日期/时间与搜索MainActivity复用尤其需要分模式/边界。附件发生关联树Rep1/2为5/2，不代表同页全部可选控件。
- Scarlet CreateNote Rep1关联130份树，Rep2仅1；CreateList虽Ⅰ类入口仍pending，但已有579/351次确定页面源执行与204/61份该Activity树，可审计局部编辑而不补造入口。
- Wikipedia Search有真实控件/查询输入，媒体Gallery Rep1关联树0、Rep2为6；文章/媒体业务与网络成功没有独立结果金标。阅读、搜索和共享组件不是互斥State集合。

完整页面上下文可用性见 [activity-context-coverage.csv](analysis/activity-context-coverage.csv)，各功能见 [function-summary.csv](analysis/function-summary.csv)。所有功能均“可分析已发生事实、无法认证剩余有效动作清零”。
''')
    put('functional-opportunity-ledger.md',f'''# 功能入口的三层探索机会账本

复用既有116个功能×run组，深审40组、1,967次真实入口发生。没有从resource-id或Action Type重新发明功能合并。确认成员、先前pending/UNKNOWN保留；CreateList仅上下文记录，不补为Ⅰ类。全部入口标签继承离线推断，未经人工金标。

## State、Action、Result三个层次

1. **State**：每次入口的 source/target、真实顺序、版本、局部后续记录；访问与首次观察按全run前缀。State拆分/版本变化不被自动并成新业务。共享State允许重叠。
2. **Action**：23,279次完整确认执行与18,926个有目标操作发生事实；`functional-action-result-ledger.*` 2,792行以局部Concrete键归集，保留真实输入参数、逐次执行ID、目标分布。当前可用/未试Concrete列全为NA，不把历史出现过的控件当永久机会。
3. **Result**：每个具体动作的Target、版本转换、新ID三元组、输入文本、模式/对象敏感性。Target不同为“可区分GUI结果”，不是已认证业务功能分支；Target相同也不能证明数据落盘/后端结果一致。`all_results_explored=UNKNOWN`。

账本和检查点将“已经执行过操作”与“所有结果已探索”分开。`model-action-concrete-diversity.csv`列出一个version/State/ModelAction下实际执行过的不同identity，**不是当时同页同时可用的数量**。颜色/日期/动态文本可能增加具体键，不按其数量宣称新业务。

## 未验证机会如何保留

历史Selection未访问ID是模型机会提示。对每个检查点，只取过去已访问source的最近同version快照，减去之后至检查点已有确认执行的ModelAction，记录age和原enabled-valid-unvisited数量；无法把数量映射到每个ID的enabled/valid，也无法证明旧快照在当前页仍有效。

未来真正执行的这些ID写入独立 [historical-opportunity-warnings.csv](analysis/historical-opportunity-warnings.csv)，132行是跨检查点重复证据，不是132个独立新操作。后来成功只能验证后来机会，不能回填过去身份与有效性。Back模型提示单列action_type，不作为待试具体控件。

## 边界和复用限制

B沿真实确认执行，GUI ID/timestamp/State/version/事件位置任何断裂即右删失；明确页面/Activity退出、其他Ⅰ入口、QuickFix模式移交分段，并保留退出结果。Save/Back不按名称提前切；固定2/5/10/20步仅对照。不同入口的B片段可共享操作，非互斥分区。

除ODK Download、AD Editor、Omni Settings、Scarlet CreateNote、Wiki Search已有页面线索外，其他冻结功能用同Activity保守片段；MainActivity内功能切换可能漏切。`complete`只表示观察到分段边界，不能当完整业务访问认证。发生关联表不用于严格因果归因或业务覆盖率。

{functable(fs)}

S/T/C列是去重执行集合中全run首次观察事件数，退出结果可在内；跨功能行可能重叠，不求和当总覆盖。查看器可逐次检查动作、树、边界和未来验证。
''')
    put('cross-entry-sharing.md',f'''# 跨 State、跨入口历史可以共享到什么程度

## 现有机制，不新增语义身份系统

原生 `Graph.nameToActions`、`StateActionDiffer` 是抽象Name与Type层的选择历史；Jev的 `ConcreteActionIdentity` 则是 actionType+fullName。`JevRegistry.hasExactExecution:359–366` 与 `hasRelatedConcreteExecution:369–386` 分别提供当前State/action匹配和同Activity精确identity存在性。不能因为同名资源或同ModelAction就共享，属性相似排序也不会把当前历史池自动扩为完整功能池。

本轮L1使用输入时version+State+ModelAction+Concrete；L2为同Activity+精确identity。它们是保守离线证据键，不等同于Native refinement后对象重映射的全量模拟。L3结构/模板候选只在页面与原件中展示，不把它当覆盖事实。

## 时间有序的跨入口操作/结果

以下只统计40个深审入口组内：某次操作之前，其他入口组已有相同键的确认记录；不是全App共享率或错误率。

{sharingtable}

ActivityDiary复现最明确。Add/Edit后续在L1有98/74次操作可检索先前另一入口样例，其中35/50次得到该另一入口此前未见Target。操作样例可复用，创建/编辑、对象与保存结果不能因此判充分。Rep1 `g28e189:231 编辑 → g28e190:232 Save → g28s87`，与 `g28e233:275 Add → g28e234:276 Save → g28s90`，相同编辑State/控件仍结果不同。Rep2 `g27e277:2208 Save`停留编辑State，不能把Save视为统一退出。

颜色选择、字段焦点与对话框操作可以提供“已执行过该GUI操作”的样例；输入值、初始值、对象、创建/编辑模式必须保留。Save/Delete/QuickFix属于结果敏感动作，不能共享成对象结果覆盖。

## 反例和跨App限制

- **ODK Rep2设置Checkbox**：`g16e203:355`与`:364`都为`g16s67/g16a349/android:id/checkbox`，但祖先路径分别`0-0-1-10-2`、`0-0-1-7-2`，同GUI树兄弟title为截断的“High res”“Delete a”。这是不同配置行，不应按ModelAction或Toggle合并。现有精确identity把二者分开，Native不提供逐具体已试分母。
- **Scarlet**：CreateList上下文有579/351次源执行；块的index、编辑内容与输入参数会拆分identity。相同块模板可作候选对应，移动/删除/文本值与所处Note不能当等价。Ⅰ入口尚pending，不为本研究补人工金标。
- **Omni**：同State的多语言Settings入口可拆为不同fullName；提醒日期与搜索输入/结果随数据变化。L2命中也可能只共享底层控件，而不是业务行为。
- **Wikipedia**：ⅠSearch入口与Ⅲ查询字段/提交不同；输入字段长按、Clear、结果卡、语言配置/文章阅读不可合并为一种Search执行。Gallery或主题设置的同类控件也要保留当前文章与结果上下文。

可以安全共享的是**有来源、有时间的已确认操作事实**；是否可代表当前模式、对象、参数及结果，需要额外对应证据。属性/结构相似而身份不同的成员先保留候选，不用LLM强制等价。本轮未调用研究模型。
''')
    body='''# 五 App 的探索充分性对照

本批不支持“所有App都像ODK”。下表按Rep分别报告；S/T/C均为入口关联B片段中的真实新观察，不等于新增业务功能，片段可能包含退出结果或同Activity边界混杂。

'''
    notes={
    'odkcollect':'Download Rep2晚期入口稳定，80%后21次S/T/C均零，最长相同完整路径64次；表单列表Drafts、新表单入口也反复返回已有状态。Rep1 Download晚期仍执行新Checkbox并发现转换；Download两Rep没有完整源GUI树，不能归为已认证“机会较少”。Settings入口仅2/3次且有多个配置行，不受高频主页命令代表。',
    'activitydiary':'Add/Edit跨Source和动态对象重复进入共同编辑页面，操作共享跨Rep复现，保存结果不可共享为充分。80%后Add两Rep各仍有1个原生新State；编辑Rep2即使新State为0，仍有26个新ID转换、27个新局部Concrete。新增浮层/动态值不都等于新业务。',
    'omninotes':'Rep1附件最多同一路径17次，80%后8次入口未观察S/T/C增量；Rep2附件21次中80%后仍有1新State、15新ID转换、10新Concrete。Search 68/127次，Rep2晚期仍发现操作与状态，但MainActivity复用使某些Back/菜单变化可能是退出或其他页面，不能一概称Search新功能。提醒具有日期/时间组合行为；Settings只有12/9次不支持稳定饱和。',
    'scarletnotes':'Rep2空态新建134次、最多完整同路径66次，80%后26次S/T/C零；Rep1新建27次，80%后5次仍有2新State、26新ID转换、88新局部Concrete（大量编辑文本/块实例）。不同Rep不可推广。CreateList入口pending但有大量真实局部编辑，单个ModelAction访问过不能证明块/参数/结果已覆盖。',
    'wikipedia':'SearchⅠ入口29/55次；Rep2 80%后11次仍有5新State、31新ID转换、38新局部Concrete；Rep1晚期新State零但仍有9个新转换与9个新Concrete。Query依赖输入，文章阅读/媒体/主题样本少且不少同GUI树缺失；不能按同资源合并结果。'}
    for app in FOCUS:body+='## '+app+'\n\n'+functable(funcrows(app))+'\n'+notes[app]+'\n\n'
    body+='''## 三种典型情形的证据强度

- A“高重复、低新增、机会较少”：**没有任何功能能被完整认证**，因为当前有效未试Concrete全为NA。ODK Rep2、Scarlet Rep2及Omni Rep1附件只能称A-like观察。
- B“低新增但仍有机会”：ODK Rep1给出过去未访问模型提示、后来真实Checkbox首次执行/新转换。可认证历史提示和后来的机会，不能认证两时刻之间一直有效。Scarlet Rep1等还有迟到首次操作，逐例保留。
- C“高重复但仍有新行为”：AD模式/结果、Scarlet Rep1编辑、Wiki Search Rep2有直接后续新转换/操作事实；“新业务行为”无全量标签，保留操作与GUI结果层，不夸大成功。

完整40组与未选入口116组分别在function-summary与frozen-entry-groups，不把前者当全App功能普查。两个Rep只能检查复现/反例，不能估计稳定因果效应。
'''
    put('multi-app-analysis.md',body)
    put('temporal-validation.md',f'''# 历史检查点与后续真实发现

## 无未来信息的口径

每个40组分别在入口累计20/40/60/80%确认时设置检查点，共160个。仅使用 `monotonic_ns<=cutoff` 的事件/Selection与已记录GUI；按前缀**重新分段**，不使用完整episode终点事后裁剪。target Activity只采用同GUI树/严格连续下一source回执，且受available_ns约束；最终图只供截图定位，不进入特征。

入口组是事后冻结研究cohort，不主张当时在线已能识别全部成员。历史动作与全run其他入口历史均只能读过去；未完成入口后续不进入最近完成5次。留出指标只看检查点之后新发生入口的轨迹；跨cutoff仍在进行的旧发生不强并为新入口。功能窗口有重叠，检查点有共享晚期事件，不能解释为独立样本/预测准确率。

S=原生new_state；T=首次ID三元组（另保留version键）；C=version/State/ModelAction/Concrete局部首次。`最近≤5`与`后续新集合减全run过去集合`不是同一个分母，因此数值不要求相加守恒。

{cptable}

全部160点、过去序列、当时机会快照与留出事件ID见 [temporal-checkpoints.json](analysis/temporal-checkpoints.json)。查看器默认折叠未来事实，避免在阅读过去证据时混入答案。

## 哪些信号有价值

有完整最近5个完成分段且最近new_state为0的58个重叠检查点，后来18个还有新State、40个有新ID转换、30个有新局部Concrete。最近S/T/C三类都零的29个点，后来新State为0，但15个仍有新ID转换、5个有新局部Concrete。它们说明多指标比State单指标更有区分力；**不是足够停止的阈值**，也没有评价未尝试分支。

ODK Rep1 80%为第97次Download；最近5次State与Concrete均零（转换仍有1次），之后24次入口中出现3个新ID转换和1个新局部Concrete。`g16e255:1978 → g16e256:1979 Checkbox`是具体反例。历史Selection中`g16s71/g16a582`仍未访问；真正执行时selected_model_action_visits=0/unvisited=true，Target是旧State却转换新。该同Activity精确控件以前做过，并未覆盖这个上下文。

ODK Rep2 80%第88次以后21次S/T/C零；Scarlet Rep2第108次后26次也零。因为完整库存缺失，归档没有尝试其余动作仍不能证明未来没收益。Omni附件Rep1/2晚期差异与Wiki/AD正好构成跨Rep限制。

## 机会提示并非有效库存

132条“过去模型unvisited、后来实际执行”检查点行含重复与Back；不是132个新增具体控件。过去快照的enabled-valid-unvisited总数是EXACT记录，但没有给每个ID赋资格；旧version/旧页面机会不可搬到当前页。未来执行只能证实后来可执行，不倒推早期一直可用。对象、模式、文本与不同结果仍要分开。

本轮不拟合充分性评分、阈值或SUPPRESS反事实，不把后续无新增当收益为零；未计算方法覆盖、后端成功或全业务行为覆盖。
''')
    put('representative-cases.md','''# 真实案例、反例与缺失

所有GUI来自真实归档，框线是记录bounds的投影；同State历史代表图、同GUI但未认证对齐的图均明确标注。图片非当次精确证据时，不从截图反推出Native候选资格。24案例由agent离线复核，非人工金标。

'''+''.join(f"## {c['title']}\n\n- [离线交互案例](visuals/index.html#{c['id']})；run `{c['run']}`，焦点执行 `{c['focus_event']}`，入口 `{c['entry'] or 'NA/未确认'}`。\n- {c['reason']}\n- 关联：{c['linkage']}；库存整体 `{c['inventory_level']}`，完整有效成员与剩余数仍NA。\n- Source `{events[(c['run'],c['focus_event'])]['state']}` → Target `{events[(c['run'],c['focus_event'])]['target_state']}`；{events[(c['run'],c['focus_event'])]['action_type']}，ModelAction `{events[(c['run'],c['focus_event'])]['input_model_action']}`；原始事件行 {events[(c['run'],c['focus_event'])]['event_line']}。输入/回执路径与SHA及便携原件见查看器。\n\n" for c in cases))
    put('shadow-capture-design.md','''# 最小 Native Shadow 采集设计（仅设计，未实施）

## 依据与最小范围

历史缺口位于“全部ModelAction已有解析缓存”到“按策略使用随机代表”之间：当前只输出模型数量及最后一个选中控件，未输出所有动作的匹配节点、资格新鲜度和策略实际触达。既有input/注入/transition足够证明已尝试事实，应复用，不复制一套执行器/数据库/身份系统。

最小新增是**一次决策的被动模型/解析缓存快照 + 实际选择关联**。它能补足控件机会证据，但不声称穷举所有输入字符串、动态对象或业务结果。先采Shadow，不改变排序、预算、阈值或禁用规则。

## 采集点与数据来源

|点|真实函数/位置|记录内容|不得做的事|
|---|---|---|---|
|S0 当前缓存快照|`StatefulAgent.resolveNewAction:840–856`中`adjustActionsByGUITree`之后、首次选择之前；State/tree/timestamp需一致|`newState.getActions()`全部ID/type/Name/valid/enabled/priority/visited/saturation；`getResolvedNodes/Node/Tree`缓存、GUI与Naming/version|不重跑resolveAction/validateNewAction、不消费RNG、不重新Naming、不抓新树|
|S1 选择实际触达|`SataAgent.returnSelectedAction:304–318`、`StatefulAgent.validateNewAction:813–830`原有结果返回处|本轮真实尝试的策略、动作、代表、已有validate结果，最终selected；未触达策略记NOT_EVALUATED|不为了记录全部候选重新跑策略或validator；不把未选都标disabled|
|S2 输入实例|既有`JevEvidenceAudit.beforeInput:203–216`/`MonkeySourceApe.generateEventsForAction:548–565`|snapshot_id→input_id、最终代表与参数、绑定是否变化，复用生成/注入记录|不把S0的代表当最终输入；不新增输入计划|
|S3 真实结果|既有`JevRuntime.inputSummary:764–793`与NATIVE_TRANSITION、transition receipt|确认/失败/丢弃，target GUI/version/State与输入实例关联|不以markVisited/生成输入替代确认执行，不推定业务成功|

S0只是当前随机代表资格的被动真值。每个resolvedNodes成员只有命名匹配；代表之外`native_validation=NOT_EVALUATED`。若某动作缓存tree/timestamp过期，记录STALE，而不是调用resolver刷新。需在后续设计验证已有缓存是否足够完整；不能保证单个快照等于所有潜在Concrete随机结果的已验证集合。

## 字段 Schema

可机器读取的 [shadow-capture.schema.json](analysis/shadow-capture.schema.json) 与 [example](analysis/shadow-capture.example.json) 是**提案示例，非采集结果**。主要字段：

- envelope：schema_version、run/attempt、process_epoch、snapshot_id、step/decision_round、monotonic_ns与wall_time、event_kind。
- observation：sourceState/model_version、Activity、GUI id/timestamp、Naming id、tree observation时间、snapshot freeze/写出时间、坐标/root bounds；区分观察时刻和日志到达时刻。
- inventory coverage：完整State动作枚举是否完成、当前tree缓存成员覆盖是否完整、逐成员Native验证是否完整、策略是否仅实际触达、丢弃/截断/未知原因。没有足够证据不设complete=true。
- 每ModelAction：ID、type、targetName引用、enabled/valid、priority、visitedCount、unvisited、resolvedSaturation、resolvedTree/timestamp、selected representative node_ref、全部已缓存member_refs（不构造新`GUITreeAction`）。
- 每节点：快照局部node_ref、parent_ref/index/path、class/resource、原始Native text/desc与generated_image_text标记、enabled/checkable/checked/clickable/longclick/scrollType、focus、bounds、inputText是否已计划；祖先与兄弟行上下文保留。现有Native文本会截断，不能假定其是完整对象业务键。
- identity：复用已存在的Concrete identity缓存；若要新计算`JevIdentity.fullName`，放在冻结的必要字段副本上离线完成并做同版等价测试，不在热路径额外调用全局Name intern。无证据则identity=null，不能伪造精确身份。
- execution：chosen action/node/input_id、已有confirmed history引用、注入结果、transition_id/target；source与target abstraction version分别保存。历史“已执行”由输入确认事实派生，不直接复制Native visit计数。
- mode/object/input：可靠已有上下文才记来源与值；无业务object键时UNKNOWN；Add/Edit和Save/Delete保留模式、对象指纹/来源及参数。入口组/功能ID可离线关联，Native不得新增语义推断或Prompt。

## 完整库存与策略资格如何解释

S0可完整列出State.actions与**缓存当前tree匹配成员**；不等于所有GUI元素，也不等于所有成员已验证。当前Native的bounds validator本身简单，但`validateNewAction`包含随机解析，不能为Shadow重调它。可在离线冻结bounds上计算非空/相交派生条件，必须标DERIVED，不冒充逐成员Native执行结果。

S1只记录实际评估/拒绝、缓存复用与最终分支；未走到的动作是NOT_EVALUATED。策略先后、路径缓存、随机数与相邻State差异不允许被重新执行来“补理由”。完全枚举潜在策略选择空间不是最小Shadow目标。

## 开销、频率与失败

历史23971决策的ModelAction中位数9、P95=25、P99=31、最大43；选中动作成员中位1、P95=4、最大50。抽样树flag操作对中位20/P95=49，**不是全State匹配成员总数**。因此不能从选中成员数量精确估计全快照体积。

建议每次正常State决策冻结一个快照，内容hash/字典去重节点与长identity，仅状态/计数/代表变化记增量；保留序号和可恢复基线。示例预算假设每点10–60KiB，则约2400点/run为24–144MiB未压缩，输入结果复用既有日志；这只是容量预算，非实测。极端别名/长文本可超出，不能截断后仍声称完整。

冻结后有界队列异步序列化写本地JSONL即可，无服务/DB。队列满记drop范围、原因和completeness=false；不阻塞、不重试改变动作选择，也不能静默丢完整性。观察新增必有CPU/内存/写盘成本，**不能承诺零耗时或完全不影响固定wall-clock预算内吞吐**；下阶段需对照测试RNG/选择序列未被采集调用改变，并测P50/P95采集耗时、队列峰值、drop率、字节/决策与动作吞吐。这里没有启动该测试。

原始敏感字段避免采密码/认证内容；公开副本另做脱敏。对象身份无法可靠获取时保留UNKNOWN，不用文本相同猜业务对象相同。

## 下一阶段最小可证伪假设

“在已给定Ⅰ入口的连续发生中，完整记录当前缓存控件成员与代表资格，再与精确模式/对象/参数下的确认操作及结果关联，能比State计数更早暴露尚未尝试的机会，并区分重复GUI操作和新结果。”

先检查Shadow完整性与留出新增解释能力，特别重测ODK晚期Checkbox、AD跨模式Save、Scarlet块操作和Wiki查询；只有证据充足才讨论充分性阈值。本轮没有修改Native或实施SUPPRESS。
''')
    put('conclusion.md',f'''# 结论：功能入口＋动作机会＋历史结果值得验证，当前数据尚不能认证机会耗尽

本轮核对十条完成Pure的23,279确认执行、23,971 Selection与2,280份抽样GUI树；深审40个冻结功能×run组、1,967入口发生、160前缀检查点。未修改正式代码或实验；探索性标签不是人工金标。

## Q1. APE是否具备完整可执行Concrete库存？

**没有一个统一、已逐成员验证并经过所有选择策略的Concrete全集。** 它有完整State ModelAction数组，以及每个动作当前Naming匹配的`resolvedNodes`，随机代表`resolvedNode`与单个绑定GUITreeAction。全部新ModelAction会先解析/验证代表，enabled-valid和priority随后按代表更新；策略顺序/路径/随机选择仍会再改变可选范围。文本参数在选择后才具体化，不能把控件数等同全部输入/结果空间。

## Q2. 十条归档能恢复多少历史动作机会？

**完整有效Concrete库存恢复0；部分证据19,027次，模型推断4,252次。** 2,253次source有同GUI树，其中1,225在输入前已写出；它们仍缺ModelAction映射、逐成员valid和未选原因。2,131个Selection可从unvisited∪selected恢复完整ModelAction **ID**，并不补齐Concrete。

{invtable}

完整Model/成员/有效性/策略层分别见字段矩阵。所有精确剩余Concrete、操作覆盖率均NA；缺失从不填零。

## Q3. 哪些功能最明显重复？

ODK Download 121/109次，Rep2 80%后21次S/T/C全零、相同完整路径最多64次；ODK列表入口同样高度重复。Scarlet空态新建27/134次，Rep2后26次三类新增零、相同路径最多66次，但Rep1晚期仍有2新State/26新转换/88新局部Concrete。Omni Rep1附件晚期零增量而Rep2仍新增，不能跨Rep推广。AD Add/Edit与Wiki Search反复进入，仍有新操作和结果。

没有完整当前库存，以上只能认证“已观察重复/低新增”，**没有任何功能可被认证为机会很少或清零**。ODK Rep1长期State不新后，`g16e255:1978 Download → g16e256:1979 Checkbox`仍首次执行局部Concrete并产生新转换；过去未访问模型提示有预警价值。

## Q4. 跨State/入口能共享到什么程度？

共享有来源时间的操作样例可以。AD L1跨入口先有样例98/74次，其中35/50次后来得到先前另一入口没见过Target；相同Save在Add/Edit对象上结果不同。字段/颜色可提供共享GUI操作证据，Save/Delete/QuickFix、对象、输入值及结果需分开。

ODK Rep2两个不同配置Checkbox是同State/ModelAction/resource但不同祖先行、不同兄弟标题；不能合并为一个已试Toggle。Scarlet动态块、Omni多语言/提醒、Wiki查询/文章也分别保留模式/对象差异。现有同Activity+精确identity索引适合找操作先例，不能证明功能/结果等价；相似结构仅是待审候选。

## Q5. 动作库存比State计数提供什么新证据？

**有明确新增价值，但本批只能验证部分价值。** State零增量掩盖首次控件尝试、新转换、不同Save结果；历史unvisited模型提示可指出未验证机会。58个最近5次new_state为零的重叠检查点，后来18个仍有新State、40个新转换、30个新Concrete；三指标都零的29点仍有15点新转换、5点新Concrete。不是独立准确率或正式阈值。

完整当时库存本可回答“哪些有效控件还没试”，现在没有这个分母。截图按钮、最终ModelAction集合与后来未出现新发现都不能填补它。其他App的动态实例又可能制造Concrete新颖性，必须联合参数、结果和模式。

## Q6. 最少新增什么能力？

在`StatefulAgent.resolveNewAction`评分后/选择前，被动冻结State.actions与当前resolved节点缓存、代表、tree/timestamp/version、valid/enabled/priority/访问状态；在实际选择路径记录真实触达与绑定变化；复用现有input_id、注入确认与transition结果链。节点保留祖先/行上下文、checked、动态值与参数/对象模式证据；未知不强推断。

非代表验证为NOT_EVALUATED、旧缓存为STALE、未走到策略为NOT_EVALUATED，不通过额外resolver/RNG/策略重跑“制造完整库存”。字段与JSON Schema见 [最小Shadow设计](shadow-capture-design.md)。这是数据采集提案，没有实施。

## 下一阶段最小机制假设与停止边界

支持下一阶段验证“**入口发生＋缓存动作机会观察＋带模式/对象/参数的确认操作/结果账本**”，保留Dominator作为局部结构线索。首先检验Shadow能否覆盖实际当轮成员、是否能预警留出首次操作/新结果，以及跨入口共享会不会掩盖结果差异；不再用静态子树直接定义充分性。

当前研究只证明重复事实、部分机会提示和操作/结果必须分层，不证明安全禁用。未尝试的后续机会仍未验证；没有业务成功/方法增益全量证据，不能承诺预测完全充分。调查与设计到此停止，未加采集、Locator、阈值或SUPPRESS规则。
''')
    # The schema deliberately does not claim that cached member validity is complete.
    nullable_string={'type':['string','null']};nullable_int={'type':['integer','null']}
    schema={'$schema':'https://json-schema.org/draft/2020-12/schema','$id':'urn:guitaboo:shadow-opportunity-proposal:v1',
        'title':'PROPOSED ONLY — passive Native opportunity shadow envelope','type':'object',
        'required':['schema_version','proposal_only','event_kind','run_id','process_epoch','snapshot_id','step','monotonic_ns','coverage'],
        'properties':{'schema_version':{'const':'guitaboo-opportunity-shadow-proposal-v1'},'proposal_only':{'const':True},
          'event_kind':{'enum':['INVENTORY_CACHE','SELECTION_BINDING','INPUT_LINK','RESULT_LINK','DROPPED_RANGE']},
          'run_id':{'type':'string'},'attempt_id':nullable_string,'process_epoch':{'type':'string'},'snapshot_id':{'type':'string'},
          'step':{'type':'integer'},'decision_round':{'type':'integer'},'monotonic_ns':{'type':'integer'},'wall_time_ms':nullable_int,
          'observation':{'type':'object','properties':{'state_id':nullable_string,'model_version':nullable_int,'activity':nullable_string,
              'gui_id':nullable_int,'gui_timestamp':nullable_int,'naming_id':nullable_string,'tree_observed_ns':nullable_int,
              'frozen_ns':nullable_int,'written_ns':nullable_int,'root_bounds':{'$ref':'#/$defs/bounds'}}},
          'coverage':{'type':'object','required':['model_actions_complete','cached_members_complete_current_tree','all_members_native_validated','strategy_scope','dropped_records'],
            'properties':{'model_actions_complete':{'type':'boolean'},'cached_members_complete_current_tree':{'type':['boolean','null']},
              'all_members_native_validated':{'type':['boolean','null']},'strategy_scope':{'enum':['ACTUALLY_EVALUATED_ONLY','UNKNOWN']},
              'dropped_records':{'type':'integer','minimum':0},'reason':nullable_string}},
          'model_actions':{'type':'array','items':{'$ref':'#/$defs/model_action'}},'nodes':{'type':'array','items':{'$ref':'#/$defs/node'}},
          'selection':{'type':['object','null'],'properties':{'model_action_id':nullable_string,'node_ref':nullable_string,'strategy':nullable_string,
              'input_id':nullable_string,'binding_changed_since_snapshot':{'type':['boolean','null']},
              'actual_evaluations':{'type':'array','items':{'type':'object','properties':{'strategy':nullable_string,'model_action_id':nullable_string,
                'node_ref':nullable_string,'status':{'enum':['ACCEPTED','REJECTED','CACHE_REUSED','NOT_EVALUATED']},'reason':nullable_string}}}}},
          'result':{'type':['object','null'],'properties':{'input_id':nullable_string,'input_confirmed':{'type':['boolean','null']},
              'transition_id':nullable_string,'target_state':nullable_string,'target_model_version':nullable_int,'target_gui_id':nullable_int,
              'business_success':{'enum':['UNKNOWN','OBSERVED_WITH_PROVENANCE']},'outcome_evidence_ref':nullable_string}},
          'context':{'type':'object','properties':{'function_group_id':nullable_string,'mode':nullable_string,'object_key':nullable_string,
              'object_key_provenance':nullable_string,'input_parameter_ref':nullable_string,'evidence_ref':nullable_string}}},
        '$defs':{'bounds':{'type':['array','null'],'items':{'type':'integer'},'minItems':4,'maxItems':4},
          'model_action':{'type':'object','required':['id','type','enabled','valid','representative_ref','member_refs','cache_status'],
             'properties':{'id':{'type':'string'},'type':{'type':'string'},'target_name_ref':nullable_string,'enabled':{'type':'boolean'},
                 'valid':{'type':'boolean'},'priority':{'type':'integer'},'visited_count':{'type':'integer'},'unvisited':{'type':'boolean'},
                 'resolved_saturation':{'type':'number'},'resolved_gui_id':nullable_int,'resolved_timestamp':nullable_int,
                 'representative_ref':nullable_string,'member_refs':{'type':'array','items':{'type':'string'}},
                 'cache_status':{'enum':['CURRENT','STALE','UNRESOLVED','UNKNOWN']}}},
          'node':{'type':'object','required':['ref','parent_ref','index','class','resource_id','bounds','native_validation'],
             'properties':{'ref':{'type':'string'},'parent_ref':nullable_string,'index':{'type':'integer'},'path':nullable_string,
                'class':{'type':'string'},'resource_id':{'type':'string'},'native_text':nullable_string,'native_content_desc':nullable_string,
                'generated_image_text':{'type':['boolean','null']},'enabled':{'type':['boolean','null']},'checkable':{'type':['boolean','null']},
                'checked':{'type':['boolean','null']},'clickable':{'type':['boolean','null']},'long_clickable':{'type':['boolean','null']},
                'scroll_type':nullable_string,'focused':{'type':['boolean','null']},'bounds':{'$ref':'#/$defs/bounds'},'planned_input_text_ref':nullable_string,
                'concrete_identity_ref':nullable_string,'identity_provenance':{'enum':['EXISTING_CACHE','OFFLINE_RECONSTRUCTED_TESTED','UNKNOWN']},
                'native_validation':{'enum':['REPRESENTATIVE_ACCEPTED','REPRESENTATIVE_REJECTED','NOT_EVALUATED','STALE','UNKNOWN']}}}}}
    write('analysis/shadow-capture.schema.json',schema)
    write('analysis/shadow-capture.example.json',dict(schema_version='guitaboo-opportunity-shadow-proposal-v1',proposal_only=True,
        event_kind='INVENTORY_CACHE',run_id='PROPOSAL_NOT_REAL_DATA',process_epoch='proposal',snapshot_id='proposal-s0',step=0,monotonic_ns=0,
        coverage=dict(model_actions_complete=False,cached_members_complete_current_tree=None,all_members_native_validated=False,
            strategy_scope='ACTUALLY_EVALUATED_ONLY',dropped_records=0,reason='schema illustration only; no Native shadow has run'),model_actions=[],nodes=[]))
    # Preserve the already-reviewed entry-cohort denominator bridge explicitly.
    # Reuse only its membership evidence, never its old boundary/gain statistics.
    bridge_path=ROOT.parent/'region-exploration-evidence-20261107/analysis/denominator-bridge.csv'
    bridge_bytes=bridge_path.read_bytes()
    bridge=list(csv.DictReader(bridge_bytes.decode().splitlines()))
    row=next(r for r in bridge if r['run']=='odkcollect-Rep2' and r['frozen_study2_entries'])
    additional=json.loads(row['parent_card_additional_entries'])
    assert len(additional)==5 and int(row['frozen_study2_entries'])==104 and int(row['expanded_frozen_study4_entries'])==109
    occurrences=read(ROOT/'analysis/entry-occurrences.json')
    current={o['entry'] for o in occurrences if o['run']=='odkcollect-Rep2' and o['function']=='odkcollect.download'}
    assert len(current)==109 and set(additional)<=current and len(current-set(additional))==104
    delta=[]
    for tid in additional:
        e=events[('odkcollect-Rep2',tid)]
        assert e['label']['function']=='odkcollect.download'
        delta.append(dict(app='odkcollect',rep='Rep2',event_id=tid,source_state=e['state'],target_state=e['target_state'],
            model_action=e['input_model_action'],resource_id=e['resource_id'],node_path=e['node_path'],
            legacy_entries=104,current_frozen_entries=109,reason='previously reviewed get_forms parent card; not a study6 discovery',
            inherited_from='region-exploration-evidence-20261107/analysis/denominator-bridge.csv',inherited_source_sha256=hashlib.sha256(bridge_bytes).hexdigest()))
    table('denominator-bridge',delta)
    note='''

## 与前轮入口分母的对照

本轮沿用第四、五轮已审入口组：ODK Download Rep1/Rep2 为 **121/109** 次。第二轮旧分母为121/104；Rep2额外5次是此前已确认的 `get_forms` 父卡片，不是本轮新增分类或新实验。真实执行为 `g20e251:700`、`:736`、`:768`、`:787`、`:815`，详见 [分母桥接与原件SHA](analysis/denominator-bridge.csv)。

本轮时间检查点与B片段均按当前109次重新计算；不把第五轮桥接表中的旧边界/收益数字复制为本轮结果。增加5次成员不能计作动作库存恢复、入口发现率或探索机制收益。
'''
    for filename in ['README.md','functional-opportunity-ledger.md','conclusion.md']:
        p=ROOT/filename;p.write_text(p.read_text().rstrip()+note+'\n')
    print('wrote ten requested reports, proposal Schema and example; preserved legacy/current entry denominator bridge')

if __name__=='__main__':main()
