docs(contributing): make first-contribution cost visible and smaller - #5086
Conversation
- state the Node.js >= 22.22.3 runtime in pyproject metadata and in the CONTRIBUTING prerequisites, with npm ci as a one-time setup step - collapse the missing-npm-dependency failures into one named remedy: the TypeScript semantic scan detects a missing typescript package or node binary, and pytest prints one loopx setup line at the end - map all 14 workflows to trigger, merge blocking and purpose; only Sign-off and merge-gate block a merge - define when a change needs an RFC and how a compact RFC is sized - add a Code Map convention for capability READMEs, starting with decision_context, guarded so a map cannot go stale - guard Node minimum consistency across README, CONTRIBUTING, pyproject, install guide, entrypoint, package.json and workflow pins Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
结论:APPROVE。未发现阻塞项。 评审对象为完整 PR,head 2d253802b51cbffd70e673acb1abea254d21d515,对照基线 71dbfd5e605da4e7efdb58c87cd3f4a96d39e0e5。相关修改的正向路径、缺依赖失败和恢复均经过真实 Node/pytest 进程验证。
动机
这次改动解决的是首次参与者的具体障碍:开发前需要什么、失败后如何恢复、平时跑哪些检查、完整验证的成本在哪里。原来的语义扫描在缺少 Node 时抛出系统异常,在缺少 TypeScript 时只给出笼统的解析器错误;大量失败之后也没有集中显示修复命令。现在指南、错误信息和末尾提示构成一个可完成的贡献者路径。这个范围内的目标已达到,持续维护和使用体验都有改善,无须把它扩大成新的安装产品。
改动思路
入口仍是 CONTRIBUTING、现有语义扫描器和 pytest。Node 最低版本仍由现有常量拥有;工作流和模块列表从当前仓库读取,避免手工维护第二份事实。扫描器只在原有错误边界识别依赖问题,结构化语法错误仍先处理。pytest 汇总提示只影响终端呈现,不改变失败报告、退出码或测试选择。RFC 门槛放在既有架构说明里,代码地图也是能力 README 的可选约定,没有新增能力、provider、CLI 或持久状态。
具体改动
完整 diff 涉及贡献指南、RFC 门槛、能力代码地图约定、Decision Context 双语代码地图、包描述、扫描诊断、pytest 提示及定向测试。文档说明 Node 前提、uv/npm 源码环境、快速迭代与完整检查的区别,并列出所有工作流和 merge-gate 依赖。代码地图把 source/provider、assembler、capture、render 等既有职责画清楚;新的检查将实际模块集合与英中文地图比较。它不要求其他能力强行新增地图。包描述补充源码开发需要 Node 的事实,没有改变安装依赖或最低版本。
关键代码讲解
loopx/semantics/production.py:125的run_typescript_scan:空输入仍直接返回;非空输入先寻找 Node,再调用真正的 TypeScript parser。结构化语法错误优先,随后才识别缺少 TypeScript;任意 stderr 不会被直接回显。tests/conftest.py:121的报告和结束 hooks:以 nodeid 去重共享设置失败,在测试总计后显示一次修复提示。两个失败仍是两个失败,安装依赖后正常通过。tests/test_contributing_guide.py:34:将用户会看到的最低版本与既有运行时常量比较,并检查 package engines、工作流完整集合和 merge-gate 依赖。版本主线的 CI 配置与精确最低版本固定值作了区别。tests/test_capability_code_maps.py:34:只检查已经采用地图的能力,列全顶层 Python/TypeScript 模块和子包;Decision Context 的中文地图必须与英文集合一致。
对主干的风险
最强反例是“测试通过,但提示掩盖了真实解析错误,或把缺依赖测试变成跳过”。真实进程验证排除了这个反例:缺 Node 和缺 TypeScript 的诊断更具体;安装依赖前两个用例退出失败,安装后两个通过;无效 TypeScript 的路径、行号和错误优先级与基线一致,成功 AST 行也一致。字符串识别只生成诊断提示,不是状态或交付规则;不同自定义 loader 格式可能退回既有的安全通用错误,不会获得新的通过权限。
38 项定向测试、778 项架构测试、修改文件 Ruff、语义模块 mypy、文档治理/语义词汇/Decision Context 三项 smoke,以及风险选择的 18 项 canary 检查均通过。仅读取了主分支 required-check 规则以核对指南;按当前评审策略没有读取或等待远端 CI。没有配置变更,因此无须 frontend/Lark 编辑器伴随修改。相关 #5075 若增加模块,后合入的一方需要同步两份代码地图。
语义与 CI 对齐
这次复用现有 Node 和 AST 语义,没有新增控制面词汇或降低义务。快速检查是迭代建议,完整检查仍是 ready 前的要求;可选地图一旦采用,集合一致性由 pytest 强制。指南对 required checks 的说明与主分支规则一致;本结论不等于 merge readiness 或合并授权。
我的整体评价
APPROVE:长期维护成本和贡献者恢复体验均改善,实际调用路径完整,规模与问题相称。未来维护方向已经通过复用诊断 owner 和源文件派生检查落实;在当前显示提示范围内再增加错误协议或独立 onboarding 框架没有收益。剩余限制是没有覆盖全部 Python/Node 版本组合,以及相关模块新增时需要正常更新地图;这些不阻塞当前 head 的审查结论。
English verdict: APPROVE - head 2d25380. Existing owners are reused; real base/head Node and pytest failure/recovery paths preserve successful parsing and syntax diagnostics. Focused tests, 778 architecture tests and local risk-selected checks passed; remote CI was not consulted. No merge authority is granted.
Why
The core LoopX contracts are worth their cost. But a first contribution pays several costs that are not written down anywhere, or are larger than they need to be:
pyproject.tomlsaysdependencies = []and "lightweight", yet everyloopxcommand and the test suite need a system Node.js 22.22.3+.CONTRIBUTING.mdnever mentioned Node.js ornpm ci.npm ci, 91 of 777 architecture tests fail. Each one prints its own traceback, and the remedy is buried inside them. Ifnodeis not on PATH at all, the scanner crashes with an uncaughtFileNotFoundError.decision_contextis 17 modules, about 6.5K lines. No README maps modules to steps.This PR does not remove any of the rigor. It makes these costs visible up front and, where possible, smaller.
What changes
Node.js is visible before install
pyproject.toml: the description drops "lightweight" and states "(requires Node.js 22.22.3+)". A comment next todependencies = []explains that pip cannot install the Node.js runtime.CONTRIBUTING.md: a new Prerequisites and one-time setup section covers Python 3.11+ viauv, Node.js 22.22.3+ (24 LTS recommended), andnpm ci --ignore-scriptsas a once-per-worktree step.A missing
npm ciproduces one message, not 91loopx/semantics/production.py:nodeis on PATH before running the scan;ERR_MODULE_NOT_FOUNDfortypescriptand raises one named error,NPM_DEV_DEPENDENCIES_MISSING. The parser's stderr is still never echoed.tests/conftest.py: when thetypescriptpackage cannot be resolved, pytest prints a header line. After the final totals line it prints:90 failure(s) share one cause: repository npm dev dependencies are not installed (the typescript package is missing); run npm ci --ignore-scripts once from the repository root.The remaining failure, the retrodiction baseline, is an indirect consequence and passes once
npm cihas run. With dependencies installed, the architecture suite passes (777).Which CI checks matter
CONTRIBUTING.mdgains What CI runs on a pull request:Sign-offandmerge-gateblock a merge, per themainruleset;merge-gateaggregates;When a change needs an RFC
docs/architecture/rfcs/README.mdgains When a change needs an RFC:Not applicable: <reason>and adds appendices only once they have content. The mirror keeps the same compact shape.TEMPLATE.mdor the bilingual-mirror policy itself.Capability code maps
loopx/capabilities/README.mddefines an optional## Code Mapconvention.decision_contextgets the first one, in the English README and the zh-CN mirror. It has one row per module, in pipeline order, plus an add an observable field route that lists which files to touch for a per-source fact, a decision-level field, a capture-only fact, the CLI, docs, and tests.Guards so this does not drift
tests/test_contributing_guide.pychecks three things:Node.js X.Y.Zin the README (en/zh), CONTRIBUTING, pyproject, the install guide, and the entrypoint equalsMINIMUM_NODE_VERSION;package.jsonengines is>=that version; exact workflow pins equal it;.github/workflows;merge-gatedependency.tests/test_capability_code_maps.pyrequires any code map to list exactly the package's modules, and the Chinese map to name the same set.tests/architecture/test_semantic_production.pycovers both new scanner diagnostics (Node missing,typescriptmissing) and checks that stderr does not leak into them.Interaction with open PRs
decision_context/freshness.py. Whichever PR lands second adds one Code Map row, which the new guard will point out.TEMPLATE.mdand other hunks of the RFCREADME.md. This PR only inserts one new subsection after the opening paragraph, with no overlapping lines.Not in this PR
Splitting large modules, merging workflows, and relaxing the bilingual mirror policy for small RFCs are larger structural or policy decisions for maintainers.
Validation
test_delegation_result_use[file] and [sqlite], also fail on the unmodified merge base.tests/architecturein a fresh worktree withoutnode_modules: 91 failed, with a singleloopx setupremedy line at the end. Afternpm ci --ignore-scripts: 777 passed.ruffon the touched Python files,mypy: clean.examples/docs-governance-smoke.py,examples/semantic-vocabulary-drift-smoke.py,examples/decision-context-contract-smoke.py: ok.loopx check --scan-pathon every touched file: errors=0.git diff --check: clean.