Skip to content

feat(api,control,docs): 新增 project.export——把分支快照流式导出到本地目录并实时报告进度(layerfs-project#53) - #600

Merged
yifanxuaaa merged 6 commits into
Ephemeral-AI-Lab:layerfs_v2_0_0from
jiangkoumo:feat/lp53-project-export
Nov 7, 2026
Merged

yifanxuaaa merged 6 commits into
Ephemeral-AI-Lab:layerfs_v2_0_0from
jiangkoumo:feat/lp53-project-export

Conversation

@jiangkoumo

Copy link
Copy Markdown
Collaborator

⚠️ 依赖:先合 #599,再合本 PR

本 PR 单独在 Python 3.15 上会红一项:test_project_export.py::AsyncBinding.test_callbacks_run_on_loop_in_order_before_return。原因是基线 aio.py 的回调排空有竞态,跟本 PR 无关,修复在 #599。实测:本分支单独(3b3cb179c)在 3.15 上 7/8,失败的就是这一项;和 #599 的分支合在一起(26fc1ae73、23fa36892)3.15 上 8/8。
合并顺序:先 #599,再本 PR。

任务:Ephemeral-AI-Lab/layerfs-project#53。提交 608b9aba1 标题里的 (#53) 指的也是 layerfs-project#53,不是本仓库的 #53。


新增 project.export(project, destination, { branch = "main", on_progress }),CLI 是 layerfs project export <store>/<project> <destination> [--branch <name>] [--progress]。它把一个 Branch 已提交的快照导出成调用方机器上的普通目录。来源可以是本地 SQLite、Docker / Lima / Apple Container 机器上的 SQLite(走共享 worker 流式路径),也可以是 PostgreSQL(同机或异机)。导出过程有分阶段、单调递增的实时进度;失败或断连不会报成完成,也不留半成品。

Base:layerfs_v2_0_0 @ b1802332b(本分支已包含,落后 0 个提交,git merge-tree 预演无冲突)。

改了什么

相对 base b1802332b:45 个文件,+3619/−75。生产 LOC(tools/production_loc.py,e1b86ae6…,两份快照都在干净 worktree 上按整树统计):b1802332b 140,847 → c71f89215 141,815(delta +968);增量全在 api 层:layerfs-api 1,427 → 1,450(+23)、layerfs-control 18,252 → 19,197(+945),core 39,399 / engine 64,750 / connect 16,070 不变。实现提交 608b9aba1 当时相对基线 d43047413 记的是 137,010 → 137,978(同为 +968;绝对值差 3,837 是上游在基线之后自己加的行)。之后的 3b3cb179c、c71f89215 都是 delta 0(实测 15e3258e5 与 c71f89215 都数出 141,815,产品代码 0 改动;c71f89215 提交信息里的绝对值写成 142,081,delta 0 与实测一致)。

1)新调用进入共享 call table,三端同一份契约

  • layerfs-api/src/project/{export.rs(新),mod.rs}:project、destination 必填,branch 默认 main,on_progress 可选;不提供 commit 参数(CLI 传 --commit 时 rc=2,提前拒绝)。
  • layerfs-control/src/calls/{mod.rs,dispatch.rs}:表从 61 条变成 62 条,project.export 的进度并入同一个事件流。
  • Node/Python 本来就按 call table 泛化派发,没有新增客户端逻辑;只重新生成了类型声明 api/node/src/index.d.ts、api/python/src/layerfs/{_client,aio}.pyi,package.mjs、test_stubs.py(含 mypy)都对得上。
  • 文档:docs/architecture/api/sdk/project/export.md(新)、call table、front-ends、routing、versioned/2.0.0/{README,calls,sdk}.md(61→62)、.agents/skills/layerfs-js-sdk。

2)只固定一次快照,只用一个本地写入器(layerfs-control/src/project/{export.rs(新),staged.rs,tree.rs})

  • 开始时解析一次目标 Branch,整个导出期间固定不变,结果里回报 snapshot、node、root、branch。
  • 先写进目标父目录下的 .layerfs-export-<id> 暂存目录(0700,与目标在同一文件系统),全部完成后才原子 rename 发布。目标已存在且非空,或者是普通文件、符号链接,一律拒绝,原目标不动。
  • 写入严格限制在暂存目录内:拒绝 ..、相对路径、Store home 内的路径;符号链接原样保留 target,从不跟随。
  • 导出前先检查 Store 格式:这个版本读不了的 Store(例如 SQLite schema version 1)在 open 时就被拒为 Failed,消息里写出离线转换工具 tools/store_blocks.py migrate;此时不产生 prepare 事件,也不建暂存目录。

3)Worker 流式路径(Docker / Lima / Apple Container)

  • machine/worker/{client,server}.rs 新增 project.export:worker 在 Store 旁遍历快照、按 2 MiB 分块回传,宿主用同一个本地写入器落盘。
  • 本地写失败时立即关掉 worker 流,worker 侧随之停止遍历,不会把整个快照读完才报错。
  • 发布前再核对一次:写入器统计的 files/directories/symlinks/bytes 和快照计数对不上,就拦下并清理暂存目录。

4)进度契约

  • 阶段依次是 prepare → export → finalize;字段 files, directories, symlinks, bytes, done, total,计数单调;不为算百分比做全量预扫描,total 恒为 null。
  • 大文件按块推进(9 MiB 级的文件会产生多条 export 事件);finalize 的计数与返回值一致;失败或中断时不产生 finalize,也不报完成。
  • 三端一致:CLI --progress(stderr JSONL,返回值走 stdout)、Node onProgress、Python 同步回调与 aio 异步回调。

5)准入与并发

  • 导出期间持有共享 Store 租约:可以同时跑 file.read 和另一个 project.export;这期间 store.remove、store.push 返回 InUse;处于 Busy/Unresolved 的 Store 按现有准入拒绝。
  • 导出途中执行 project.remove,不影响正在导出的固定快照。

6)测试

  • layerfs-api/tests/project_export.rs(新,8 个测试),postgres_connect.rs +2 个用例,calls_table.rs/project_family.rs 更新;api/node/test/project_export.mjs(9 个),api/python/test/test_project_export.py(8 个)。
  • 覆盖:空项目、二进制和 Unicode 路径、深层目录和大量文件、大文件、默认 main 与指定 Branch、拒绝 commit、.git 和被忽略的文件、权限位、空目录、相对/绝对/悬空符号链接、同一 symlink inode 的多个名字、非空目标、符号链接逃逸、写失败中断、计数不一致、并发写下的固定快照、SQLite schema v1 Store 被拒。

怎么验证

下面的数字都来自各轮结果文件,每行注明被测提交。被测提交之间的关系:

也就是说,head 上新增的 2 个测试只在 head 上跑过;其余结果来自产品代码与 head 相同(23fa36892)或更早的提交,表里如实标出。

通过

被测提交 / 环境 项目与数字
c71f89215,Mac(R3-FOLLOW) cargo +1.85.1 test --locked -j 2 -p layerfs-api --test project_export:8 passed / 0 failed(含新增的 symlink 与 schema v1 两项);git diff --check、tools/check_product_boundary.py、rustfmt --check 通过
c71f89215,Linux layerfs-test(PREPR,同一 target 连跑两遍) cargo test --locked -j 4 -p layerfs-api --test project_export:8 passed / 0 failed(0.47 s);同一条加 --features postgresql 再跑一遍:8 passed / 0 failed(0.44 s)。两遍都含新增的 symlink_aliases_keep_targets_and_never_follow_outside_staging 与 schema_version_1_store_is_refused_before_prepare_and_keeps_destination;两遍 Store busy 命中 0 次,没有重跑
23fa36892,Linux layerfs-test(CLOUD-R3) Rust project_export 6/6、calls_table 15/15(62 calls);Node project_export.mjs 9/9、package.mjs 4/4;Python 3.11.17 与 3.15.0rc3 的 test_project_export.py 各 8/8、test_stubs.py 各 8/8(mypy Checked 2/2 真跑,0 跳过);postgres_connect 2/2
23fa36892,Linux,SQLite schema v2 与 PostgreSQL 17 的 CLI 导出对拍(CLOUD-R3) SQLite Store 和同机 PG Store 各导出一次(files=5, directories=2, symlinks=1, bytes=2097194,进度 4 行 prepare → export → export → finalize)。src↔out-sq、out-sq↔out-pg、src↔out-pg 三组都 IDENTICAL(类型、权限、纳秒 mtime、软链目标、字节);成功后暂存目录残留 0;Store 记录里只有口令引用,home 里搜口令明文 0 命中
23fa36892,Linux(CLOUD-R3,缩范围前跑过) boundary check、guard 自测、cargo fmt --check、clippy --no-deps -p layerfs-control -p layerfs-api -D warnings、Rust calls_scope/project_family/workspace_names、root 下 control 套件(kernel_application 1/1、observed_application 8/8、r5_1_actual_daemon_commit 1/1、mount_control 9/9、kernel_mount_routes、unmount_dirty)、Python 3.11/3.13/3.15/3.14t 的 test_calls/test_project_export/test_stubs 全部 rc=0;基线 b1802332b 上的同一批 control 套件也通过,无差异
23fa36892,Mac,Docker(Colima 0.10.3 / Engine 29.5.2),bundle linux-aarch64 重打,source.head=23fa36892,hash 1b0a5401…(MAC-R3) bundle 与宿主构建 7/7;Docker worker 导出矩阵 37/37:worker 导出 main/agent 与 native 基准对拍一致、导出到已有空目录、--progress 结构校验、worker 内 project init 后再导出、11 个负例(NotEmpty/Exists×2/NoSuchStore/NoSuchProject/NoSuchBranch/相对路径/home 内路径/NotFound/66 位 hex 分支名 InvalidInput/--commit rc=2)、停机后 Unavailable 且不建目录、恢复后导出一致、暂存残留 0
23fa36892,Mac(MAC-EXEC) Python 3.11.15 与 3.15.2 的 test_calls.py(带 LAYERFS_DAEMON,含 exec 用例)各 14/14,0 跳过;Node events.mjs 2/2(含 exec output);macOS 专属 sandbox_direct_live(--features machine)2/2
26fc1ae73,Linux(CLOUD-R2) Rust calls_scope 4/4、calls_table 15/15、project_family 2/2、workspace_names 2/2、project_export 6/6;root 下 sandbox_family 1/1、CLI stream 1/1、control 套件 29/29;Node calls.mjs 3/3、project_export.mjs 9/9、events.mjs 2/2、package.mjs 4/4;Python 3.11.17 / 3.13.5 / 3.15.0rc3 / free-threaded 3.14.8t 各 test_calls 14/14、test_project_export 8/8、test_stubs 8/8(mypy Checked 2/2);free-threaded 3.13.16t 纯 Python AsyncCallbacks 7/7、export Binding+AsyncBinding 7/7、mypy 2/2;boundary(1246 个生产文件)、guard 37/37、fmt、clippy --no-deps -D warnings 通过
26fc1ae73,Mac,bundle hash beacfe62…(MAC-R2) Docker、Lima、Apple Container 三个后端:worker 导出 main(19 项)与 agent(20 项)都与 native 基准逐字节、纳秒 mtime、权限、软链一致;空目录导出、--progress(prepare → 单调 export → finalize)、11 个负例、停机 Unavailable、恢复后导出一致、暂存残留 0(Apple Container 和 Lima 各有一次失败,见下表);macOS sandbox_direct_live 2/2、Python 3.11/3.15 test_calls 各 14/14、Node events.mjs+package.mjs 6/6、test_stubs Stubs 6/6
d60dc8026,Mac(WORKER-MATRIX) 三个后端同一套矩阵(main 清单 83b3d31c…,agent 分别为 3163388d… / ce182f9f… / 81f61335…),除 Lima 冷缓存那一次外全部通过
608b9aba1,Linux PG 17.11(PG-TLS-NETLOSS) TLS(受信任 CA):sslmode=require 连接、导出、清单对拍一致(TLSv1.3);默认 prefer 同上;disable 对照通过(pg_stat_ssl 显示未加密)。导出 632,217,600 B 的夹具到约 25% 时,分别注入 pg_terminate_backend、iptables+ip6tables REJECT 5432、停 PG:三次都 rc=125、stdout 为空、错误类别 Unknown、没有 finalize、目标目录不存在、暂存残留 0、无关文件完好;PG 恢复后重新导出,与基准清单完全一致
608b9aba1,Mac 连 layerfs-test 上的 PG(异机,见 53-STATE.md) postgres_connect 2/2,导出到 Mac 本地目录通过

失败(都不是本 PR 引入的,各自有证据)

被测提交 项目 结论
3b3cb179c(本分支单独,不含 #599) Python 3.15 test_project_export.py 7/8,AsyncBinding.test_callbacks_run_on_loop_in_order_before_return 失败(events == []) 基线 aio.py 的竞态,#599 修复;合并树上 8/8
26fc1ae73(AC-FLAKE 专项) Apple Container 上背靠背导出 9.4 MB:255 次失败 91 次(36%;两组各 100 次分别 35、29 次)。报错 Unknown: … the worker's answer was lost (worker connection: failed to fill whole buffer) … was not resent。同一份代码在 Docker 上 130/130 成功 Apple Container 的发布端口转发丢了数据:guest 侧整份 12.6 MB 都写出并被 ACK,宿主只收到约 6.2 MB。不是本 PR 引入的(store.pull 也被同样截断)。产品行为符合契约:不重试、报 Unknown、目标为空、无残留
26fc1ae73 / d60dc8026 Lima 冷缓存时第一次 machine create 报 limactl create did not end within 30 s;镜像缓存预热后通过 基线 layerfs-machine 的 30 s 调用超时,与导出无关,另案处理
26fc1ae73 / 23fa36892 不加 --no-deps 的 clippy rc=101:layerfs-persistence/src/backend/mod.rs:10 unused import: ORDINAL_END 上游已有(基线同样失败);受影响的 crate 加 --no-deps 后 0 warning
c71f89215 测试组(R3-FOLLOW) 同一进程内并行跑整个测试文件时,偶尔出现 Store open: Store busy before effect 上游已有:没改过的 HEAD 跑 80 次也复现 1 次
608b9aba1 PG sslmode=verify-full / verify-ca 报 Failed: making the PostgreSQL Store: Malformed 驱动限制,见「已知限制」
608b9aba1 对照组:PG 用不受信任的自签名证书时,require 和默认模式都报 Malformed 符合预期(证书校验在生效),归类问题是 layerfs-project#100
26fc1ae73 / 23fa36892 非 root 跑 sandbox_family / kernel_application rc=101 需要 root(namespaces、/dev/fuse),root 下通过,与基线一致

未运行(原因)

项目 原因
PG schema v1 Store 被导出拒绝 没有测试(文档写了,见 3.0.1 建议 1)
PG TLS、断连、异机导出在 schema v2 之后的提交上复测 最近一次是 608b9aba1;23fa36892 上只跑了同机 PG 的 CLI 导出对拍与 postgres_connect
Lima、Apple Container 在 23fa36892 上的矩阵 按范围只跑 Docker;最近一次三后端是 26fc1ae73
云机上的 Sandbox/exec 用例(23fa36892) 云机缺 guest bundle sandbox-image.tar;Mac 上 23fa36892 已跑通(MAC-EXEC),云机 26fc1ae73 也已跑通
Mac 上 test_stubs 的 Checked 2 项(26fc1ae73) Mac 没装 mypy;云机上 mypy 已真跑
容器内磁盘写满(ENOSPC)、跨容器断网 没做真机注入;进程内写失败中断已在 project_export.rs 覆盖,PG 中途断连三种已覆盖
旧 bundle 配新宿主(混合版本) 未测
全工作区 cargo test 只跑了受影响的 crate 和测试
Durable persistence profile NOT_RUN — disabled by owner until explicit reauthorization
Windows 不在本 PR 范围

已知限制(本 PR 不处理)

  1. sslmode=verify-full / verify-ca 用不了:Cargo.lock 锁定的 tokio-postgres 0.7.18 只认 disable/prefer/require,连接串在解析阶段就被拒,然后被映射成容易误导的 Malformed。这是驱动限制。
  2. require 也校验证书链(native-tls 默认策略,和 libpq 不同),自签名证书要先加进系统信任库,否则报 Malformed(归类问题见 layerfs-project#100,不阻塞本 PR)。三种断连都报成同一句 Unknown: provider failure: Store object demand: storage failure,分类正确,但消息里看不出原因。
  3. Apple Container 的发布端口转发会截断大流量 worker 调用:9.4 MB 导出背靠背约 30% 失败,Docker 上 0/130。不是本 PR 引入的(store.pull 也会被截断)。在 Apple Container 上,大流量导出建议改用 Docker 或 Lima 机器。
  4. free-threaded Python 3.13t 不能用原生扩展:上游锁定的 pyo3 0.30.1 不支持 3.14 以下的 free-threaded CPython,上游已有;纯 Python 部分和 mypy 在 3.13t 上通过,3.14t 上原生扩展通过。
  5. 上游已有的 clippy 告警:layerfs-persistence 的 unused import: ORDINAL_END。
  6. project_export 测试偶发 Store busy before effect:并行跑时低概率出现,没改过的 HEAD 上同样复现(80 次 1 次),上游已有。
  7. Durable 按维护者要求禁用,没有运行。
  8. Lima 冷缓存首次 machine create 会超过 30 s 超时,属基线行为,另案。

风险

  • 新增一条跨层调用(call table → control → worker 协议),连接时按 bundle hash 做 worker.hello 校验。只验证了宿主和 bundle 同源的情况;旧 bundle 配新宿主没有测,按现有协议推断会被拒(stale_bundle),不会静默降级。
  • 进度事件的频率有上限,但超大文件产生的事件数仍会与分块数成正比;total 恒为 null,调用方不能假设有百分比。
  • 导出持有共享租约期间,store.remove / store.push 会返回 InUse,行为变化只出现在这几个调用并发的时候。
  • 文档改动较多(call table、front-ends、versioned/2.0.0),以后和别的 PR 可能改到同一段文字,属合并顺序问题。

…gress (Ephemeral-AI-Lab#53)

Implement project.export(project, destination, { branch = 'main', on_progress }) across the call table, layerfs-control, worker protocol, CLI/Node/Python front-end tests, and 2.0 architecture/SDK documentation:

- Pin the selected Branch snapshot once (main published Layer or Branch head Commit/base Layer) and stream tree::Record parts through a shared local StagingGuard (.layerfs-export-<id>) before atomic rename publication.
- Stream worker-backed SQLite exports over 'project.export'; immediately abort and close the worker stream on local write errors (Capacity, Conflict, etc.) and propagate event write failures on the worker side so snapshot traversal stops immediately.
- Enforce release-level verification between LocalWriter counts (files, directories, symlinks, bytes) and snapshot/worker counts before atomic publication on both in-process and worker paths.
- Emit files, directories, symlinks, bytes, done and total across prepare, export and finalize progress events, and use neutral 'the Store home' wording in destination refusal messages.
- Cover shared Store lease concurrency (file.read, concurrent project.export), exclusive Store operation refusals (store.remove, store.push -> InUse), Busy/Unresolved Store admission, and mid-export project.remove snapshot isolation in tests/project_export.rs.

Production LOC: 137,010 -> 137,978 (delta +968)
- Scope: first-party product source counted by python3 -B tools/production_loc.py --detail comparing parent d430474 to committed tree.
- Subtotals:
  - core: 38,400 -> 38,400 (delta 0)
  - engine: 62,799 -> 62,799 (delta 0)
  - connect: 15,947 -> 15,947 (delta 0)
  - api: 19,864 -> 20,832 (delta +968: layerfs-api 1,434 -> 1,450 [+16], layerfs-control 17,521 -> 18,473 [+952])
  - reference: reference absent (retired R9c; last counted 65,417 at tree 498dd19)
- 执行 api/scripts/gen-node-types.mjs 与 api/python/tools/gen_stubs.py,从包含 62 个调用(新增 project.export)的调用表重新生成 api/node/src/index.d.ts、api/python/src/layerfs/_client.pyi 与 aio.pyi
- 同步更新 docs/architecture/api/front-ends/python.md 中 test_stubs.py 的 62 sync/async methods 计数
- 补齐 docs/architecture/api/sdk/project/ 下 get.md 与 remove.md 的底部翻页链,将 project.export 纳入单向遍历链
- 在 families.md、routing-table.md、workers.md 三张核心表中补列 project.export
- 同步更新 docs/architecture/README.md、glossary.md、flows/call.md、api/README.md 以及 layerfs-js-sdk skill 文档中的 62 calls 与 project 调用列表

Production LOC: 140373 -> 140373 (delta 0)
Scope: core 38811, engine 63682, connect 16068, api 21812; reference absent (retired R9c; last counted 65,417 at tree 498dd19).
Method: python3 -B tools/production_loc.py --json on parent 89b6213 and committed tree (generated stubs and documentation excluded).
docs/versioned/2.0.0/README.md 的第 27、44、59 行仍写 61 calls,而同目录的
calls.md 与 sdk.md 在 Ephemeral-AI-Lab#53 之后已是 62,手册首页与正文对不上。按
LP53-STUBS-REVIEW 的 R1 一并改为 62。

全仓 grep 后仍有两处 61 calls:core/docs/issues/536/README.md 与
core/docs/issues/536/DECISIONS.md,均为历史决策记录,按报告要求保持原样。

生产 LOC: 140373 -> 140373 (delta 0)
统计范围:core、engine、connect、api 四个分层的产品源码(含运行期 SQL 与
JavaScript),不含测试、文档、工具与第三方代码。计数方法:
`python3.11 -B tools/production_loc.py`(与父提交同一计数器与范围)。
本次只改文档,产品代码未变。

验证:`git diff --check` 退出码 0;全仓 grep 已无残留的 61 calls(仅上面
两处历史记录);`python3.11 -B tools/check_product_boundary.py` 输出 PASS。
按 LP53-R3-REVIEW 的 S1、S2 执行,只改测试和文档,不改产品代码;S3 是上游本身
的文案问题,未做。

- S1:新增 symlink 导出行为覆盖。同一个 symlink inode 的两个名字
  (linkat 不传 AT_SYMLINK_FOLLOW,Linux 与 macOS 都链到 symlink 本身)、两个名字
  只共享同一 target、以及指向导出树外的绝对 target。断言每个名字各自成为一个
  destination 条目并保留原 target、分别计入 symlinks、共享 inode 的 mtime 在两个
  导出名字上都在、绝对 target 不被跟随(树外文件未被改写)。按
  docs/architecture/api/sdk/project/export.md 现有承诺,不断言 hard-link identity:
  source 侧先断言夹具确为一个 inode 两个名字,destination 侧不做 identity 断言。
- S2:新增 v1 Store 负向测试。把已初始化的 Store 的 SQLite 头部 user_version 改写
  为 22(schema version 1)后调用 project.export,断言:以 Failed 拒绝、消息点名
  schema version 1 与离线转换 tools/store_blocks.py migrate、没有任何 prepare 事件、
  原本存在的空 destination 仍为空、父目录下没有 .layerfs-export-* 残留、源 Store
  未改动(版本与长度不变)。仓库没有 rusqlite dev-dependency(加它需要改
  Cargo.lock),故测试直接改写头部字段并在测试内回读校验。
- S2 文档:export.md 新增 "Store format prerequisite" 小节并交叉链接 SQLite、
  PostgreSQL 与 Store lifecycle 的格式说明,注明旧 SQLite v1 会给出离线转换指引、
  PG v1 同样在 open 被拒(Integrity),且该 SQLite 工具不是 PG 迁移工具;Errors 表
  与说明补充该拒绝发生在 prepare/staging 之前。
- 顺带把 populate_sample 里的 set_mtime 闭包提成模块级 helper 供新测试复用,行为不变。

验证:cargo +1.85.1 test --locked -j 2 -p layerfs-api --test project_export
(本 worktree 自己的 CARGO_TARGET_DIR)8 passed / 0 failed;git diff --check、
tools/check_product_boundary.py 通过;rustfmt --check 干净。PostgreSQL、真机/VM/
容器 Worker 导出与 Durable 未运行(Durable NOT_RUN — disabled by owner until explicit
reauthorization)。既有 suite 在同一进程内并行运行时存在极低概率的
"Store open: Store busy before effect" 抖动:未改动的 HEAD 版本 80 次里同样复现
1 次,不是本次引入,也未在本任务里改产品代码。

Production LOC: 142081 -> 142081 (delta 0)
Scope: 首个 API 层产品源码范围 core/crates、engine/crates、connect/crates、api 及随包
运行时 SQL;本次只改 api/crates/layerfs-api/tests/ 与 docs/,产品代码零改动。
Method: tools/production_loc.py --json(本 worktree 树;reference absent,retired R9c,
last counted 65,417 at tree 498dd19)。
Copilot AI balanced review requested due to automatic review settings November 6, 2026 17:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@yifanxuaaa
yifanxuaaa merged commit abc4606 into Ephemeral-AI-Lab:layerfs_v2_0_0 Nov 7, 2026
2 of 4 checks passed
yifanxuaaa added a commit that referenced this pull request Nov 7, 2026
feat(project): project.export, ported from #600, with review fixes (layerfs-project#53)
NelsonLongxiang pushed a commit to NelsonLongxiang/layerfs that referenced this pull request Nov 8, 2026
…rt and fixes (layerfs-project#53)

core/docs/issues/project-53/PR600-PORT.md records the author's commits
and production LOC (+968), the port onto layerfs_v2_0_0 (+1,069 against
the base), the three fixes, the review findings withdrawn (setuid/setgid
cannot reach a Store; c71f892's LOC line is correct), checks run and
not run, and what stays open (PR Ephemeral-AI-Lab#599 first; Apple Container truncation).

Production LOC (tools/production_loc.py d3148db88f91, whole tree,
tests excluded): 144,952 -> 144,952 (delta 0), docs only.
Reference absent (retired R9c; last counted 65,417 at tree 498dd19).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants