Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion llmdoc/architecture/dag-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,13 @@ Operator-visible input 排除集合(skip 控制字段 + `common_input_template
- pine-go / pine-java:`BuildInput` 阶段构建 `common` map 时**直接丢弃**排除字段(materialize-time exclusion),`input.Common(field)` 在字段名不在 map 中时返回 nil。
- pine-cpp:`OperatorInput` 是懒代理,`common(field)` 直查 frame——**必须在读路径显式 gate** 排除集合(`InputFieldSpec::excluded_common`),否则算子看到 raw frame 值。issue #174 首次暴露该差异:`reorder_shuffle_by_salt` 以 `metadata.common_input` 构 salt,pine-cpp 未 gate 时读到 skip 字段 `_skip_branch=false` 而 pine-go/pine-java 读到 nil,salt 分歧 → 排序分歧 → 下游整链 cascading。

**跨运行时不变量**:任何 op 通过 `input.common(field)` 访问排除集合内的字段名,都必须收到 nil。materialize 侧靠 build-time 剔除保证,proxy 侧靠 spec.excluded_common gate 保证。给 spec 加新的排除维度时(新增 skip 桶、template 桶等)需逐一核对每种实现是否都把该维度带进 excluded_common。
**跨运行时不变量**:排除字段不得通过三个消费面向算子泄漏:

- 值访问:任何 op 通过 `input.common(field)` 访问排除集合内的字段名,都必须收到 nil。materialize 侧靠 build-time 剔除保证,proxy 侧靠 `spec.excluded_common` gate 保证。
- 字段名元数据:传给算子 init 的 `metadata.common_input` 不得包含顶层 `skip` 控制字段。pine-cpp 在实例 init 前过滤字段名,但 DAG 依赖推导仍读取过滤前 metadata,避免改变调度边。
- 观测快照:debug/trace 输入快照必须使用与算子值访问相同的三桶并集;`[pine-debug]` 与 `_return_trace` 不得显示算子本身不可见的 raw frame 字段。

给 spec 加新的排除维度时(新增 skip 桶、template 桶等),需逐一核对值访问、字段名元数据和观测快照,而非只验证 `OperatorInput` 的读取结果。

#### BuildInput 错误消息约定

Expand Down
2 changes: 1 addition & 1 deletion llmdoc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

## architecture/

- `llmdoc/architecture/dag-engine.md` — 核心引擎架构:配置编译流水线、DAG 推导规则(三标记 + auto-inject 模型:ConsumesRowSet/MutatesRowSet/AdditiveWritesRowSet 标记与 item 字段自动注入)、调度模型、DataFrame 语义(含 InputFieldSpec 三态模型:Nullable/Strict/Defaulted)、算子类型约束、行集依赖行为,以及引擎级 option / 根级配置注入(含 debug nullable 三态继承)、Server struct 生命周期与 context 传播、服务端 reload 集成与 HTTP middleware 包装边界、双通道运行时观测、ExecutionError/PanicError 因果链(三运行时 cause chain parity)、资源数据型(snapshot 导出)/句柄型(borrow 借用,如 redis_connection)区分、Pine-Java 完整功能对等描述、接受的跨引擎设计差异归档(如 issue #91 Lua VM pool 上限/GC 回收语义不对等:指标层 5 元组对等 + 端到端 calibrated 持平 + 生产无 OOM 痛点 + 跨语言机制无可移植近似 → 接受差异,重启触发条件为生产 RSS 单调爬升数据;issue #169 Java routeHandler 抛/返回二分 vs Go 统一 err 传 Egress)、跨运行时 operator-visible input 排除集合契约(skip/template/common_input_skip 在 pine-go/pine-java 走 materialize-time 剔除、pine-cpp 走 proxy 读路径 gate,issue #174)。
- `llmdoc/architecture/dag-engine.md` — 核心引擎架构:配置编译流水线、DAG 推导规则(三标记 + auto-inject 模型:ConsumesRowSet/MutatesRowSet/AdditiveWritesRowSet 标记与 item 字段自动注入)、调度模型、DataFrame 语义(含 InputFieldSpec 三态模型:Nullable/Strict/Defaulted)、算子类型约束、行集依赖行为,以及引擎级 option / 根级配置注入(含 debug nullable 三态继承)、Server struct 生命周期与 context 传播、服务端 reload 集成与 HTTP middleware 包装边界、双通道运行时观测、ExecutionError/PanicError 因果链(三运行时 cause chain parity)、资源数据型(snapshot 导出)/句柄型(borrow 借用,如 redis_connection)区分、Pine-Java 完整功能对等描述、接受的跨引擎设计差异归档(如 issue #91 Lua VM pool 上限/GC 回收语义不对等:指标层 5 元组对等 + 端到端 calibrated 持平 + 生产无 OOM 痛点 + 跨语言机制无可移植近似 → 接受差异,重启触发条件为生产 RSS 单调爬升数据;issue #169 Java routeHandler 抛/返回二分 vs Go 统一 err 传 Egress)、跨运行时 operator-visible input 排除集合契约(值访问、init 字段名元数据、debug/trace 快照三个消费面,issue #174)。
- `llmdoc/architecture/apple-compiler.md` — Python DSL 架构:Flow 声明 API、SubFlow 契约声明与编译期强制(`common_input`/`common_output`/`item_input`/`item_output` 在 issue #78 落地为 subtree-scoped 字段覆盖 + 死代码校验,未声明契约的 SubFlow 自动继承外层;`required_resources` 沿用 issue #37 校验)、编译流水线(含 step 8b `_validate_subflow_contracts`)、校验规则(含 `validate_write_without_read` 对 `AdditiveWritesRowSet` 算子的同字段豁免,issue #72)、控制流降级(含 `_rename_field` Lua `_G[]` 语法处理)、资源声明处理、根级配置字段扩展路径(如 `storage_mode`、`log_prefix`、`debug`),以及 row-set 标记三元组(`consumes_row_set` / `mutates_row_set` / `additive_writes_row_set`)通过 `apple_generated/markers.py` 表填充 `OpCall`、True-OR widen 合并语义、`_apply` 与 `_add_op` 的刻意非对称(仅 `consumes_row_set` 暴露给 DSL 调用点)。
- `llmdoc/architecture/pine-cpp-runtime.md` — Pine-C++ 运行时架构:作为标杆运行时的定位、错误/fixture parity 契约、CLI 与 HTTP 入口(含 HTTP/1.1 keep-alive / read-header-timeout / idle-timeout / max-body-size / middleware / graceful shutdown / 客户端断连取消 eventfd 零延迟唤醒 / custom Route 与 Watch 的"黑盒行为对等、实现结构自由"决策——不做 Go/Java 嵌入 API、可测校验逻辑抽 socket-free routes.cpp)、codegen 入口(`-schema-json` schema 导出 + `-output` 发射完整 Apple DSL 产物集与 Go/Java 字节级一致 + `-doc-dir` 发射算子文档 markdown 与 pine-go byte-equal、`OperatorSchema.metadata` 字段显式声明、`format_g` 对 |d| > LLONG_MAX 的 UB 守卫与 Ryu/Grisu 路由点、ResourceSchema 全局注册表与 `reset_resource_schema_registry`/`reset_all_resource_registries` 拆分语义)、`metrics::Provider` 与 `resource::Manager` 对等(`ResourceValue` 数据 `Variant` XOR 句柄 `shared_ptr<void>` 双通道,数据型走 `snapshot()`、句柄型走 `borrow()`,RAII 拆除)、Frame 多态基类 + ColumnFrame/RowFrame 双物理实现(C++23,per-call 锁形态与 Go/Java 对齐、`pine::SharedMutex` 备件)、Column 类型层级、`PINE_REGISTER_OPERATOR_T` 注册模型、ValidateOutput 类型约束、NaN/Inf 校验、PanicError stacktrace、外部 stop_token 取消、ready-queue DAG 调度器(双隔离线程池 + in-degree 原子追踪)、observe_log/pine-debug 日志、Redis client 失败收敛与 SIGPIPE 守卫(`MSG_NOSIGNAL` + AUTH/SELECT close fd)+ per-command 指标 `run_command<T>` 模板(错误类型分层 known follow-up)、`OperatorOutput` 缓冲区复用(`node_body` 用 `thread_local` 而非对象池——ready-queue 不迁移半完成节点故省掉 Get/Put 记账;acquire 与 node body 尾部**两侧都 reset**,承重的是尾部那次(在 `try/catch` 之外、成功与抛异常都覆盖),acquire 侧现为 defence in depth;`reset()` 用 `clear()` 保住 heap capacity 并对超 `kRetainLimit` 的容器释放;spine 上限不含元素 payload,issue #122)。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@
- 由 recorder 把前三条 promotion 写进对应稳定文档并同步 `index.md`;lazy proxy 实现差异那条建议放在 `architecture/dag-engine.md` "BuildInput 语义"节,与现有 lazy proxy 描述并列一段"实现差异清单"。
- 下次 nightly artifact 复现走弯路超过 30 分钟时,条件反射式切"从末端逐算子截断"策略,不要继续深挖末端错误路径。
- pine-java `TransformByLua.java` 的 `is*()` 派发点现已全部为 type-tag 派发(table-key check / fromLua / snapshotKeys),三处闭环;下次再触碰该文件时不需要额外扫。若 pine-java 后续加新 Lua bridge 代码,仍需 grep 全部 `is*()` 调用逐个判定 coercion-or-tag(与 #175 反思同款要求)。

## Review Follow-up

- 后续 CI differential fuzz 再次命中同族分歧:只在 `OperatorInput::common` 隐藏排除字段的值还不够。算子若遍历 init 时收到的 `metadata.common_input`,仍会看到 skip 字段名并改变 salt/hash 形状。pine-cpp 因此在 `Engine` 构造、调用 `instance->init(op_cfg)` 前过滤顶层 `skip` 字段名;DAG 仍使用过滤前 metadata 推导依赖。
- debug/trace 是第二个独立消费面。pine-cpp `snapshot_input` 必须使用 `skip ∪ common_input_skip ∪ common_input_template`,否则算子虽然读不到排除字段,`[pine-debug]` 和 `_return_trace` 仍会泄漏 raw frame 值。
- 可复用教训:输入排除契约要沿“值访问、传给算子的字段名元数据、观测快照”三个消费面逐一验证;只修首个暴露分歧的读路径会留下同族旁路。
2 changes: 1 addition & 1 deletion llmdoc/reference/operator-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ C++ 侧 `OperatorInput`(`include/pine/operator_input.hpp`)是 Frame + InputF
- **Sequence 检测严格性**(pine-go):`fromLua` 要求 `1..N` 严格连续才识别为 array,遇到 `nil` 中断即降级为 map(避免误判稀疏数组)。
- **错误前缀去重**(pine-go):`fromLua` 的内部错误已带 `lua:` 前缀,外层 `executeForItem` / `executeForCommon` 不再二次包裹。

`fixtures/operators/transform_by_lua_tables.json` 与 `scripts/differential-fuzz.py` 的 `LUA_ITEM_FUNCTIONS` table-aware 用例(`#item_tags`、`for i=1,#item_vals`、return `{a, b}`)覆盖该转换路径,由 differential fuzz 与 cross-validate 持续验证。标量类型身份路径由 `fixtures/pipelines/lua_string_number_identity.json` 与 fuzzer 的 `LUA_IDENTITY_ITEM_FUNCTION` + flow_contract 投影(使字段值进入差分比对面)覆盖。issue #174 的 skip-field-in-common_input 契约由 `fixtures/pipelines/shuffle_salt_reads_skip_field.json` 钉住:`reorder_shuffle_by_salt` 用 `metadata.common_input` 构 salt 时,`skip` 列表中的字段必须对算子的 `input.common(field)` 不可见,三运行时(pine-go / pine-java / pine-cpp)字节级一致输出
`fixtures/operators/transform_by_lua_tables.json` 与 `scripts/differential-fuzz.py` 的 `LUA_ITEM_FUNCTIONS` table-aware 用例(`#item_tags`、`for i=1,#item_vals`、return `{a, b}`)覆盖该转换路径,由 differential fuzz 与 cross-validate 持续验证。标量类型身份路径由 `fixtures/pipelines/lua_string_number_identity.json` 与 fuzzer 的 `LUA_IDENTITY_ITEM_FUNCTION` + flow_contract 投影(使字段值进入差分比对面)覆盖。issue #174 的排除契约由 `fixtures/pipelines/shuffle_salt_reads_skip_field.json` 与 `fixtures/pipelines/shuffle_salt_reads_common_input_skip.json` 钉住:`reorder_shuffle_by_salt` 用 `metadata.common_input` 构 salt 时,排除字段的值和顶层 `skip` 字段名都不得进入算子可见输入;debug/trace 快照也不得泄漏同一排除集合

### Lua Pool Baseline 重置契约(仅覆盖字符串键 globals)

Expand Down