Skip to content

L2 ETLPipeline 在本仓无任何执行侧消费者(仅 spec 自身 + 生成文档),而 SYNC_ARCHITECTURE.md 把它作为 L1 退役后的推荐去处 #6414

Description

@os-zhuang

发现于 #6384(修 SYNC_ARCHITECTURE.md L3 字段映射值转换措辞,PR #6395)的邻域扫描,不在该 PR 范围内,故单独记录。

事实(origin/main @ c78be03)

packages/spec/src/automation/etl.zod.ts 的 ETLPipelineSchema / ETLTransformation 在本仓没有任何执行侧消费者。

$ grep -rln "automation/etl\|ETLPipeline" packages apps --include=*.ts --include=*.tsx | grep -v "^packages/spec/"
apps/docs/.source/browser.ts
apps/docs/.source/server.ts

两处命中都是 fumadocs 生成的文档源,不是执行器。packages/spec 内部的引用只有 migrations/registry.ts、scripts/build-docs.ts 与自身测试。

补充读数:

  • packages/spec/liveness/ 下没有 etl.json / pipeline.json —— 该面未进入 liveness 账本,所以 Spec property liveness 门禁对它没有读数。
  • 同目录的 mapping.json 存在,并且 shared/mapping.zod.ts 的模块 TSDoc 明确把 import mapping 的 transform 描述为"applied row by row by the REST import path and recorded live, key by key, in packages/spec/liveness/mapping.json" —— 即同一文件家族里,被执行的那一面有账本,ETL 这一面没有。

为什么值得记

SYNC_ARCHITECTURE.md 把 L2 ETL 当作在役的一层在推荐,而且是 L1 退役时指定的去处。文档 L34-40(#4738 写的):

**What to use instead:**
- **Transformation pipelines** — `ETLPipeline` (`automation/etl.zod.ts`) for
  multi-source, multi-stage data movement.

而 #4738 退役 L1 DataSyncConfig 的理由正是"narrative-only:no engine ever parsed, scheduled or executed a DataSyncConfig —— the schema had zero importers across objectstack, cloud and objectui"。L2 现在的读数与当时 L1 的判据同型:零执行侧 importer。

文档同时在 L158-171 的 ### Transformation Types 表里逐行宣传十种 transformation(含 script | Custom JavaScript/Python | return row.price * 1.1),这是一份具体到能照抄的能力清单。#6384 的 PR #6395 刚刚在同一文件里把 L3 字段映射的值转换措辞改成如实说法,并把作者引向"L2 ETL transformation step"——如果 L2 本身也没有执行器,那条引导指向的是另一个不执行的面。这是我在那个 PR 里没法自行裁定、也不该顺手改的部分。

我测了什么、没测什么(请勿据此直接动手)

测了:本仓 packages/* / apps/* 的 TS/TSX 标识符引用;packages/spec/liveness/ 目录清单;/home/user/cloud 与 /home/user/objectui 两个同级 checkout 的同名 grep(均无命中)。

没测:

  • 两个同级仓的 checkout 是否处在与 origin/main 一致的状态 —— 结论不应只靠我这次的本地读数。
  • 是否存在非 TS import 的消费路径(JSON 元数据装载、os CLI 的 metadata root 注册、插件契约按名解析)。etl 作为字符串出现在 migrations/registry.ts,我未展开该链路。
  • ADR-0049 的账本里是否已有对该面的裁定记录。

因此这是观察类,不是已定性的缺陷:今天没有用户会看到报错(作者写一份 pipeline,得到的是静默不执行 —— 这恰恰是 ADR-0078 命名的那种不对称,但要断言"确实无执行器"需要补完上面三项)。按 objectstack#4949 的分级,打 finding、不打 pm:queue、不指派,严重度请 PM 复核 —— filing 时刻的严重度判断两个方向都不可靠。

若确认为 dead,可选路线(不预设结论)

  1. 建执行器 —— 若 ETL 是真实业务方向(需要有实际业务拉力的证据:谁在写 pipeline、哪个部署在跑)。
  2. 按 ADR-0049 enforce-or-remove 退役 —— 与 L1 同样处理,并把 SYNC_ARCHITECTURE.md 的推荐去处改掉。
  3. 先补 liveness 账本读数 —— 成本最低的一步,把这一面纳入既有门禁,让裁定有数据而不是靠一次性 grep。

我倾向 3 作为下一步(它不预判 1/2,且把判断建立在持续读数上),但这是维护者的裁定,不是我的。

参考


Generated by Claude Code

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Findings triage — PROMOTE, scoped to route 3 only. finding → pm:queue; domain:spec kept.

    Stale-premise check. packages/spec/src/automation/etl.zod.ts has no commits since filing, and the ledger directory on origin/main still contains no etl.json and no pipeline.json — 28 ledger files, mapping.json among them, this face absent. The asymmetry the body rests on is real and current: within the same file family, the executed side (shared/mapping.zod.ts) has a ledger and says so in its own module TSDoc, and the ETL side has neither.

    What is dispatchable, and why it is dispatchable despite the body's own caveats. The filer correctly refused to assert "no executor" on a single grep, listing three unmeasured things. All three are mechanical measurements, not judgements: (1) re-run the sibling-repo greps against origin/main rather than whatever the local cloud / objectui checkouts happened to be at — Operational note 4 exactly (git grep <pat> origin/main, never the shared working tree); (2) chase the non-TS consumption paths the body names — JSON metadata loading, os CLI metadata-root registration, plugin contracts resolving by name, and specifically the etl string in migrations/registry.ts, which is the one link the filer explicitly did not expand; (3) check whether ADR-0049's ledger already records a verdict for this face. That is a card with a definite completion, and it produces exactly the evidence any later ruling would need.

    Route 3 is the whole scope. Routes 1 and 2 are explicitly out of it. Building an executor needs business pull the repo cannot supply, and retiring a shipped schema under ADR-0049 enforce-or-remove is a maintainer decision with its own playbook. The implementing seat's completion is the reading plus the ledger entry, and if the measurement lands on "dead", the correct output is a needs-user-decision card carrying the evidence — not a retirement PR, and not an edit to SYNC_ARCHITECTURE.md.

    One live consequence to carry into that card rather than act on now. SYNC_ARCHITECTURE.md L34-40 names ETLPipeline as the replacement for retired L1 DataSyncConfig, and PR #6395 (#6384) has just pointed authors at the "L2 ETL transformation step" for value transforms. If L2 has no executor, both signposts route authors to a second inert face — and #4738 retired L1 on a judgement of the same shape ("narrative-only: no engine ever parsed, scheduled or executed a DataSyncConfig; zero importers across all three repos"). That parallel is the reason this is worth measuring now rather than holding, and it is also the reason nobody should edit those docs before the measurement returns.

    Lane note, recorded rather than acted on. domain:spec is kept deliberately: the work is ADR-0049 liveness bookkeeping on packages/spec's own enforcement account, and the ruling it feeds is an accepted-face question. It is not spec-surface (no describe/JSDoc text is at stake) and it is a genuine borderline against spec-tooling (packages/spec/liveness/** is gate input). Flagging the boundary here so the spec seat can bounce it back if it reads the ledger as machinery — this seat does not re-tag on a coin-flip.

    Refs already checked, non-duplicating: #4738 (L1 retirement, the shape precedent), #5552 / PR #6078 (FieldMapping.transform, same "no executor" reasoning), #6384 / PR #6395 (the discovery site).

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    Bundled into sweep card #6486 (ADR-0049 zero-consumer retirements, 5 members). Keeps pm:queue but is excluded from batch selection while #6486 is open — claim the sweep card, not this one; it closes via Fixes when that PR merges. ⚠️ Member-specific requirement: SYNC_ARCHITECTURE.md currently recommends ETLPipeline as the post-L1-retirement destination — that prose is corrected in the same PR, or the retirement contradicts the doc.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions