diff --git a/.workbuddy/memory/2026-10-17.md b/.workbuddy/memory/2026-10-17.md deleted file mode 100644 index f2f36c0b..00000000 --- a/.workbuddy/memory/2026-10-17.md +++ /dev/null @@ -1,25 +0,0 @@ -# 2026-10-17 - -## Benchmark 文档 review(惰性镜像 + 文件系统章节) - -用户要求 review `docs/src/*/benchmarks/` 的撰写风格,认为惰性镜像与文件系统两章不像开源项目行文、过于进攻性。 - -结论: -- 两章的证据纪律(CI、provenance、失败保留)是优点,进攻感主要来自"以竞品为参照的获胜式断言"而非数据本身。 -- P0 发现:`filesystem.md`(中英两版)章节顺序违反 `benchmark/README.md#structure` 固定四节顺序(Motivation 排在主要结论前);结论节点名 Firecracker/QEMU/Docker 做"更快"断言,但数据为 N=3 探索性浅测,与页内"N=3 不支持普遍排名"自相矛盾;640 MiB 工作集 4 个超时单元只在折叠区,结论节无短板(违反"有短板就写短板")。 -- P1:filesystem 结论首句未回答标题问题;缺选型含义表(startup/index 有);index.md 标题"在哪些场景有优势?"给整个 section 定了竞争基调。 -- lazy-image-startup.md 基本合规(n=30、CI、含热缓存不利结果),仅需去营销化措辞微调。 -- 修改时注意:中英同步(checklist 要求);结论数字必须能在本页表中找到。 - -## 全项目设计与实现分析 - -用户要求通读整个仓库的设计与实现。产出:分层结构 + Attempt 时序两张图,加一份 P0/P1/P2 问题清单。 - -核心判断(供后续复用): -- 三条贯穿性不变量:定义/执行分离;请求-决策-事实分离(Requested/Rewritten/Placed/Completed);保证必须来自实际边界(EnforcementPlanLevel + finalize 里 missing_dimensions 改判)。 -- 唯一生命周期所有者是 `Session`:`transition()` 拒绝 terminal,终态只由 `complete()` 在 teardown 之后 `finish()`。 -- 边界强度分层:VM+smoltcp 为 non-bypassable(fail closed),host/container 显式代理为 cooperative,文档与 `interception.rs` 都承认。 -- 已核实 P0:`pvisor-daemon/src/daemon/mod.rs:4` 声明 `mod e2b;` 但无源文件(api.rs:48 引用);`pvisor-shim/src/vm.rs:56` 给 `filesystem()` 传 1<<29,而 builder.rs:339 要求 shm_size==0;`pvisor-replay` managed 路径写 TOML 却走 `run --spec`(run.rs 要求 JSON)。 -- P1 结构性问题:CLI 是"第一方特权前端"(用 doc(hidden) 的 RunRecord、直接 job.write() 改 checkpoint ledger,绕过 RuntimeJobService 的 lease/target 栅栏);JobCommand 直接复用 clap Args 作 wire DTO;journal 每条事件 sync_all + 单文件无分段 + 全量扫描重建索引;daemon GET 取写锁且 inspect 内做 HTTP probe,supervisor 单线程;快照 version=1 + deny_unknown_fields 使跨版本恢复不可能。 -- 工程亮点:`pvisor-vm/tests/api_contract.rs` 用 syn 强制 api.rs 无 cfg/无 impl/无默认方法;`repository_boundary` 禁 krun 依赖;semspec 人在环审批(摘要绑定 + STALE);documentation_json 测试要求文档样例能被产品 reader 读回。 -- 本次未能运行 cargo/nextest(会话内 Bash/Grep 持续 Connection lost),所有编译失败结论均为静态阅读;行数为抽样估算。 diff --git a/.workbuddy/memory/2026-10-18.md b/.workbuddy/memory/2026-10-18.md deleted file mode 100644 index cf0c7213..00000000 --- a/.workbuddy/memory/2026-10-18.md +++ /dev/null @@ -1,35 +0,0 @@ -# 2026-10-18 - -## Benchmark 文档去进攻性修订(已落地) - -承接 2026-10-17 的 review,完成以下修改(数字均只引用本页已有表格,未动数据): - -- `docs/src/{zh,en}/benchmarks/filesystem.md`:恢复固定四节顺序(主要结论→Motivation→实验设计→数据);重写结论节——首句给 Ready 绝对水位(2.63–111.88 ms)回答标题;四条 bullet 场景化、不点名竞品(原"短于 Firecracker/QEMU""接近 Docker"已移除);新增 640 MiB 超时短板 bullet;新增"需求→选型含义"表(对齐 startup/index 的惯例)。 -- `docs/src/{zh,en}/benchmarks/lazy-image-startup.md`:结论节 Docker 点名改为中性表述("预先完整拉取的路径")。 -- `docs/src/{zh,en}/benchmarks/index.md`:标题改为"pVisor 适合哪些场景,各自代价是多少?" / "Which workloads fit pVisor, and at what cost?"。导航(docs/zensical.{zh,en}.toml)用固定标签,不受 H1 改动影响。 - -## 结论层压缩与边界修正(第二轮 review) - -用户复审后三条准确性修正 + 两处减法,已全部落实(中英同步):(1) 删除"超过 128 MiB"外推写法,改为"640 MiB 超时、其他规模另测";(2) "写回不能改善"→"耗时接近,未观察到明显收益";(3) 惰性镜像恢复点名 Docker(差异含容器/VM 之别,模糊化误导归因)。减法:filesystem 结论层去掉数字范围与选型表,主句收成一句 + 三条无数字短条目;两章数据导读删掉目录式链接串联,各留一句解释。行文约定已沉淀到 .workbuddy/memory/MEMORY.md。 - -## lazy-image-startup.md Motivation 重写(与 filesystem 同模式) - -按用户要求对惰性镜像章做同样处理:标题"为何需要惰性镜像"→"短任务的环境准备要等多久",正文改为两个选型问题(首次使用省多少下载/等待;缓存复用后开销多少);机制句"按访问需要获取文件,让环境准备随任务推进"下移至"实验数据和分析"章首,改写为三组数据的读者导引(#application-comparison / #stage-comparison / #preparation 锚点链接)。中英双版同步。已排查其余章节(startup/network/density/supervision-cost/agent-tasks/vm-memory),Motivation 均已是用户场景出发,无需改动。 - -## filesystem.md Motivation 重写(用户视角) - -用户指出 Motivation"为何需要文件系统缓存与写回"是技术出发点而非用户出发点。已重写为"选择执行模式前要回答什么"(三个问题:启动等多久、任务到产物落盘等多久、大工作集/并发能否完成),机制性表述(缓存与写入合并的目的)移到"实验数据和分析"章首,改写为四组数据的读者导引(含小节锚点链接)。中英双版同步。惯例:Motivation 一律从用户场景与选型问题出发,技术机制归属数据/分析章节。 - -## filesystem.md 小写合并节的基线提升 - -用户指出"小写合并与同步边界"节把 Docker/Firecracker 等基线折叠进 details 不合理(选型页正文需要参照)。原设计意图是正文只回答"写回开/关"的内部 A/B。已将密集小写与逐次同步两个负载的完整九配置对照提升到正文表格(数据原样取自折叠区表格),并在解读句中点名同批参照(数据节允许点名);折叠区保留其余机制明细。中英双版同步。 - -## filesystem.md 参照物补全(第二轮) - -用户要求"修复类似问题,报告要让人能读懂、有参照物"。排查结论: -- "工作集与并发边界"节正文原本只有超时失败、无任何水位数据 → 从 `docs/overrides/assets/benchmarks/data/filesystem/layered-references/filesystem-layered-references-levels.csv`(sum_three_rounds, completed_ns, R01/R02)提取 128 MiB 下九配置中位数,新增正文对照表(单位 s,如 VM 41.545/15.751、VM+wb 4.195/2.073、Docker 2.822/1.550、QEMU q35 2.566/1.685)。 -- "启动等待的取值范围"节原本整节折叠 → 把含四种配置中位数的摘要句提到折叠外。 -- 全章节扫描:network/density/supervision-cost/agent-tasks/startup/lazy-image/vm-memory 正文表格均自带基线,无同类问题。 -- 注意:两版 filesystem.md 的下载链接和图链接在会话期间被外部更新过(PDF→SVG、裸文件名→overrides 完整路径),编辑前需重读文件。 - -经验:benchmark 用户页规范在 benchmark/README.md#structure 与 #checklist——结论不点名对照项目(名称/版本/数据放数据节)、首句必须直接回答标题、短板上浮、中英同步。 diff --git a/AGENTS.md b/AGENTS.md index 9abc0c3d..3b6a95ed 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,7 +57,7 @@ this boundary. Any work under `benchmark/`, `docs/src/*/benchmarks/` or `docs/src/assets/benchmarks/` must follow `benchmark/README.md`: find the benchmark's registry entry before measuring or writing, keep each user page in -the order conclusions, motivation, experiment design, data and analysis, and +the order Motivation, experiment design, data and analysis (three sections), and keep engineering A/B and diagnostic results out of user pages. ## Test command diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92f50641..71fbca8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to PolicyVisor Thanks for helping. This page is the short version; the full guide is -[community/contributing](https://deeplink-org.github.io/pvisor/zh/community/contributing/). +[community/contributing](https://deeplink-org.github.io/pvisor/en/community/contributing/). ## Before you start @@ -22,7 +22,7 @@ just lint # clippy and ruff just docs-build # build and check the documentation site ``` -See [development](https://deeplink-org.github.io/pvisor/zh/community/development/) +See [development](https://deeplink-org.github.io/pvisor/en/community/development/) for platform setup (FUSE/macFUSE, KVM/HVF, OCI runtimes). ## Semantic specifications @@ -37,7 +37,7 @@ an approval: snapshots are human-only maintainer actions. Run `just cases --suite stage` for the STAGE domain and `just semspec lint docs/src/zh/cases` for the -specifications. Details: [testing](https://deeplink-org.github.io/pvisor/zh/community/testing/). +specifications. Details: [testing](https://deeplink-org.github.io/pvisor/en/community/testing/). ## Pull requests diff --git a/README.md b/README.md index 4f992e8f..81e717e3 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Cross-node placement, workflows and retries belong to external orchestrators such as Kubernetes or Ray, not a pVisor Cluster control plane. For the four levels, where pVisor places its bet, and the status of L2/L3, see the -[trust ladder](https://deeplink-org.github.io/pvisor/en/why/trust-ladder/). +[trust ladder](https://deeplink-org.github.io/pvisor/en/why/#trust-ladder). ## Scope @@ -94,7 +94,7 @@ controls, with platform-dependent container/VM support. See [capabilities and ev ## Documentation -- [Start here](https://deeplink-org.github.io/pvisor/en/start/) — the path from install to a reviewed run +- [Start here](https://deeplink-org.github.io/pvisor/en/start/installation/) — platform requirements and installation - [Your first run](https://deeplink-org.github.io/pvisor/en/start/first-run/) — the run-review-apply loop - [Why pVisor](https://deeplink-org.github.io/pvisor/en/why/) — vision, trust ladder, use cases, and comparisons - [Capabilities and evidence](https://deeplink-org.github.io/pvisor/en/concepts/capabilities-and-evidence/) — how far a guarantee goes @@ -103,7 +103,7 @@ controls, with platform-dependent container/VM support. See [capabilities and ev - [Design and research](https://deeplink-org.github.io/pvisor/en/design/) — architecture, isolation, and research directions - [Experimental features](docs/src/en/design/experimental/index.md) — proposed capabilities, implementation stages, and validation gates - [Community](https://deeplink-org.github.io/pvisor/en/community/) — contributing, testing, and roadmap -- [中文文档](https://deeplink-org.github.io/pvisor/zh/start/) +- [中文文档](https://deeplink-org.github.io/pvisor/zh/start/first-run/) Security issues: see [SECURITY.md](SECURITY.md). Contributions: see [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/benchmark.new/README.md b/benchmark.new/README.md index 6492226c..c3ca4290 100644 --- a/benchmark.new/README.md +++ b/benchmark.new/README.md @@ -142,7 +142,7 @@ python3 benchmark.new/docs.py check python3 benchmark.new/docs.py publish "$batch" ``` -`python3 benchmark.new/measurement_coverage.py` 更新 14 个用户页的复测范围清单。没有匹配负载的页面保留历史数字并明确标识。 +`python3 benchmark.new/measurement_coverage.py` 更新 `docs.json` 登记的中英文 benchmark 用户页的复测范围清单。没有匹配负载的页面保留历史数字并明确标识。 `check` 检查文章覆盖、动态 JSON 引用、表结构、未执行命令与 CSV 来源。 公开的新表还必须逐格等于各条件最新 CSV 的展示值,样本数和计时范围不匹配会阻止构建。 @@ -150,8 +150,8 @@ python3 benchmark.new/docs.py publish "$batch" 仅向共享位置发布白名单内的完整精度 CSV,更新构建所需展示 JSON 与必要用户实验的 provenance,原 MD 无需改写。 必要 provenance 摘要统一保存在 `docs/overrides/assets/benchmarks/`,中英文共用一份; 保留批次、计时口径、运行配置、输入/二进制与证据摘要。完整 manifest、逐文件 harness -清单、宿主路径和软件包收据留在批次 `.data/`。启动仅发布文档引用的 Ready / Exit -两张 JSON 表,单行复测保留其他条件的来源配置。 +清单、宿主路径和软件包收据留在批次 `.data/`。启动页引用 Ready JSON 表;完整 +Ready / Exit 指标保留在统计 CSV 中,单行复测保留其他条件的来源配置。 发布器验证 `metric_scope` 与绑定声明的负载配置;中位数与标准差同一行,批次名称放在来源记录,不挤入数值表。 没有 live binding 的条件会拒绝发布;工程 A/B 不写入用户表。filesystem 的历史 hyperfine 结果 保留在本地归档,其用户表、下载和发布绑定已删除;新 Python 时钟数据需单独登记文档表,必要公开 CSV 按白名单发布。改变历史表数据时需同步 @@ -182,3 +182,11 @@ python3 benchmark.new/docs.py publish "$batch" 亲和性在准备与 semspec 外层设置,manifest 记录实际选择;被测命令没有 Python 或 `taskset` 包裹。所有适配器按独立条件采样,不声称随机配对改善比例。 + +## 公开图表清理 + +`docs.py check` 拒绝未被文章、展示表或主题引用的公开 SVG。新增图表先在对应文章中引用; +`filesystem/publish_io_curves.py` 只发布当前引用的图,完整图表仍在批次 publication 中归档。 +2026-10-18 撤下的无引用 SVG 原字节保存在 `.data/docs-assets-cleanup-20261018/`, +可提交的路径、大小和 SHA-256 索引见 [清理清单](evidence/docs-assets-cleanup-20261018.json)。 +清单只覆盖这次公开图表清理,不表示其他历史原始批次已在当前 checkout 核验或完整保留。 diff --git a/benchmark.new/docs.json b/benchmark.new/docs.json index 6fd2d419..7a0bf94c 100644 --- a/benchmark.new/docs.json +++ b/benchmark.new/docs.json @@ -14,16 +14,6 @@ "tables": [], "source_csv": [] }, - { - "locale": "zh", - "page": "benchmarks/cluster-scalability.md", - "benchmark_ids": [ - "B-CLUSTER" - ], - "role": "user-facing", - "tables": [], - "source_csv": [] - }, { "locale": "zh", "page": "benchmarks/compare-rl-infra.md", @@ -70,7 +60,7 @@ { "json": "benchmarks/measurement-coverage.render.json", "kind": "coverage", - "rows": 14, + "rows": 12, "columns": [ "数据状态", "实测范围" @@ -108,16 +98,6 @@ "../../../overrides/assets/benchmarks/data/lazy/lazy-stage-comparisons.csv" ] }, - { - "locale": "zh", - "page": "benchmarks/methodology.md", - "benchmark_ids": [ - "B-METHOD" - ], - "role": "user-facing", - "tables": [], - "source_csv": [] - }, { "locale": "zh", "page": "benchmarks/network.md", @@ -175,20 +155,6 @@ ], "rows": 8, "options": {} - }, - { - "json": "benchmarks/startup-timing.exit.render.json", - "kind": "published", - "columns": [ - "N", - "Exit 中位数 ms", - "Exit 均值 ms", - "Exit 标准差 ms", - "Exit 最小 ms", - "Exit 最大 ms" - ], - "rows": 8, - "options": {} } ], "source_csv": [ @@ -219,7 +185,7 @@ }, { "locale": "zh", - "page": "design/vm-startup-performance-analysis.md", + "page": "lab-notes/vm-startup-performance-analysis.md", "benchmark_ids": [ "B-STARTUP-ENG", "B-KERNEL-ENG", @@ -231,7 +197,7 @@ }, { "locale": "zh", - "page": "design/vm-memory-performance-analysis.md", + "page": "lab-notes/vm-memory-performance-analysis.md", "benchmark_ids": [ "B-MEMORY-SCALE", "B-MEMORY-DIAG", @@ -243,7 +209,7 @@ }, { "locale": "zh", - "page": "design/filesystem-performance-analysis.md", + "page": "lab-notes/filesystem-performance-analysis.md", "benchmark_ids": [ "B-FS-ENG", "B-FS-DIAG" @@ -254,7 +220,7 @@ }, { "locale": "zh", - "page": "design/filesystem-io-performance-analysis.md", + "page": "lab-notes/filesystem-io-performance-analysis.md", "benchmark_ids": [ "B-FS-ENG", "B-FS-DIAG" @@ -265,7 +231,7 @@ }, { "locale": "zh", - "page": "design/agent-task-performance-analysis.md", + "page": "lab-notes/agent-task-performance-analysis.md", "benchmark_ids": [ "B-AGENT-TASK" ], @@ -275,27 +241,7 @@ }, { "locale": "zh", - "page": "design/cluster-performance-analysis.md", - "benchmark_ids": [ - "B-CLUSTER" - ], - "role": "engineering evidence", - "tables": [], - "source_csv": [] - }, - { - "locale": "zh", - "page": "design/cluster-benchmark-plan.md", - "benchmark_ids": [ - "B-CLUSTER" - ], - "role": "engineering evidence", - "tables": [], - "source_csv": [] - }, - { - "locale": "zh", - "page": "design/benchmark-methodology-evidence.md", + "page": "lab-notes/benchmark-methodology-evidence.md", "benchmark_ids": [ "B-METHOD" ], @@ -314,16 +260,6 @@ "tables": [], "source_csv": [] }, - { - "locale": "en", - "page": "benchmarks/cluster-scalability.md", - "benchmark_ids": [ - "B-CLUSTER" - ], - "role": "user-facing", - "tables": [], - "source_csv": [] - }, { "locale": "en", "page": "benchmarks/compare-rl-infra.md", @@ -370,7 +306,7 @@ { "json": "benchmarks/measurement-coverage.render.json", "kind": "coverage", - "rows": 14, + "rows": 12, "columns": [ "Data status", "Measured scope" @@ -408,16 +344,6 @@ "../../../overrides/assets/benchmarks/data/lazy/lazy-stage-comparisons.csv" ] }, - { - "locale": "en", - "page": "benchmarks/methodology.md", - "benchmark_ids": [ - "B-METHOD" - ], - "role": "user-facing", - "tables": [], - "source_csv": [] - }, { "locale": "en", "page": "benchmarks/network.md", @@ -475,20 +401,6 @@ ], "rows": 8, "options": {} - }, - { - "json": "benchmarks/startup-timing.exit.render.json", - "kind": "published", - "columns": [ - "N", - "Exit median ms", - "Exit mean ms", - "Exit SD ms", - "Exit min ms", - "Exit max ms" - ], - "rows": 8, - "options": {} } ], "source_csv": [ @@ -519,7 +431,7 @@ }, { "locale": "en", - "page": "design/vm-startup-performance-analysis.md", + "page": "lab-notes/vm-startup-performance-analysis.md", "benchmark_ids": [ "B-STARTUP-ENG", "B-KERNEL-ENG", @@ -531,7 +443,7 @@ }, { "locale": "en", - "page": "design/vm-memory-performance-analysis.md", + "page": "lab-notes/vm-memory-performance-analysis.md", "benchmark_ids": [ "B-MEMORY-SCALE", "B-MEMORY-DIAG", @@ -543,7 +455,7 @@ }, { "locale": "en", - "page": "design/filesystem-performance-analysis.md", + "page": "lab-notes/filesystem-performance-analysis.md", "benchmark_ids": [ "B-FS-ENG", "B-FS-DIAG" @@ -554,7 +466,7 @@ }, { "locale": "en", - "page": "design/filesystem-io-performance-analysis.md", + "page": "lab-notes/filesystem-io-performance-analysis.md", "benchmark_ids": [ "B-FS-ENG", "B-FS-DIAG" @@ -565,7 +477,7 @@ }, { "locale": "en", - "page": "design/agent-task-performance-analysis.md", + "page": "lab-notes/agent-task-performance-analysis.md", "benchmark_ids": [ "B-AGENT-TASK" ], @@ -575,27 +487,7 @@ }, { "locale": "en", - "page": "design/cluster-performance-analysis.md", - "benchmark_ids": [ - "B-CLUSTER" - ], - "role": "engineering evidence", - "tables": [], - "source_csv": [] - }, - { - "locale": "en", - "page": "design/cluster-benchmark-plan.md", - "benchmark_ids": [ - "B-CLUSTER" - ], - "role": "engineering evidence", - "tables": [], - "source_csv": [] - }, - { - "locale": "en", - "page": "design/benchmark-methodology-evidence.md", + "page": "lab-notes/benchmark-methodology-evidence.md", "benchmark_ids": [ "B-METHOD" ], diff --git a/benchmark.new/evidence/docs-assets-cleanup-20261018.json b/benchmark.new/evidence/docs-assets-cleanup-20261018.json new file mode 100644 index 00000000..8ea2c583 --- /dev/null +++ b/benchmark.new/evidence/docs-assets-cleanup-20261018.json @@ -0,0 +1,126 @@ +{ + "schema": 1, + "scope": "Unused published SVG copies only; raw experiment evidence unchanged", + "files": [ + { + "path": "docs/overrides/assets/benchmarks/cluster-scalability-20261005/execution.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/cluster-scalability-20261005/execution.svg", + "bytes": 35789, + "sha256": "4437cef0333dc3857b5f92b5ffbfbd9da83039b313a2076bf99bd85bb38dec37", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/confirm-phase-means-selected-blocks.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/confirm-phase-means-selected-blocks.svg", + "bytes": 44992, + "sha256": "8aaa88a020272428fc2f555d0725b6d8d23d6558663a9f0f13d3235bc5701397", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/confirm-smallfiles-smallfiles.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/confirm-smallfiles-smallfiles.svg", + "bytes": 62062, + "sha256": "85c6598e1e8903c2f9f4a76762f05d86537155b06e6eb50b416cfd7e4ac56588", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/confirm-sync-stream.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/confirm-sync-stream.svg", + "bytes": 60141, + "sha256": "c5e8916f8cf2f7c3285de79df730cd15f777b02294caa498930268016521bab1", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/memory-batch_kib-sampled_memory_current_peak_bytes-4.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/memory-batch_kib-sampled_memory_current_peak_bytes-4.svg", + "bytes": 16336, + "sha256": "1d9424f871cc77b590e720bdf4c4f0036ceff1e978c218c9a7449b3c9ccbab48", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/memory-capacity_mib-sampled_memory_current_peak_bytes-1.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/memory-capacity_mib-sampled_memory_current_peak_bytes-1.svg", + "bytes": 17365, + "sha256": "25dfc693b265f8d9838ab3ab257755fb581ced847c1c88f8983abb23008c0e0a", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/memory-delay_us-sampled_memory_current_peak_bytes-3.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/memory-delay_us-sampled_memory_current_peak_bytes-3.svg", + "bytes": 18365, + "sha256": "3ac1250f3b96e06a9a77374d7aeec78c6e0fba3fd855f5df619ed2b73e5a9556", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/parameters-block-stream.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/parameters-block-stream.svg", + "bytes": 86357, + "sha256": "6bd800edb4bb2a12573ef957c8267b80d3bb8beb14a9fca560b092fbd925f38e", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/pressure-stream.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/pressure-stream.svg", + "bytes": 171834, + "sha256": "7d8c3b219df9914445dcd29a3b38efcf669e13f7326c3df398e1e54f21b8c6d3", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/readset-read.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/readset-read.svg", + "bytes": 108153, + "sha256": "e8f26ecea197b23320bc8f3663bfe48c1af6b909ae96d99b981c99d4e6401d5c", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/smallfiles-smallfiles.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/smallfiles-smallfiles.svg", + "bytes": 61036, + "sha256": "45874d52812750e6b1449634448915efaa335df705b521f4c857339a7c5f1b79", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-io/sync-stream.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-io/sync-stream.svg", + "bytes": 58496, + "sha256": "b1920126d9dd77348bac05cca86efa3ae2f5b75384340e30d1ab30dbe5d76bab", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/filesystem-service-20261005/lazy-vm.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/filesystem-service-20261005/lazy-vm.svg", + "bytes": 20323, + "sha256": "c07ed4132d6337b0c5f6365942053601ec0510b2e59e9716a3c2513bdf60b27c", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/full-ubuntu-20261004/ubuntu-startup.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/full-ubuntu-20261004/ubuntu-startup.svg", + "bytes": 66182, + "sha256": "5484de021520cda1db71c05c346d36eb9d53a698d66594eeab1fda0f33b824f3", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + }, + { + "path": "docs/overrides/assets/benchmarks/full-ubuntu-20261004/ubuntu-workflows.svg", + "archive_path": "benchmark.new/.data/docs-assets-cleanup-20261018/full-ubuntu-20261004/ubuntu-workflows.svg", + "bytes": 92472, + "sha256": "29c83deb68d952c322e23b79d871d49654fbbb3b300d776d4dcedd65e7c8a7d8", + "retention": "local archive; original also retained in Git history", + "reason": "not referenced by tracked page, table, theme or configuration" + } + ] +} diff --git a/benchmark.new/filesystem/README.md b/benchmark.new/filesystem/README.md index 436e3d65..4763d508 100644 --- a/benchmark.new/filesystem/README.md +++ b/benchmark.new/filesystem/README.md @@ -96,7 +96,7 @@ host只隐藏已验证的OverlayFS内部标记,不放过意外应用文件。 逐case guest脏页峰值、队列占用与精确操作尾延迟仍未插桩。 下述旧入口和来源保持独立,已有数据不重命名为新协议结果。 -首轮浅测结果见[分层工程分析](../../docs/src/zh/design/filesystem-io-performance-analysis.md#workload-v2-results): +首轮浅测结果见[分层工程分析](../../docs/src/zh/lab-notes/filesystem-io-performance-analysis.md#workload-v2-results): 19项、114个新VM、342条轮记录全部通过;独立N1计数另用16个VM。 这批数据只比较同一固件的guest WB关/开,不代表0049相对0048的增量或跨后端排名。 @@ -134,6 +134,7 @@ guest 内连续五次 reopen、内部三轮,展示吞吐、READ 消除与容 主输入批次的`publication//`,PDF继续保留在原分析目录;CLI入口没有图时 仅做本地归档。组合I/O曲线以`--shape`批次作为归档主目录。归档清单完整描述材料, `public_outputs`仅列实际公开的图;阶段计时、来源校验和SVG/PDF完整性检查均不减少。 +I/O 曲线发布器只复制当前文章或主题引用的 SVG;未引用的图仍保留在本地 publication。 这些结果不写入下述原生工具表或跨运行时用户排名。 ## 原生 metadata/read 表 diff --git a/benchmark.new/filesystem/publish_io_curves.py b/benchmark.new/filesystem/publish_io_curves.py index 186f6cff..133bc427 100644 --- a/benchmark.new/filesystem/publish_io_curves.py +++ b/benchmark.new/filesystem/publish_io_curves.py @@ -18,6 +18,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from curves_analysis import describe, seed_for +from public_assets import referenced_svg_paths from publication_archive import archive_targets, preflight_archive, write_archive REPO = Path(__file__).resolve().parents[2] @@ -546,6 +547,7 @@ def usage(resource): "read-diagnostic", ) cohorts.append(provenance) + referenced_figures = referenced_svg_paths(REPO) manifest = dict( schema=1, benchmark_ids=["B-FS-ENG", "B-FS-DIAG"], @@ -560,7 +562,7 @@ def usage(resource): public_outputs={ str(Path("docs/overrides/assets/benchmarks/filesystem-io") / name): spec["sha256"] for name, spec in files.items() - if name.endswith(".svg") + if name.endswith(".svg") and f"filesystem-io/{name}" in referenced_figures }, precision="CSV bytes archived unchanged; only SVGs public; local analysis PDFs retained and verified; no raw_rows.csv publication or numeric formatting", graph_methods="Frozen analysis source hashes and per-cohort statistical scope retained; N5 exploration and independent N30 confirmation remain separate", @@ -593,7 +595,10 @@ def main(): preflight_archive(archives) targets = [] for name, spec in files.items(): - if not name.endswith(".svg"): + if ( + str(Path("docs/overrides/assets/benchmarks/filesystem-io") / name) + not in manifest["public_outputs"] + ): continue destinations = [REPO / "docs/overrides/assets/benchmarks/filesystem-io" / name] for target in destinations: diff --git a/benchmark.new/filesystem/test_filesystem_publication_layout.py b/benchmark.new/filesystem/test_filesystem_publication_layout.py index fb9b6a4b..c998c6b6 100644 --- a/benchmark.new/filesystem/test_filesystem_publication_layout.py +++ b/benchmark.new/filesystem/test_filesystem_publication_layout.py @@ -50,7 +50,7 @@ def test_private_archive_is_readonly_when_checked_and_refuses_changed_bytes(self def test_private_archive_rejects_a_symlinked_publication_directory(self): with tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() batch, outside = root / "batch", root / "outside" batch.mkdir() outside.mkdir() @@ -62,7 +62,7 @@ def test_private_archive_rejects_a_symlinked_publication_directory(self): def test_collected_provenance_omits_pdfs_but_still_requires_local_pdf_bytes(self): with tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() timing, diagnostic = root / "timing", root / "diagnostic" analysis, times = timing / "analysis", timing / "analysis-times" analysis.mkdir(parents=True) @@ -194,7 +194,7 @@ def test_writeback_publishers_share_csvs_and_exclude_pdf_destinations(self): (TUNING.BASE, "filesystem-guest-writeback-tuning"), ): with self.subTest(namespace=namespace), tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() name = namespace + "-levels.csv" files = { name: {"data": b"full_precision\n1.23456789\n"}, @@ -214,7 +214,7 @@ def test_writeback_entrypoints_archive_metadata_and_publish_only_their_svg(self) (TUNING, TUNING.BASE, "filesystem-guest-writeback-tuning"), ): with self.subTest(namespace=namespace), tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() batch = root / "input" batch.mkdir() files = { @@ -258,7 +258,7 @@ def test_writeback_entrypoints_archive_metadata_and_publish_only_their_svg(self) def test_cli_publication_archives_tables_without_public_downloads(self): with tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() files = { CLI.PREFIX + suffix + ".csv": b"value\n1.23456789\n" for suffix in ("-levels", "-comparisons", "-environments", "-counters") @@ -284,11 +284,12 @@ def test_cli_publication_archives_tables_without_public_downloads(self): def test_io_publication_archives_csv_and_provenance_and_publishes_only_svg(self): with tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() table = "filesystem-io-shape.csv" files = { table: {"data": b"value\n1.23456789\n", "sha256": ""}, "curve.svg": {"data": b"", "sha256": ""}, + "unused.svg": {"data": b"archived", "sha256": ""}, } import hashlib @@ -308,7 +309,21 @@ def test_io_publication_archives_csv_and_provenance_and_publishes_only_svg(self) ] with ( patch.object(IO, "REPO", root), - patch.object(IO, "collect", return_value=(files, {}, b"{}")), + patch.object( + IO, + "collect", + return_value=( + files, + { + "public_outputs": { + "docs/overrides/assets/benchmarks/filesystem-io/curve.svg": files[ + "curve.svg" + ]["sha256"] + } + }, + b"{}", + ), + ), patch.object(sys, "argv", arguments), contextlib.redirect_stdout(io.StringIO()), ): @@ -321,6 +336,10 @@ def test_io_publication_archives_csv_and_provenance_and_publishes_only_svg(self) files[table]["data"], ) self.assertEqual(len(list(root.rglob("*.csv"))), 1) + self.assertEqual( + (root / "shape/publication/filesystem-io/unused.svg").read_bytes(), + files["unused.svg"]["data"], + ) self.assertFalse((root / "docs/src").exists()) self.assertEqual( [p.suffix for p in (root / "docs").rglob("*") if p.is_file()], [".svg"] @@ -329,7 +348,7 @@ def test_io_publication_archives_csv_and_provenance_and_publishes_only_svg(self) def test_workload_publication_keeps_tables_pdfs_and_provenance_local(self): with tempfile.TemporaryDirectory() as temporary: - root = Path(temporary) + root = Path(temporary).resolve() batch = root / ".data/synthetic" analysis = batch / "analysis" analysis.mkdir(parents=True) diff --git a/benchmark.new/measurement_coverage.py b/benchmark.new/measurement_coverage.py index f608297d..6e652f22 100644 --- a/benchmark.new/measurement_coverage.py +++ b/benchmark.new/measurement_coverage.py @@ -159,9 +159,9 @@ def coverage(): page = row["page"].removeprefix("benchmarks/") if page == "startup.md": description = ( - "同次启动 Ready / Exit;完整命令另列" + "启动到首条校验输出;不报告退出时间" if locale == "zh" - else "Same-launch Ready / Exit; whole-command time is separate" + else "Launch to first checked output; exit time is not reported" ) elif page == "replay-fidelity.md": description = ( diff --git a/benchmark.new/memory/README.md b/benchmark.new/memory/README.md index ce76eee1..38938280 100644 --- a/benchmark.new/memory/README.md +++ b/benchmark.new/memory/README.md @@ -303,7 +303,7 @@ frozen supporting harnesses and the hashes of monitor, PSS and guard observation ## Published curves and archived history -The [bilingual technical analysis](../../docs/src/zh/design/vm-memory-performance-analysis.md) +The [bilingual technical analysis](../../docs/src/zh/lab-notes/vm-memory-performance-analysis.md) uses only the complete `q8` and `l4` preflights. It publishes idle charged-memory and PSS curves, with readback and CPU observations; post-write curves remain local. The public SVG files are byte-identical copies of each cohort's diff --git a/benchmark.new/public_assets.py b/benchmark.new/public_assets.py index 0f88dcd5..25c73860 100644 --- a/benchmark.new/public_assets.py +++ b/benchmark.new/public_assets.py @@ -4,6 +4,7 @@ Only data needed by current publication contracts is exported to the site. """ +import re from pathlib import Path PUBLIC_CSV = frozenset( @@ -100,6 +101,24 @@ def csv_path(repository, filename, locale=None): return Path(repository) / "docs/overrides/assets/benchmarks/data" / group / filename +def referenced_svg_paths(repository): + """Return benchmark SVG paths referenced by articles, tables or theme sources. + + Paths are relative to the shared benchmark asset directory. Local evidence + and generated site files do not keep an unused public download alive. + """ + docs = Path(repository) / "docs" + references = set() + for root in (docs / "src", docs / "overrides"): + for path in root.rglob("*"): + if ".data" in path.parts or path.suffix not in {".md", ".json", ".html", ".css", ".js"}: + continue + references.update( + re.findall(r"assets/benchmarks/([^\s\"'<>)]*\.svg)", path.read_text()) + ) + return references + + def check_public_assets(repository): """Reject accidental publication of intermediate or duplicate evidence. @@ -108,6 +127,10 @@ def check_public_assets(repository): """ repository = Path(repository) assets = repository / "docs/overrides/assets/benchmarks" + figures = referenced_svg_paths(repository) + for path in assets.rglob("*.svg"): + if path.relative_to(assets).as_posix() not in figures: + raise ValueError(f"unreferenced public SVG: {path}") for path in assets.rglob("*.csv"): if not is_public_csv(path.name) or path != csv_path(repository, path.name): raise ValueError(f"unneeded or duplicate public CSV: {path}") diff --git a/benchmark.new/startup/README.md b/benchmark.new/startup/README.md index 5b79abb0..4a7d200c 100644 --- a/benchmark.new/startup/README.md +++ b/benchmark.new/startup/README.md @@ -43,9 +43,9 @@ pVisor 默认使用 `target/release/pvisor`,可用 `--binary PATH` 指定。 - `hooks.py`:重置每次输入,校验输出、canary、Run Bundle 和只读 stage。 - `timing.py`:共享事件时钟、采样和统计;各 `*_timing.py` 固定后端。 - `audit.py`:复算当前批次的配对样本并校验逐次证据。 -- `publish.py`:将成功批次发布为双语 Ready / Exit 表。 +- `publish.py`:将成功批次发布为双语 Ready / Exit 结果 JSON。 -文档只保存 Ready / Exit 两张结果 JSON;来源摘要共用 +公开 CSV 同时保留 Ready 与 Exit 两列;用户页只引用 Ready 表,因为退出时间不改变读者的选型。来源摘要共用 `docs/overrides/assets/benchmarks/startup-timing.provenance.json`,单行复测保留其他 条件的批次和配置。完整 manifest、输入清单与内核收据留在试验 `.data/`。 diff --git a/benchmark.new/tests/test_docs.py b/benchmark.new/tests/test_docs.py index ce972188..931544e6 100644 --- a/benchmark.new/tests/test_docs.py +++ b/benchmark.new/tests/test_docs.py @@ -20,8 +20,8 @@ class DocumentationTests(unittest.TestCase): def test_all_benchmark_articles_and_bound_data_are_consistent(self): pages, tables = DOCS.check_inventory() - self.assertGreaterEqual(pages, 42) - self.assertEqual(tables, 8) + self.assertEqual(pages, 36) + self.assertEqual(tables, 6) manifest = json.loads((ROOT / "docs.json").read_text()) pairs = {} for page in manifest["pages"]: diff --git a/benchmark.new/tests/test_public_assets.py b/benchmark.new/tests/test_public_assets.py index c909d359..9dd3e29c 100644 --- a/benchmark.new/tests/test_public_assets.py +++ b/benchmark.new/tests/test_public_assets.py @@ -11,6 +11,25 @@ class PublicAssetTests(unittest.TestCase): + def test_svg_requires_a_current_page_reference_with_matching_directory(self): + with tempfile.TemporaryDirectory() as tmp: + repo = Path(tmp) + figure = repo / "docs/overrides/assets/benchmarks/study/chart.svg" + figure.parent.mkdir(parents=True) + figure.write_text("") + article = repo / "docs/src/en/lab-notes/result.md" + article.parent.mkdir(parents=True) + article.write_text("![Plot](../assets/benchmarks/other/chart.svg)") + with self.assertRaisesRegex(ValueError, "unreferenced public SVG"): + check_public_assets(repo) + article.write_text("![Plot](../assets/benchmarks/study/chart.svg)") + check_public_assets(repo) + archive = article.parent / ".data" + archive.mkdir() + article.rename(archive / article.name) + with self.assertRaisesRegex(ValueError, "unreferenced public SVG"): + check_public_assets(repo) + def test_numeric_csv_has_one_location_across_languages(self): repo = Path("/repository") a = csv_path(repo, "filesystem-layered-references-levels.csv", "zh") diff --git a/benchmark/README.md b/benchmark/README.md index 85f4a49d..a510747d 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -26,57 +26,51 @@ ## 每篇 benchmark 的结构 {#structure} -用户文档中的每篇 benchmark 固定为以下四节,顺序不变: +用户文档中的每篇 benchmark 固定为以下三节,顺序不变: ```markdown # 标题:用户关心的问题,不是被测组件名 -## 主要结论 {#conclusions} -一句话说明 pVisor 的收益,再用两到三条简短结论支撑。 - ## Motivation {#motivation} -用户为什么需要知道这件事:哪种决策依赖它,不知道会付出什么代价。 +第一段给定性判断,第一句直接回答标题。第二段给定量支撑:只放支撑该判断的数字。 ## 实验设计 {#interpretation} -为了回答上面的问题,测什么、对照什么、怎样控制变量、什么算有效样本。 +第一段用三句话说明用什么衡量:测量哪个量、把它叫什么;这个量代表系统的什么能力;这个量往哪个方向变化意味着什么。不写测量步骤。 +后续段落说明如何测量:环境、对照、控制变量、采样、排除规则、设计不能回答什么。 ## 实验数据和分析 {#results} -支撑结论的数据表或图,以及对数据的解读和适用范围。 +支撑判断的数据表或图,以及对数据的解读和适用范围。 ``` 各节的要求: -- **主要结论** - - 第一句直接回答标题的问题,读者只看这一句也能做决定。 - - 按“总判断 → 支撑判断 → 定量证据”分层。总判断说明 pVisor 的技术选择及用户价值;两到三条支撑判断各表达一个完整观点;数字紧随对应观点或放在数据节。不要把指标或对照项目平铺成结论列表。 - - 结论中的每个数字都必须出现在本页"实验数据和分析"的表或图中。 - - 写清楚适用条件(平台、配置、负载类型),但不在结论里堆批次、日期、制品哈希。 - - 有短板就写短板。"pVisor 在 X 上更慢"也是结论。 - **Motivation** + - 第一段是定性判断:这个页面回答什么问题,读者该据此做什么选择。首句直接回答标题,读者只看这一句也能做决定。 + - 第二段是定量支撑:给出支撑第一段的数字。结论中的每个数字都必须出现在本页"实验数据和分析"的表或图中。 - 写用户的决策,不写我们的工程动机。"选 staged 还是 VM 前需要知道工具任务要等多久"可以;"验证路径索引优化"不可以。 - - 两到四句话。 + - 不在这一节放表格、列表或批次说明;写清楚适用条件(平台、配置、负载类型),但不堆批次、日期、制品哈希。 + - 有短板就写短板。"pVisor 在 X 上更慢"也是判断。 - **实验设计** - - 说明负载为什么能代表用户场景,对照组为什么是这几个。 + - 第一段是固定句式,不加小标题或粗体标签。第一句写"测量 X,作为 Y";第二句写"Y 是系统的什么能力";第三句写"Y 越低或越高,用户得到什么"。三句话只回答"用什么衡量",不写怎么测。 + - 后续段落说明如何测量:负载为什么能代表用户场景,对照组为什么是这几个,控制变量(硬件预算、预热和采样数、缓存状态、隔离方式、正确性校验),什么样本被拒绝,以及这个设计不能回答什么。 + - 只描述当前批次。历史批次、旧版本和它们的口径属于"实验数据和分析",不在这一节叙述。 - 使用读者能理解的任务和操作描述;benchmark 注册编号、内部 API、辅助程序与开关细节留在复现手册和证据中。 - - 列出控制变量:硬件预算、预热和采样数、缓存状态、隔离方式、正确性校验。 - - 说明什么样本被拒绝(失败、校验不通过、受干扰),失败不能当作零耗时。 - - 说明这个设计**不能**回答什么。 - **实验数据和分析** - 先放回答结论的那张表,再放补充数据。 - 每张表写明单位、统计量(P50/P95)、样本数。 - 分析要解释数据对用户意味着什么,不复述表格。 - 末尾按需提供白名单内的必要统计 CSV 和来源摘要,复现命令链接到 `benchmark/` 的 README。正文已有的静态表不默认另附下载;完整数据、原始样本与制品清单留在本地 `.data/`,不生成失效的站点下载链接。 -先写 pVisor 做了什么、带来什么收益,用具体动词和简短判断表达。对照项目的名称、版本和数据放在实验与数据节;适用条件集中说明。实测收益与预期分开,保留不利结果;多个条件同时变化时,只报告整体效果。 +先写 pVisor 做了什么、带来什么收益,用具体动词和简短判断表达。对照项目的名称、版本和数据放在实验与数据节;适用条件集中说明。实测收益与预期分开,保留不利结果;多个条件同时变化时,只报告整体效果。用户页的措辞规则和常见失败模式见 [docs/README.md § Benchmark pages](../docs/README.md#benchmark-pages)。 -篇幅:正文控制在一屏到三屏。超过时,把技术分析移到 `docs/src/*/design/*-performance-analysis.md`,用户页只保留结论和一句链接。 +篇幅:正文控制在一屏到三屏。超过时,把技术分析移到 `docs/src/*/lab-notes/*-performance-analysis.md`,用户页只保留结论和一句链接。 ## 角色 {#roles} | 角色 | 回答谁的问题 | 结果放在哪里 | 能否进入用户文档正文 | |---|---|---|---| | **user-facing** | 用户:该不该用、选哪个模式、要预留多少资源 | `docs/src/*/benchmarks/` | 能,且必须遵守[结构](#structure) | -| **engineering A/B** | 开发者:这个改动有没有让产品变好或变差 | `docs/src/*/design/*-performance-analysis.md`、PR 描述 | 不能;只有改变了用户结论时,才更新 user-facing 页的数字 | +| **engineering A/B** | 开发者:这个改动有没有让产品变好或变差 | `docs/src/*/lab-notes/*-performance-analysis.md`、PR 描述 | 不能;只有改变了用户结论时,才更新 user-facing 页的数字 | | **diagnostic** | 开发者:时间花在哪里 | 相关目录的 `.data/`、设计文档的分析节 | 不能 | 一个脚本可以同时被多个 benchmark 使用,但每次运行只服务一个 benchmark ID,报告中要记录该 ID。 @@ -117,7 +111,7 @@ Design: 负载、对照、控制变量与有效样本判据。 ### B-OVERVIEW / B-METHOD:选型总览与比较方法 {#b-overview} -- **文档:** `index.md`、`methodology.md` +- **文档:** `index.md`(选型总览与比较方法) - **角色:** user-facing(综合页) - **Motivation:** 用户需要选择主题并判断哪些数字可比较。 - **想要的结论:** 各主题的选型含义、证据范围与未测项目。 @@ -226,8 +220,8 @@ Design: 负载、对照、控制变量与有效样本判据。 ### B-FS-ENG:文件系统改动的工程 A/B {#b-fs-eng} -- **文档:** `docs/src/*/design/filesystem-performance-analysis.md`、 - `docs/src/*/design/filesystem-io-performance-analysis.md` +- **文档:** `docs/src/*/lab-notes/filesystem-performance-analysis.md`、 + `docs/src/*/lab-notes/filesystem-io-performance-analysis.md` - **角色:** engineering A/B - **Motivation:** 开发者需要判断一次文件系统改动是否让 B-FS-TOOLS 的用户结论变好,并定位时间花在哪一层(传输、OverlayCore、持久化、内容指纹)。 - **想要的结论:** "改动 X 让负载 Y 的中位数变化 Z%(95% 置信区间),其余负载未检出差异";以及"staged 与 FUSE 直通之间的差距中,持久化占 A ms,内容指纹占 B ms,路径解析占 C ms"。 @@ -355,7 +349,7 @@ Design: 负载、对照、控制变量与有效样本判据。 checkpoint 核对每轮每工具的 rootfs/workspace OPEN、READ、LOOKUP、READINDEX 和物理查询;计数含该工具进程树启动/校验,与 worker 时钟范围分别说明。 入口 `filesystem_cache_matrix.py`;原始入口/制品/准备/失败留在 `.data/`, - 工程结论进入 `design/filesystem-performance-analysis.md`,不更新跨运行时用户表。 + 工程结论进入 `lab-notes/filesystem-performance-analysis.md`,不更新跨运行时用户表。 - **普通 CLI 封存 rootfs 入口快速对照:** 同一冻结真实 CLI 与 0047 固件, 比较同一封存物理 rootfs 的普通 `--rootfs PATH` 与公开认证的 `--rootfs-base-store STORE --rootfs-base ID`;通过公开 SnapshotStore API @@ -572,13 +566,13 @@ Design: 负载、对照、控制变量与有效样本判据。 - **读队列与 journal 锁对照:** `host_read_journal_ab.py` / `host_read_journal_driver.rs`;冻结同一源码,仅撤销/保留读调度与指纹锁改动。macOS FSKit 的实际部分 copy-up 窗口中并发测只读 OPEN、已打开描述符 READ、OPENDIR,关闭日志、legacy 与 compact strict 分条件;另以共享 Core 的真实 1 GiB 原生文件指纹计算测 unrelated journal 观测,legacy/compact 独立成批。原生文件访问时间变化证明首次读已发生,开始探测时哈希线程必须仍在运行,不人工延迟。每格 3 次预热、30 个 seeded 随机配对样本,空闲对照、完整内容/观察/卸载和干扰门禁、配对 bootstrap 95% CI;不合并复制与哈希条件,不宣称冷磁盘、Linux、VM、吞吐或端到端工具收益。报告/加工 CSV 在 `benchmark/pvisor/`,原始来源和失败在 `.data/`。 -- **Linux staged 空闲调度对照:** 使用 `reference_baselines.run_trial` 的原 task timer,以冻结的 coordinator/namespace helper 随机配对同源码基线与仅修改 host dispatch 的候选,API/README 和私有测试同步更新。CPU 0,1、整父组两核 quota / 16 GiB / swap 0,Btrfs 热宿主缓存、相同空工具缓存与 Python bytecode 策略;每样本独立 user/mount/PID namespace、owned pivot_root 和 Host listener,namespace/输入准备不计时。3 warmups、30 配对轮次、完整七工具输出/Run Bundle/宿主隔离/upper 字节校验、前后输入清单与外部 0.5 s 构建/测试干扰门禁。插桩关闭、保留有效慢样本,5,000 次配对 bootstrap,分离簇不作整体排名。raw helper、冻结源码、制品和失败/中间尝试保留 `.data/`;整理 CSV 与结论仅进入 `design/filesystem-performance-analysis.md#host-idle-dispatch`。不作为 hyperfine 数据,也不与跨运行时用户批次或 macOS/VM 结果合并。 +- **Linux staged 空闲调度对照:** 使用 `reference_baselines.run_trial` 的原 task timer,以冻结的 coordinator/namespace helper 随机配对同源码基线与仅修改 host dispatch 的候选,API/README 和私有测试同步更新。CPU 0,1、整父组两核 quota / 16 GiB / swap 0,Btrfs 热宿主缓存、相同空工具缓存与 Python bytecode 策略;每样本独立 user/mount/PID namespace、owned pivot_root 和 Host listener,namespace/输入准备不计时。3 warmups、30 配对轮次、完整七工具输出/Run Bundle/宿主隔离/upper 字节校验、前后输入清单与外部 0.5 s 构建/测试干扰门禁。插桩关闭、保留有效慢样本,5,000 次配对 bootstrap,分离簇不作整体排名。raw helper、冻结源码、制品和失败/中间尝试保留 `.data/`;整理 CSV 与结论仅进入 `lab-notes/filesystem-performance-analysis.md#host-idle-dispatch`。不作为 hyperfine 数据,也不与跨运行时用户批次或 macOS/VM 结果合并。 -- **Linux VM worker 调度对照:** 同一冻结源码的三版本配对:撤销 `65e65c93`/`09bd1d59` 的优化前版本、保留当前优化与 host 修复的基线、仅修改 VM worker 调度/私有测试及 README 的候选。每版本 3 warmups、30 个随机同轮样本;独立 namespace、owned pivot_root、fresh VM/Host listener,整父组 CPU 0,1 / quota 两核 / 16 GiB / swap 0,同 B-FS-TOOLS 七工具及输入、缓存、逐字节 upper、宿主隔离与干扰门禁。使用原 reference timer,profiling 关闭;与当前基线的差异用于候选归因,优化前版本只用于同批恢复程度对照。5,000 次配对 bootstrap,分离簇不报整体排名;各候选批次独立保留,只发布通过门禁的最终制品,不合并样本。原始 helper、冻结源码、构建和诊断在 `.data/`,加工 CSV 与结果仅进入 `design/filesystem-performance-analysis.md#vm-completion-dispatch`,不重算跨运行时用户表,不外推 macOS、冷磁盘或并发吞吐。 +- **Linux VM worker 调度对照:** 同一冻结源码的三版本配对:撤销 `65e65c93`/`09bd1d59` 的优化前版本、保留当前优化与 host 修复的基线、仅修改 VM worker 调度/私有测试及 README 的候选。每版本 3 warmups、30 个随机同轮样本;独立 namespace、owned pivot_root、fresh VM/Host listener,整父组 CPU 0,1 / quota 两核 / 16 GiB / swap 0,同 B-FS-TOOLS 七工具及输入、缓存、逐字节 upper、宿主隔离与干扰门禁。使用原 reference timer,profiling 关闭;与当前基线的差异用于候选归因,优化前版本只用于同批恢复程度对照。5,000 次配对 bootstrap,分离簇不报整体排名;各候选批次独立保留,只发布通过门禁的最终制品,不合并样本。原始 helper、冻结源码、构建和诊断在 `.data/`,加工 CSV 与结果仅进入 `lab-notes/filesystem-performance-analysis.md#vm-completion-dispatch`,不重算跨运行时用户表,不外推 macOS、冷磁盘或并发吞吐。 - **不可变 share 的 DAX 开关对照:** `benchmark.new/filesystem/dax_ab.py` 准备同一优化制品、固件和物理不可变输入,生成 `in.json` 后通过 `semspec bench` 执行 Python 配对行;不使用 hyperfine。两组均通过公开 VM API 建立只读 DAX-capable share 和 128 MiB 窗口,仅 guest 挂载选项 `dax=never` / `dax=inode` 不同;statx 必须验证实际 DAX 属性。宿主热缓存、新 guest、独占 rootfs upper/work;完整 VM 组 CPU 0,1、两核 quota、2 GiB、swap 0,guest 2 vCPU/512 MiB。静态 C 探针测独立 64 MiB 文件的顺序读取、双线程读取和 mmap 页遍历,以及 128×64 KiB 小文件 open/read/close、2,048 路径 metadata;首次数据访问与 guest 内重复访问分列,全量内容验证在阶段计时之外。小文件组有超过窗口容量的映射,保留其正常回收成本。各组 3 次预热、30 个预先随机平衡配对,共 60 个正式 VM;5,000 次配对 bootstrap,先检查分布,保留有效慢样本,不报告 P99。校验错误、输入/制品变化、非零退出、预算不符、OOM 或外部构建/测试干扰使批次失败;报告失败和剔除数。冻结 harness、源码、制品、全部日志与样本在 `.data/`,加工表和 CSV 为工程报告;不将只读 share 的结果外推到 CLI 可写 workspace、启动退化或磁盘冷缓存。 -- **guest 写合并开关对照:** 同一冻结的直接队列 GNU release/gateway 制品,仅切换宿主 runner 的 `PVISOR_VM_FS_WRITEBACK=1` / `0`,由专用 worker 恢复并校验原环境。Linux VM 的 rootfs/workspace 均无 DAX 窗口;与 B-FS-TOOLS 相同的七项操作、完整任务和校验,整父组 CPU 0,1、两核 quota、16 GiB、swap 0,guest 2 vCPU/16 GiB。热宿主缓存、每次私有 namespace/pivot_root、独立工作区与工具缓存;每臂 3 warmups、30 个 seeded 随机配对,共 60 个正式任务。输入与制品摘要、完整 upper 字节、Run Bundle、正常退出、预算和外部构建/测试门禁通过后才能发布;保留慢有效样本,分离簇不给整体排名,5,000 次配对 bootstrap,不报告 P95/P99。原始及冻结执行入口保留 `.data/writeback-ab-*` 与 `.data/writeback-quick-*`;工程表和 CSV 进入 `design/filesystem-performance-analysis.md#writeback-ab`,生产默认值和跨运行时用户表不由该开关实验改写。 +- **guest 写合并开关对照:** 同一冻结的直接队列 GNU release/gateway 制品,仅切换宿主 runner 的 `PVISOR_VM_FS_WRITEBACK=1` / `0`,由专用 worker 恢复并校验原环境。Linux VM 的 rootfs/workspace 均无 DAX 窗口;与 B-FS-TOOLS 相同的七项操作、完整任务和校验,整父组 CPU 0,1、两核 quota、16 GiB、swap 0,guest 2 vCPU/16 GiB。热宿主缓存、每次私有 namespace/pivot_root、独立工作区与工具缓存;每臂 3 warmups、30 个 seeded 随机配对,共 60 个正式任务。输入与制品摘要、完整 upper 字节、Run Bundle、正常退出、预算和外部构建/测试门禁通过后才能发布;保留慢有效样本,分离簇不给整体排名,5,000 次配对 bootstrap,不报告 P95/P99。原始及冻结执行入口保留 `.data/writeback-ab-*` 与 `.data/writeback-quick-*`;工程表和 CSV 进入 `lab-notes/filesystem-performance-analysis.md#writeback-ab`,生产默认值和跨运行时用户表不由该开关实验改写。 - **guest 目录镜像与惰性 OPEN:** `guest_cache.py`,同一冻结 release CLI/SDK 和固件切换 `PVISOR_VM_GUEST_CACHE=0/1`,writeback 固定关闭。普通 `--safe` CLI 工作区与 SDK 显式 Immutable lower 独立成批;2 vCPU/4096 MiB、热宿主输入、新 VM/upper、3 warmups/30 seeded 随机配对。分列 2048 路径首次/重复 stat、深目录 stat、目录枚举、64 MiB 读取、1000 次热 open/fstat 与 open/read、宽目录单文件访问及 1.3s 空闲后 stat。校验全部数据、退出/Bundle 和输入不变,保留全部有效慢样本,配对 bootstrap 95% CI、先检查分布,不报告 P99。独立 B-FS-DIAG 运行用 prime-only 差分核对 READINDEX/OPEN/GETATTR 等请求,不把 profiling 耗时混入正式样本;声明资格、TTL 和跨文件数据缓存策略差异,不将 SDK 不可变 share 外推到普通 CLI 或整个 Agent。报告、来源、失败和完整数据保留 `.data/guest-cache-*`。修复预取退化时,使用 `--baseline-firmware` 在同一 CLI/SDK/payload 下比较旧/新固件,两臂 guest cache 均为 1,仍采用相同的随机配对、分布与校验规则。自适应预取由 `guest_cache_adaptive.py` 同批比较原始预取、仅枚举加载和候选三种固件(均 cache=1),增加宽目录两文件、32 随机文件、32 跨步文件及全量连续 stat,检验利用率门槛和恢复程度;预算、30 配对轮次、独立计数和校验规则相同。 @@ -653,7 +647,7 @@ Design: 负载、对照、控制变量与有效样本判据。 ### B-KERNEL-ENG:裁剪固件是否缩短当前产品的启动 {#b-kernel-eng} -- **角色:** engineering A/B;放入 `docs/src/*/design/vm-startup-performance-analysis.md`,不作为跨产品用户排名。 +- **角色:** engineering A/B;放入 `docs/src/*/lab-notes/vm-startup-performance-analysis.md`,不作为跨产品用户排名。 - **Motivation:** 判断裁剪 guest 内核的收益,以及它是否仍支持工作区、开发工具和网络所需能力。 - **想要的结论:** 相同 pVisor 二进制、相同 Linux 源码和补丁、相同打包方式,仅配置不同的两份新固件,其就绪/完整任务中位数差及 95% 配对 bootstrap 区间;列出减少的功能与未验证能力。 - **实验设计:** 冻结固件源码、输入 tarball、补丁、配置与编译记录,分别重建通用配置和裁剪配置;不复用旧固件作为基线。先验证构建和同样负载的输出、暂存隔离与工作区内容;Linux KVM 上以相同两核/内存/工具输入,随机交替 shell-ready、七项文件工具和修复任务,每格 30 次、3 次预热。CPU 缓解、seccomp、namespaces、virtio-fs 等所需配置必须保留;网络/恢复能力需独立正确性检查,不能由 shell 启动通过推导。配置中 guest LSM/设备功能差异必须明确,不称为相同加固程度的排名。 @@ -839,8 +833,8 @@ Design: 负载、对照、控制变量与有效样本判据。 ### B-CLUSTER:增加机器和资源后,能否得到更多有效结果 {#b-cluster} -- **文档:** `cluster-scalability.md` -- **状态:** 已退役;只保留历史证据,无活动测量或发布入口。旧 Controller/Worker 数据不是当前 daemon 的吞吐、密度或历史成本。 +- **文档:** 无用户页;原 `cluster-scalability.md` 已删除,历史证据只保留在本地归档。 +- **状态:** 已退役;无活动测量、发布入口或用户页。旧 Controller/Worker 数据不是当前 daemon 的吞吐、密度或历史成本。 - **角色:** user-facing(历史证据) - **Motivation:** 规模化运行 Agent 时,用户关心的是增加 Worker 和资源能不能线性地增加有效产出,以及控制面在长期运行后是否会成为瓶颈。 - **想要的结论:** "在固定的总资源预算下,每秒完成的有效任务数随 Worker 数增长的曲线";"控制面在保留 N 条历史记录时的内存和重启耗时"。 @@ -892,8 +886,9 @@ Design: 负载、对照、控制变量与有效样本判据。 - [ ] 已阅读本文件和路径上每一级目录的 README。 - [ ] 改动对应的注册表条目存在,脚本注释块与条目一致。 -- [ ] 用户文档页严格按"主要结论 → Motivation → 实验设计 → 实验数据和分析"四节组织。 -- [ ] 主要结论的第一句直接回答标题的问题,所有数字都能在本页的表或图中找到。 +- [ ] 用户文档页严格按"Motivation → 实验设计 → 实验数据和分析"三节组织。 +- [ ] Motivation 第一段是定性判断、首句直接回答标题;第二段是定量支撑,所有数字都能在本页的表或图中找到。 +- [ ] 实验设计先回答"衡量什么"、再回答"如何测量",且只描述当前批次。 - [ ] 结论以 pVisor 的技术选择、用户价值与适用条件为主线;对照身份明确,预期与实测区分,不利结果完整保留。 - [ ] 没有过程叙述、版本迭代史和内部代号;工程 A/B 和诊断结果没有进入用户页正文。 - [ ] 百分比变化来自同批对照,并附有置信区间;双峰分布与受干扰样本已按[规则](#data-rules)处理。 @@ -905,4 +900,4 @@ Design: 负载、对照、控制变量与有效样本判据。 - [`pvisor/`](pvisor/README.md):测量脚本、运行方式与报告格式。 - [`replay/`](replay/qwen3.6-results.md):Qwen3.6 SandboxReplay 实验记录,保留历史样本,不作为产品保证。 - 用户文档:[`docs/src/zh/benchmarks/`](../docs/src/zh/benchmarks/index.md)。 -- 技术分析:`docs/src/zh/design/*-performance-analysis.md`。 +- 技术分析:`docs/src/zh/lab-notes/*-performance-analysis.md`。 diff --git a/benchmark/pvisor/FILESYSTEM_PROFILING.md b/benchmark/pvisor/FILESYSTEM_PROFILING.md index a6029add..b85943c8 100644 --- a/benchmark/pvisor/FILESYSTEM_PROFILING.md +++ b/benchmark/pvisor/FILESYSTEM_PROFILING.md @@ -345,7 +345,7 @@ Explicit `--cases rg-2048,rg-deep-2048,git-status-2048,npm-offline-32` requires The five-item optimization campaign is recorded under `target/optimization-five-20261005`, with reviewable reports, source patch and -validation logs in [the evidence directory](../../docs/src/assets/benchmarks/filesystem-optimizations-20261005/). +validation logs in the evidence directory (local archive: `docs/src/assets/benchmarks/.data/filesystem-optimizations-20261005/`). Its baseline was copied before these edits; the candidate applies only the seven relevant source/build files to that copy. Concurrent lazy-cache/backend work is excluded from the comparison. Source and @@ -454,9 +454,9 @@ workload tails also varied. The executable grows from 14.87 MiB to 18.59 MiB These timings cover this fixed Linux/KVM fixture, not every workload or platform. Final raw samples and provenance are preserved in -[the release comparison](../../docs/src/assets/benchmarks/filesystem-optimizations-20261005/code-v3-4g.tsv), -[the build-profile comparison](../../docs/src/assets/benchmarks/filesystem-optimizations-20261005/profile-v3-4g.tsv) -and [the manifest](../../docs/src/assets/benchmarks/filesystem-optimizations-20261005/manifest.tsv). +the release comparison (local archive: `docs/src/assets/benchmarks/.data/filesystem-optimizations-20261005/code-v3-4g.tsv`), +the build-profile comparison (local archive: `docs/src/assets/benchmarks/.data/filesystem-optimizations-20261005/profile-v3-4g.tsv`) +and the manifest (local archive: `docs/src/assets/benchmarks/.data/filesystem-optimizations-20261005/manifest.tsv`). ## Shared filesystem service and direct lazy-image version evaluation @@ -510,8 +510,8 @@ Lazy whole-job P50 rises 2.29% cold and 0.64% warm. Removing the extra mount doe not establish general acceleration. The experiment does not separately profile metadata projection, materialization, preimage and synchronization costs. -Full results and historical context are in the [benchmark article](../../docs/src/en/design/filesystem-performance-analysis.md#filesystem-service). -Public raw reports and provenance are preserved in [the evidence directory](../../docs/src/assets/benchmarks/filesystem-service-20261005/). +Full results and historical context are in the [benchmark article](../../docs/src/en/lab-notes/filesystem-performance-analysis.md#filesystem-service). +Historical raw reports and provenance were archived locally in the evidence directory (local archive: `docs/src/assets/benchmarks/.data/filesystem-service-20261005/`). `plot_filesystem_service.py` renders the standalone SVG figures from those reports. ## Host stage journal profiling and optimization (2026-10-05) diff --git a/benchmark/pvisor/README.md b/benchmark/pvisor/README.md index 76f3d36c..1d33d659 100644 --- a/benchmark/pvisor/README.md +++ b/benchmark/pvisor/README.md @@ -4,7 +4,7 @@ Read [the benchmark registry and writing rules](../README.md) before measuring o ## Lazy image client startup -`B-LAZY-STARTUP` compares a Distribution registry's complete-image Docker path with a real `pvisor-cache serve` lazy VM path for the same pinned linux/amd64 manifest and workload. The default `ubuntu-shell` cohort uses Ubuntu 26.04; `numpy-script` is a separate Python/NumPy cohort. `torch-import` remains optional but has no formal samples; its failed attempts are retained, not performance evidence. Never pool different workloads or their preflight and formal samples. This is not OpenSandbox `pvisor-daemon serve`. See [the retained Ubuntu local report](LAZY_STARTUP_REPORT.md) and derived Ubuntu CSV (local archive: `.data/derived-tables-20261018/lazy-startup-summary.csv`); they do not establish NumPy or torch performance. The [bilingual user article](../../docs/src/zh/benchmarks/lazy-image-startup.md#numpy) includes the independent NumPy cohort, with [derived statistics](../../docs/src/zh/benchmarks/lazy-numpy-summary.csv), [differences/preparation](../../docs/src/zh/benchmarks/lazy-numpy-details.csv) and [provenance](../../docs/src/zh/benchmarks/lazy-numpy-provenance.csv). Historical evidence is retained at `benchmark/pvisor/.data/lazy-numpy-local-20261007/`. Its legacy `derive.py` writes historical CSVs; do not use it to overwrite current site downloads. The current implementation rerun below supplies the user article and current CSVs. +`B-LAZY-STARTUP` compares a Distribution registry's complete-image Docker path with a real `pvisor-cache serve` lazy VM path for the same pinned linux/amd64 manifest and workload. The default `ubuntu-shell` cohort uses Ubuntu 26.04; `numpy-script` is a separate Python/NumPy cohort. `torch-import` remains optional but has no formal samples; its failed attempts are retained, not performance evidence. Never pool different workloads or their preflight and formal samples. This is not OpenSandbox `pvisor-daemon serve`. See [the retained Ubuntu local report](LAZY_STARTUP_REPORT.md) and derived Ubuntu CSV (local archive: `.data/derived-tables-20261018/lazy-startup-summary.csv`); they do not establish NumPy or torch performance. The [bilingual user article](../../docs/src/zh/benchmarks/lazy-image-startup.md#numpy) includes the independent NumPy cohort, with historical derived files `lazy-numpy-summary.csv`, `lazy-numpy-details.csv` and `lazy-numpy-provenance.csv` belonging to local evidence rather than current site downloads. Historical evidence is retained at `benchmark/pvisor/.data/lazy-numpy-local-20261007/`. Its legacy `derive.py` writes historical CSVs; do not use it to overwrite current site downloads. The current implementation rerun below supplies the user article and current CSVs. Finish other builds/tests before sampling. Docker access uses `sg docker -c`; KVM and both frozen executables must be usable. The successful NumPy preflight uses the existing `target/release/pvisor` launcher with the separately built `target/lazy-torch-build/release/pvisor-cache`, selected via `--cache-binary`. This static cache build includes Docker gzip compatibility; the directory name is historical and does not mean torch was measured. The commands below keep the default launcher directory `target/release` and override only the cache executable, not `--binary-dir`. A new launcher conflicts with the existing persistent Host listener: **do not kill or replace the user's listener** to run this benchmark. Preserve the compatible existing launcher/listener pairing. Finish artifact preparation and freeze the binaries before preflight; do not rebuild during sampling. Install `skopeo` and `openssl`; loopback ports 15000/15443/15444/15445 must be free. First pull the report's pinned Distribution image outside timing: @@ -394,7 +394,7 @@ Apply sampling honors `--samples` and `--warmups` at every file count, including Keep raw reports, per-trial samples, stdout/stderr, failures, input hashes, binaries and frozen harnesses in `.data/`. The repository ignores that directory at every depth. A new output directory is required for every run; retain slow valid samples and failed preflights. Do not build, run other tests or sample unrelated workloads during measurement. -Public Markdown contains derived comparisons. Supporting CSVs sit beside each article in `docs/src/{zh,en}/benchmarks/`, with download links. They identify cohort, resource budget, sample count, statistic and source digest. Full typed TSV reports, sample CSVs and archives stay local. Existing evidence is preserved in `docs/src/assets/benchmarks/.data/`; the verified migration inventory is in `benchmark/.data/raw-migration.json`. +Public Markdown contains derived comparisons. Current downloadable CSVs are allowlisted by `benchmark.new/public_assets.py` and shared under `docs/overrides/assets/benchmarks/data/`; historical and engineering CSVs stay in local evidence. Retain cohort, resource budget, sample count, statistic and source digest. Full typed TSV reports, samples and archives stay local. Historical records identify `docs/src/assets/benchmarks/.data/` and the migration inventory `benchmark/.data/raw-migration.json`; these archives are not distributed with a checkout. Legacy export commands below retain their historical destinations and are not current site-publication instructions. For large parked-capacity sweeps, `parked_density.py --archive-completed-snapshots` losslessly retains completed Job snapshot/restore trees as each batch's `snapshot-artifacts.tar.zst` and `snapshot-artifacts.json`. This happens after the measured service exits, outside all task timers, cgroup phase memory and CPU. Logs, configurations, full recovery proofs, Run Bundles and final upper changes remain directly readable. Every archive member's bytes, links, mode, numeric ownership, nanosecond timestamp and extended attributes are checked before original generated trees are removed. Failed, unknown or incomplete batches keep their complete artifacts. Archive compression is a retention operation, not a measured VM compression mechanism: zstd level 3 uses one thread and a maximum 512 MiB matching window in the outer coordinator, after the measured cgroup has exited. Restore into a new scratch directory with: @@ -1030,7 +1030,7 @@ python3 benchmark/pvisor/parked_density.py \ Every state touches/checks 64 MiB, waits for an exact stdin token, and on recovery verifies the saved identity, full data, Git status and four edits among 64 files. Admission/parking is sequential, all states must remain parked at the common barrier, and recovery uses one fixed slot. Current raw/compressed Job snapshots, native SIGSTOP and Podman pause have different portability and boundary semantics. Podman needs delegated child cgroups to freeze; payload/conmon must remain below the same 2 GiB/two-core/zero-swap parent. Unsupported stdin restoration or freezer control is a failed preflight, never a timed-sleep fallback. Only after every selected preflight condition passes, start a new five-round 1..128 capacity sweep. This does not establish tail latency, active concurrent throughput, SDK offload or automatic cold-page compression; raw backing cache may be reclaimed under the same memory pressure. Keep all failed and unknown outcomes, OOM events and private backing/cache in the accounting. -B-CLUSTER is retired with the Controller/Worker implementation. Removed runners are `cluster_scalability.py`, `cluster_worker.py` and `controller_history.py`; their dedicated tests, `plot_cluster_scalability.py` and `publish_controller_history.py` are also removed. There is no current reproduction, plotting or publication command for this ID. Frozen historical harnesses and reports in local `.data/` remain archival evidence, not active entry points. The locale `cluster-scalability.md` articles identify the retained CSVs as historical results; those bytes and receipts must not be relabeled as daemon measurements. +B-CLUSTER is retired with the Controller/Worker implementation. Removed runners are `cluster_scalability.py`, `cluster_worker.py` and `controller_history.py`; their dedicated tests, `plot_cluster_scalability.py` and `publish_controller_history.py` are also removed. There is no current reproduction, plotting or publication command for this ID. Frozen historical harnesses and reports in local `.data/` remain archival evidence, not active entry points. The former locale `cluster-scalability.md` articles were removed; the retained CSVs remain archival evidence, and those bytes and receipts must not be relabeled as daemon measurements. B-DENSITY and B-VM-MEMORY remain independent local benchmarks: `density.py`/`density_worker.py`, `parked_density.py`/`parked_memory_probe.rs`, `vm_memory.py`/`memory_probe.rs`, `live_vm_memory.py` and `macos_cold_ram.py` are not Cluster runners. Their source/binary/input receipts, integrity checks, failure accounting and resource controls remain required. None establishes daemon density, scheduling throughput or retained-history costs. @@ -1614,14 +1614,14 @@ Build frozen sources with only the proposed change between versions; report pair ## CI regression gate -B-PROCESS uses `bench.py` through `just benchmark`. It checks a successful minimal Run and Bundle access, with 2 warmups/10 samples for smoke or 10 warmups/50 samples for nightly. It does not establish cross-runtime user rankings. +B-PROCESS uses `benchmark.new/process/{smoke,nightly}.json` through `just benchmark` and semspec bench. `bench.py` remains a historical helper. It checks a successful minimal Run and Bundle access, with 2 warmups/10 samples for smoke or 10 warmups/50 samples for nightly. It does not establish cross-runtime user rankings. ```bash just benchmark -OUTPUT=benchmark/pvisor/.data/nightly just benchmark nightly +just benchmark nightly --output benchmark.new/process/.data/nightly-new just benchmark-compare \ - benchmark/pvisor/.data/candidate/raw-report.json \ - benchmark/pvisor/.data/main/raw-report.json + benchmark.new/process/.data/candidate/in.bench.json \ + benchmark.new/process/.data/main/in.bench.json ``` ## Linux SDK live RAM offload diff --git a/benchmark/replay/qwen3.6-results.md b/benchmark/replay/qwen3.6-results.md index 2b53dafc..5d4d1507 100644 --- a/benchmark/replay/qwen3.6-results.md +++ b/benchmark/replay/qwen3.6-results.md @@ -4,7 +4,7 @@ 模型服务配置、硬件及重复试验次数未完整登记;以下保留原始样本和当时的诊断, 未在本次文档清理中重跑。结果只说明这些轨迹的观测,不能推广为回放确定性或当前兼容性保证。 -现行使用方法与适配版本见 [回放指南](../../docs/src/zh/guides/sandbox-replay.md)。 +现行使用方法与适配版本见 [回放指南](../../docs/src/zh/guides/replay.md)。 后续结果应另外记录运行日期、提交、模型与 Agent 版本、环境、样本及失败记录。 ## 5. Qwen3.6 实测结果 @@ -559,8 +559,8 @@ Bash: 续跑的 `A′(N+1)` 可见文本为空白但命令同样逐字复现;两轮续跑 verifier Reward 均为 1。 精确参数见 -[`pvisor replay` 命令参考](../reference/cli.md#replay-an-agent-trajectory);执行边界见 -[执行指南](execution.md)。 +[`pvisor replay` 命令参考](../../docs/src/zh/reference/cli.md#replay-an-agent-trajectory);执行边界见 +[执行指南](../../docs/src/zh/guides/executors/index.md)。 ## OpenCode 实验诊断(历史记录) diff --git a/crates/pvisor-cli/src/bin/pvisor-replay.rs b/crates/pvisor-cli/src/bin/pvisor-replay.rs index ad0ad3e7..e32d4d4e 100644 --- a/crates/pvisor-cli/src/bin/pvisor-replay.rs +++ b/crates/pvisor-cli/src/bin/pvisor-replay.rs @@ -385,7 +385,7 @@ fn run_managed(config: &ReplayToml) -> Result { ReplayError::configuration(format!("resolve managed replay workspace: {error}")) })?; let mut command = Command::new(&executable); - command.args(["run", "--spec"]).arg(file.path()); + command.args(["run", "--config"]).arg(file.path()); command.current_dir(&working_dir); let status = command.status().map_err(|error| { ReplayError::configuration(format!("start managed pVisor replay: {error}")) diff --git a/crates/pvisor-cli/src/cli/run.rs b/crates/pvisor-cli/src/cli/run.rs index 25101397..bc8d7727 100644 --- a/crates/pvisor-cli/src/cli/run.rs +++ b/crates/pvisor-cli/src/cli/run.rs @@ -3560,6 +3560,7 @@ mod tests { let live = root.path().join("live"); std::fs::create_dir(&source).unwrap(); std::fs::create_dir(&live).unwrap(); + let live = live.canonicalize().unwrap(); std::fs::write(source.join("file"), b"fixed generation").unwrap(); let root_store = SnapshotStore::new(&root.path().join("root-store")).unwrap(); let root_base = root_store.prepare_rootfs(&source).unwrap(); diff --git a/crates/pvisor-overlay-core/tests/checked_backing_lookup.rs b/crates/pvisor-overlay-core/tests/checked_backing_lookup.rs index 52435a24..081bdbaf 100644 --- a/crates/pvisor-overlay-core/tests/checked_backing_lookup.rs +++ b/crates/pvisor-overlay-core/tests/checked_backing_lookup.rs @@ -102,6 +102,7 @@ fn excluded_denied_and_backend_enoent_remain_errors_instead_of_checked_absence() let temp = tempfile::tempdir().unwrap(); let lower = temp.path().join("lower"); fs::create_dir(&lower).unwrap(); + let lower = lower.canonicalize().unwrap(); let service = FilesystemService::new( OverlayCore::new_with_exclusions_and_preimages( vec![lower.clone()], diff --git a/docs/README.md b/docs/README.md index 12f8ee9a..9e15def9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,6 +21,74 @@ English article at the same relative path under `docs/src/en/`. Chinese defines the canonical information architecture; both languages describe the same behavior, examples, evidence and known limitations. +## Benchmark pages {#benchmark-pages} + +Benchmark articles under `docs/src/{zh,en}/benchmarks/` are user decisions, not +engineering reports: a reader must be able to choose a mode or size a deployment +from them. Registration, data and publication rules live in +[`benchmark/README.md`](../benchmark/README.md#structure). The rules below are the +failure modes that have actually reached the site; treat them as hard rules. + +**Structure** + +- Exactly three H2 sections, in this order and with these anchors: + `Motivation {#motivation}`, `Experiment design {#interpretation}`, + `Data and analysis {#results}`. Never add `Conclusions`, `What is measured`, + `How it is measured` or `Limitations` sections. +- `Motivation` is two paragraphs. The first is a judgement whose first sentence + answers the H1. The second is quantitative support only. +- No tables, lists, batch history, dates or artifact hashes in `Motivation`. +- Every number in `Motivation` must be traceable to a table, figure or data + paragraph on the same page. Rounding to the displayed precision is fine; + inventing a new number is not. + +**Experiment design** + +The first paragraph is a fixed form, never a procedure and never a defence of +the metric: + +1. `Measure X as Y.` Name the quantity and the metric. +2. `Y is the capability it represents.` +3. `A lower or higher Y means the reader's outcome.` + +Example, from startup latency: + +> Measure the interval from launch to the first checked shell output as +> environment Ready time. That interval is how quickly the system answers a +> caller: a shorter Ready time means the system handles bursts of large-scale +> requests better. + +- Do not write "this page", "本页", "we", "我们", "note that", or a list of + caveats before the metric. +- The remaining paragraphs describe only the current cohort: environment, + controls, sampling, validation, exclusions and what the design cannot answer. + Historical cohorts and before/after narratives belong in the data section, + and only on a page that is explicitly historical. +- If a metric does not change a decision, do not report it. Delete its table + instead of keeping it for completeness: `startup.md` reports Ready only, + because exit time does not change which executor a reader picks. + +**Data and analysis** + +- Lead with the table or figure that answers the conclusion, then interpret it. + Do not restate table cells as prose. +- Keep historical cohorts in this section, label them, and never pool them with + the current cohort. +- Keep the page within roughly three screens. Move engineering A/B and + diagnostic detail to `lab-notes/`. + +**Editing rules** + +- Change both languages in the same edit, then run + `python3 scripts/check-docs.py --record-translations` and + `python3 scripts/check-docs.py --require-recorded`. +- Before removing or renaming an H3/H4, search the repository for its `#anchor`. + Anchor churn breaks lab-note links and is not a formatting cleanup. +- Do not put a benchmark registry ID (`B-*`) or an internal switch name on a + user page; link to the topic page or the runner manual instead. +- Run `python3 benchmark.new/docs.py check` after touching a `{{ table(...) }}` + macro, `benchmark.new/docs.json` or a `*.render.json` file. + ```bash just docs-serve # native Chinese preview on 127.0.0.1:3000 just docs-serve en # native English preview on 127.0.0.1:3001 @@ -111,9 +179,9 @@ and user-facing protocol pages belong in the site's `reference/` tree, not at th ## Information architecture Value before mechanism, mechanism before implementation. Keep Home as the first -top-level tab, followed by six sections: Quick start → User guide → Core concepts -→ Benchmarks → Design and research → Contributing -(首页 → 快速开始 → 用户指南 → 基础概念 → 基准测试 → 设计与研究 → 参与开发). +top-level tab, followed by seven sections: Quick start → User guide → Core concepts +→ Benchmarks → Design and research → Lab notes → Contributing +(首页 → 快速开始 → 用户指南 → 基础概念 → 基准测试 → 设计与研究 → 实验记录 → 参与开发). Quick start includes the product introduction and `why/` articles; User guide includes the task learning path and reference pages; Core concepts includes Security as a subsection. The homepage remains accessible through its own tab @@ -124,14 +192,15 @@ subgroups into their parent group; do not add a third sidebar level. The canonical Chinese documentation uses these sections: -- `why/`: the case for pVisor — vision, supervision-bandwidth argument, trust ladder, use cases, comparisons, when not to use. -- `start/`: product scope, installation, the first reproducible Job, and where to go next. +- `why/`: the case for pVisor — the supervision-bandwidth argument, trust ladder with use cases, and fit check with comparisons. +- `start/`: installation and the first reproducible Job, ending with where to go next. - `guides/`: tasks, commands and expected results, grouped by job (`agents/`, `policies/`, `executors/`). -- `concepts/`: the user mental model — jobs, staging, evidence, policy, glossary. +- `concepts/`: the user mental model — jobs, staging, evidence and policy layering. - `benchmarks/`: reproducible measurements and dated comparisons. - `security/`: what is protected, what is not, and how to report issues. - `reference/`: CLI, configuration, schemas and platform support matrices. - `design/`: implementation ownership, mechanisms, ADRs and research directions. +- `lab-notes/`: dated engineering experiment logs and historical evidence; conclusions are governed by `benchmarks/` and `design/`, not by these notes. - `community/`: contributing, development, testing, release, roadmap and policies. Experimental feature documents live under `design/experimental/` in both locale @@ -202,9 +271,10 @@ The native `exclude` plugin excludes `.data/` at every depth, and the generated site checker rejects leaked evidence. Zensical publishes the shared theme assets in each locale, including images and JSON downloads, so native previews need no extra server. JSON fixtures, recording tools and published figures use -`docs/overrides/assets/` directly. Existing local evidence remains in the real -`docs/src/assets/benchmarks/.data/` directory, outside the three projects' article -roots. Do not replace the former tracked `docs/src/assets/` or +`docs/overrides/assets/` directly. Historical evidence paths include +`docs/src/assets/benchmarks/.data/`, outside the locale article roots. These local +archives are not distributed with a checkout; preserve their recorded identities +without presenting absent files as public downloads. Do not replace the former tracked `docs/src/assets/` or `docs/src/stylesheets/` directories with symlinks: Git cannot stage individual old-file deletions through a symlink during the migration. @@ -227,7 +297,7 @@ matter or navigation label. Removing `status: todo` does not complete a missing field reference, schema, experiment, or policy decision. Keep outstanding items explicit and attach the implementation or verification that completes each one. Preserve page paths and bilingual parity. Keep both locale navigation trees in -the Home-plus-six-section order defined above. +the Home-plus-seven-section order defined above. ### Writing style @@ -247,7 +317,7 @@ it. The models are the uv, Ruff and Ray docs. - Prefer a concrete example over an abstract description; show the command and what it does. - State a guarantee once, on the page that owns it, and link from elsewhere. Never open a page with a disclaimer, and never repeat a caveat in every paragraph. - No meta text: no “本文/本节/本页”, no “继续阅读”, no first line that restates the heading. -- Name the mechanism when it matters; keep terms consistent with the glossary. +- Name the mechanism when it matters; keep terms consistent with the concept page that owns them. The execution-guarantee framework has exactly one naming: **有界 / 可逆 / 可查** (bounded / reversible / checkable) — do not coin variants (可恢复/可核查, 放手/把关/有据, auditable, ...). - Tables for options, matrices and comparisons; code fences for anything runnable. - Keep article directories in the sidebar. Omit tables that only map topics to documentation links, and do not replace them with equivalent link lists. @@ -261,6 +331,78 @@ it. The models are the uv, Ruff and Ray docs. where its detail becomes relevant instead of duplicating its sections. - A page with no data yet says “建设中” and links to its TODO page instead of making an empty claim. +### Page count, placement and conclusions + +Five hard rules distilled from the October 2026 restructure (161 → 124 pages). +They exist because the failure modes below already happened once; do not +reintroduce them. + +1. **Page count follows information content (页数随信息量).** A page shorter + than ~30 substantive lines does not stand alone; fold it into its parent. + Navigation depth must not exceed content depth. Never split one topic into + several pages to make the sidebar look complete. +2. **One fact, one home (一个事实一个家).** Each assertion lives on exactly + one page; every other page states it in one sentence and links. Before + adding a paragraph, grep for its key phrase — if it already exists, link, + do not restate. The 2026 review found the same three-command workflow on + ten pages and the same owner.json paragraph three times verbatim. +3. **No pages for empty sets (空集合不建页).** No adopters page without + adopters, no governance page for a single-maintainer project, no + publications page without publications. If the set is empty, say so in one + sentence on the parent page. Status honesty beats maturity theater. +4. **Status determines location (状态决定位置).** Implemented → `design/` or + `guides/`. Accepted but unimplemented → `design/experimental/` or an + explicit “proposal (not implemented)” banner, kept short. Retired → a + tombstone paragraph. Dated experiment batches and engineering logs → + `lab-notes/`, never `design/`. A page that describes a target state must + say so at the top and point to the current-implementation boundary. +5. **The conclusion test (结论测试).** The first sentence of a page must + answer the question its title asks, with absolute numbers or a direct + judgment. Delete circular sentences (“adopt when benefits exceed costs” + without a threshold) and self-referential closures that define the product + by its own coinage. Benchmark pages follow the fixed pattern: absolute + water level in the first sentence → scenario entries → shortcomings floated + up. + +`scripts/check-docs.py` enforces the mechanical parts in CI (via +`just docs-build`): bilingual pairing, navigation targets, link/anchor/image +resolution — and a **duplicate-paragraph gate** that fails the build when the +same substantive prose paragraph (≥150 chars) appears in two pages. Intentional +shared boilerplate must use a recognized convention instead of raw repetition: +blockquote notes, `measurement-status` marker regions, link/pointer lines, or +an `ALLOWED_DUPLICATES` entry with a written reason. + +### Design writing references + +Model the explanation of one mechanism on this sequence: problem and constraints → +minimal system model (who owns state) → the normal path of one real request → +the failure path → tradeoffs → implementation and evidence entry points. The +[design overview](src/zh/design/index.md) follows this order through one +end-to-end task. Each figure answers one reader question: ownership (layered +diagram), one operation (sequence), data placement (layout/map), crash residue +(failure states), or cost (sourced measurement). Figure components must have +corresponding entry points in source or contracts. + +Expression references worth studying, by local topic (accessed 2026-10-07; these +evaluate documentation craft, not project quality): + +| Project and article | What to learn | +| --- | --- | +| [ByteHook · project overview](https://github.com/bytedance/bhook/blob/main/doc/overview.zh-CN.md) | Derive mechanisms from the necessary underlying model; connect objects and calls with figures | +| [TigerBeetle · Architecture](https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/ARCHITECTURE.md) | Start from workload and constraints before persistence and design decisions | +| [Firecracker · Design](https://github.com/firecracker-microvm/firecracker/blob/main/docs/design.md) | Host integration, threads and the device model in one architecture narrative | +| [gVisor · Architecture guide](https://gvisor.dev/docs/architecture_guide/intro/) | Explain the boundary through one syscall example | +| [Tokio · Runtime](https://docs.rs/tokio/latest/tokio/runtime/index.html) | Usage model first, then thread lifetimes and scheduling guarantees | +| [etcd · Client design](https://etcd.io/docs/v3.6/learning/design-client/) | Error and retry semantics for lost ACKs and unknown outcomes | +| [Ray · Architecture whitepapers](https://docs.ray.io/en/latest/ray-contribute/whitepaper.html) | Keep overview and internal topics in separate layers | +| [Rust Compiler Development Guide](https://rustc-dev-guide.rust-lang.org/overview.html) | From pipeline to queries, data structures and source entry points | +| [CockroachDB · Design](https://github.com/cockroachdb/cockroach/blob/master/docs/design.md) | Layered diagrams connecting data abstractions to physical layout | + +Diagrams use the site's dark-blue palette: background `#0d1b30`, cards +`#142840`, accent `#a8cefa`, text `#e9eef8`; teal, amber and dark red mark +sharing, change and conflict states with text labels. Keep SVG text searchable; +split long diagrams into per-topic parts. + The native TOML files own navigation. Maintain paired Chinese and English articles. Keep only current article paths; do not maintain historical redirect maps or compatibility pages. When moving or merging articles, update incoming source @@ -397,51 +539,15 @@ To validate a TOML file without launching an executor: cargo run --locked -p pvisor --example documentation_config -- run.toml ``` -### community/adopters.md - -Measurements, generated references, or formal decisions still need completion. The acceptance criteria below remain required; the page retains its planned status. - -**Acceptance criteria** - -- Publish users and scenarios with consent. -- Distinguish production use from experiments. - -### community/code-of-conduct.md - -**Requirements** - -- Adopt [Contributor Covenant 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) or an equivalent text; -- Specify a reporting channel (dedicated email or maintainers), rather than public issues; -- Describe handling procedures and possible consequences. - -**Acceptance criteria** - -- Add repository-root `CODE_OF_CONDUCT.md` and keep this page consistent; -- Ensure that the reporting channel works and is listed on [Community](index.md). - ### community/governance.md -Measurements, generated references, or formal decisions still need completion. The acceptance criteria below remain required; the page retains its planned status. +The page describes the current single-maintainer process; a formal maintainer list, +charter and conduct reporting channel are not yet established. **Acceptance criteria** -- Define the maintainer list, decision process and advancement path. - Describe the human role in semspec approval. - -### design/decisions/index.md - -**Requirements** - -- Create an ADR template (context, options, decision, consequences, status) and a numbering convention (`NNNN-short-title.md`). -- Backfill the existing key decisions, for example: - - Admission plans stop at `Planned`; enforcement comes only from executor observations. - - Gateway and replay are separated from the core closure as optional features. - - `--safe` does not select an executor and refuses to start rather than degrading when it cannot enforce. - - The human approval process for semantic specifications. - -**Acceptance criteria** - -- At least four numbered ADRs with titles/status. +- Announce the maintainer list, charter and conduct channel on this page once established. ### design/replay.md @@ -456,46 +562,6 @@ Measurements, generated references, or formal decisions still need completion. T - Code/test references per adapter. - Link replay-fidelity results. -### design/research/cluster-execution.md - -**Requirements** - -- Metrics: single-node useful-work density and execution/evidence overhead under fixed resource budgets. -- Controls: native execution and external Kubernetes or Ray orchestration, with pinned versions. -- Workload: independent sandboxes; cross-node placement, retries and workflows remain external. -- Environment: one measured node first; any external multi-node experiment has a separately declared scope. - -**Acceptance criteria** - -- pVisor defines execution semantics without replacing schedulers. -- Distinguish the daemon's implemented VM-only `NativeRuntime` from proposed integrations; require separate prepared-image and end-to-end SDK validation. -- Align claims with measured density; Cluster/controller measurements are not evidence for the node-local daemon. - -### design/research/publications.md - -Measurements, generated references, or formal decisions still need completion. The acceptance criteria below remain required; the page retains its planned status. - -**Acceptance criteria** - -- Link papers/reports/talks. -- State implementation revisions. -- Mark outputs that do not establish product guarantees. - -### design/research/rl-execution-substrate.md - -**Requirements** - -- Metrics: throughput, isolation, reproducibility, fork cost. -- Controls: RL framework sandboxes. -- Workload: fixed rollouts, failure replay, checkpoint forks. -- Environment: pinned model/tools. - -**Acceptance criteria** - -- Integration and scope. -- Tested recording, fork, and prefix replay. -- Separate design from the rollout guide. - ### guides/ci.md **Requirements** diff --git a/docs/index.html b/docs/index.html index 30356b66..9fdd05d8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,12 +1,12 @@ - + PolicyVisor documentation dark; font-family: system-ui, sans-serif; } + :root { color-scheme: light dark; font-family: system-ui, sans-serif; } body { margin: 0; min-height: 100vh; display: grid; place-items: center; } main { max-width: 36rem; padding: 2rem; } h1 { font-size: 2.5rem; margin-bottom: 1rem; } @@ -18,9 +18,9 @@ -
- 1>PolicyVisor -

Scaling autonomous

agent execution.
让自主 Agent 的执行可以规模化。

+
+

PolicyVisor

+

Scaling autonomous agent execution.
让自主 Agent 的执行可以规模化。