Skip to content

[Decision] Root ESLint never loads @typescript-eslint/eslint-plugin, so no-explicit-any is a rule nobody runs: 1,922 as-any sites in non-test source and 211 eslint-disable comments for an absent rule — add a per-file ratchet, or not #26082

Closed

Description

@objectstack-fleet

Ruled: 6417062243 · letter C · 2026-10-26T13:22Z

Filing gate ②: a maintainer-only decision. Maintainer, 2026-10-26, verbatim: 「完整的评估本项目, 还有哪些可以优化的地方。包括 ci 和文档」 then 「使用 pm-dispatch 技能创建 issue,需要决策的立为决策卡。」 and 「低优先级的先不考虑」. Batch-of: 19 (repository evaluation 2026-10-26, session_019a9XCWsbMFp75REzthE6cs; 9 decision cards + 10 execution cards). Reader: the director seat presents this card in a decision batch; after the ruling the lane named under "After the ruling" dispatches. ⛔ Not a claim. Dedupe: REST list (439 issues), grep as any|no-explicit-any|typescript-eslint → 2 hits: #25918 (open, pm:queue, domain:ui: 14,366 no-explicit-any WARNINGS in the ui tree; "不做全仓翻转(objectui#8316 已拒),只在发布的授权面上加严"), #25302 (closed, unrelated). The root tree is a different case: the rule is not loaded at all. This card asks about packages/**; #25918 owns ui/**. New.

维护者速读

根 eslint.config.mjs 只引入了 @typescript-eslint/parser,没有安装 @typescript-eslint/eslint-plugin,所以 no-explicit-any 在 packages/** 从未生效过(ui 树是另一回事:规则是 warn,#25918 在管)。pnpm lint 又带 --no-inline-config,于是 66 个文件里 211 条 eslint-disable @typescript-eslint/no-explicit-any 注释是对一条不存在的规则的空操作。非测试源码 1,922 处 as any(350 个文件),前三名 objectql/src/engine.ts 205、metadata-protocol/src/protocol.ts 133、plugin-approvals/src/approval-service.ts 62——恰是三个最大文件(#25467 / #25522 / #25521 正在切片)。仅有两条窄的自定义规则(slot-lookup、query-options)各带 grandfather 基线。新增门禁/棘轮是人工地板项,且 objectui#8316 曾拒全仓翻转,所以请你裁:A 安装插件,加 no-explicit-any 为 error 但只对 src/** 非测试文件,配按文件计数、只减不增的基线(与 test-typecheck-debt.json 同一棘轮形态),删 211 条空注释;B 只装插件开 warn 并删空注释,不设基线不红;C 不加任何规则,只删 211 条空注释。选 A / B / C?

Governing text

Premises

  • P1 — grep -n 'typescript-eslint' package.json → parser only; grep -n 'no-explicit-any' eslint.config.mjs → 0.
  • P2 — grep -rl 'eslint-disable.*no-explicit-any' packages --include='*.ts' --exclude-dir=node_modules | wc -l → 66 files; count of comments → 211.
  • P3 — grep -rE 'as any' packages --include='*.ts' --exclude-dir=node_modules --exclude-dir=dist | grep -vE '\.(test|spec)\.ts' | wc -l → about 1,922 lines in 350 files; top files as listed.
  • P4 — the two custom rules and their baselines: scripts/slot-lookup-baseline.json (25 files, 100 sites), scripts/query-options-erasure-baseline.json (15 files, 50 sites).

One-sentence problem

The code that turns metadata into SQL and permissions is written with two thousand holes in its type checking, and the one tool meant to count them is not installed.

Options

Option What Consequence Workload
A Install the plugin; no-explicit-any: error scoped to non-test src/**; scripts/no-explicit-any-baseline.json per file, shrink-only, generated once, checked by an existing lint step; delete the 211 dead comments. New as any in source reds the PR; existing ones are debt with a number; the three giant files' slices (#25467/#25522/#25521) can graduate their new modules file by file. spec lane (lint tooling) · 1 PR (+ one install, pnpm-lock.yaml) · precedent: test-typecheck-debt.json onboarding (AGENTS.md 「Build & Test」)
B Install; warn; delete comments. A number appears in logs nobody reads (#25918's exact finding for ui: "什么都不能让 CI 红"). 1 PR
C Delete the 211 comments only. Honest file; no measurement. 1 PR, S

Business meaning

  • A: the engine's type holes get a ceiling that only goes down.
  • B: a counter on the wall.
  • C: remove the pretend guard rails, add nothing.

四维分析

  • 实际业务需求:as any 最密的三个文件是查询引擎、元数据协议、审批服务——权限与数据完整性所在,北极星「安全与数据完整性永远最高」。每个 as any 是一处编译器看不见的契约绕过。
  • 项目长远合理性:仓库已经为 typecheck 债建立了「按文件、只减不增、毕业即删」的棘轮;A 是同一形态的第三个实例,不是新发明。B 在 ui 树被实测为无效(lint/types: 14,366 no-explicit-any warnings can never red CI — make it an error on packages/types/src, delete the vestigial (schema as any) reads, and type ComponentRendererProps with unknown #25918)。
  • 防 AI 犯错:席位写代码时 as any 是最便宜的「让它编译」;没有红灯就没有阻力。A 让新增的那一处在 PR 上响亮失败,错误形态是席位看到行号;B/C 下错误形态是静默进入 main。
  • 创业阶段不扩散:这是新增门禁(④ 默认否);但它复用已有棘轮机制与 lint 步骤,不加 workflow、不加 job。推荐只按①②③得出,④ 的「默认否」由你翻。

Recommendation

A, if you name the gate; otherwise C. 只看①选 A;②③④ 是否翻转:④ 新增门禁默认否——这是唯一允许翻字母的例外,字母由你定。

Confidence gaps: whether @typescript-eslint/eslint-plugin v8 with the parser already pinned adds measurable lint wall time on 3,521 source files (the dev reads pnpm lint before/after on the PR).

After the ruling

os-decision-facets
① 项目长远合理性:复用已有的按文件只减不增棘轮,不发明新机制。
② 实际业务拉动:1,922 处集中在查询引擎、元数据协议、审批服务,权限与数据完整性所在。
③ 防 AI 犯错:新增 as any 在 PR 上响亮失败,而不是静默进 main;warn 在 ui 树已被实测无效。
④ 创业阶段不扩散:是新增门禁,默认否;只复用 lint 步骤,不加 job 不加 workflow。
Prior rulings read: no-explicit-any,as any,ratchet,baseline → 2 hits (#25918; objectui#8316 refused a whole-repo flip); none; thread: none; repo: objectstack-ai/objectstack

Related

#25918 (open, ui tree), #25467 / #25522 / #25521 (open: slicing the three largest files), AGENTS.md 「Build & Test」 ratchet principles.

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — tooling · tech-debt · priority:p2 · domain:devx · area:devpath · needs-user-decision · pm:awaiting-maintainer · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T12:07Z

    ⛔ Not a claim, ⛔ not a dispatch. On the maintainer's 「完整的评估本项目…」 / 「低优先级的先不考虑」 (repository evaluation, Batch-of 19). Low priorities were excluded at filing, so the execution cards grade p2.

    • A decision card: the options and the filer's recommendation are in the body, and the letter is the maintainer's. Floor: option A turns on a lint rule over 1,922 sites. That is a new gate, and 「新增门禁默认否」 applies, so the filer's recommendation is A only if the maintainer names the gate, otherwise C.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Brief-claimed-by: session_01KrKXQVvgYk2AJ4VkqMobyb · batch #397 · 2026-10-26T12:47Z

    Director seat, summon #51 continuation (ledger objectstack#12708). Presented to the maintainer in batch #397 (the CI / tooling family of the 2026-10-26 repository review) as item 4 of 4. Seat increment (re-verified on origin/main cdd4eea9; the card's own analysis is not restated):

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #397 item 4 · letter C · maintainer 「同意」 2026-10-26T13:21Z

    Recorded by the director seat (summon #51 continuation, session_01KrKXQVvgYk2AJ4VkqMobyb, ledger objectstack#12708, brief 6416366902). The card and the seat both left the letter to the maintainer because A is a new gate (SKILL.md 四轴 ④: 新增门禁默认否, flipped only by the maintainer's word); the reply 「同意」 names no gate, so the letter is C: delete the 211 eslint-disable @typescript-eslint/no-explicit-any comments in 66 files — inert under --no-inline-config against a rule the root config never loads (eslint.config.mjs:5, package.json:28, :218) — and install nothing, add no rule. The measurement A would have bought (a per-file shrink-only no-explicit-any baseline over non-test src/**) stays available: if the maintainer later names the gate, a new card cites this one and the three large-file slices (#25467 / #25522 / #25521) it would wait for. The ui tree stays #25918's.

    Workload of the chosen letter: spec lane (lint tooling) · 1 PR, S · the 66 files only, no config change.

    Execution: needs-user-decision → pm:queue in this act (domain:devx as triage graded; the body names the spec lane for lint tooling — the triage seat settles it on first claim); pm:awaiting-maintainer removed in the same stroke. Ruling-ref: names this comment; Clause-②: no, Metadata-protocol: none.

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4 · 2026-10-26T14:24Z
    Session: session_01Q4MDXRbEJCNdPAP4SiXwp9 (devx seat 2) · card thread session_01D8CEyQZUZgQM1xXhoZeKgb
    Account: os-steve
    Branch: claude/project-thread-6od3f3 (the harness-pinned branch of the card thread; it names no issue, so this claim is the identity record; amended on spawn)
    Worktree: objectstack-issue-26082
    Domain: domain:devx
    Seat: domain:devx#2 (seat post #20163)
    File surface: ruling 6417062243 letter C — delete the 211 eslint-disable … @typescript-eslint/no-explicit-any comments in the 66 files outside ui/ (git grep -l 'eslint-disable.*@typescript-eslint/no-explicit-any' -- ':!ui' on origin/main: 41 packages/qa/dogfood, 15 packages/verify/src, 7 packages/plugins/*, 1 each packages/types, packages/runtime, packages/core); a comment that also names another rule keeps that other rule; ⛔ no rule, plugin, baseline or eslint.config.mjs change; ⛔ nothing under ui/ (#25918 owns it) (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: default tier (TIER_DEFAULT, from dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6417062243
    Premise: holds on origin/main — 66 files / 211 comments, matching the card; check-governed-merges.mjs --test <66 paths> → governed false; none of the three files being sliced (#25467 / #25522 / #25521) is in the list
    Serial constraints cleared: 36 open PRs read, none touches the 66 files; #26093 (this seat) edits eslint.config.mjs only, disjoint


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26082,
      "status": "done",
      "branch": "claude/project-thread-6od3f3",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26252",
      "session": "session_01D8CEyQZUZgQM1xXhoZeKgb",
      "premise_still_valid": true,
      "summary": "Ruling 6417062243 letter C: deleted the 211 inert eslint-disable @typescript-eslint/no-explicit-any comments in the 66 files outside ui/ (166 whole-line disable-next-line lines deleted, 45 trailing disable-line comments cut). Every comment named only this rule, none was a block comment. No plugin, rule, eslint.config.mjs or baseline change; nothing under ui/. One merge of origin/main (#26175 touched packages/verify/src/harness.org-context.test.ts; main side taken, its 4 comments deleted the same way).",
      "files_changed": "66 (65 tests + packages/verify/src/handle.ts); per package: qa/dogfood 41 files/120 comments, verify 15/32, plugin-security 6/41, plugin-auth 1/10, core 1/6, runtime 1/1, types 1/1",
      "line_budget": "+45 / -211 = 256 changed lines vs 3000 (dispatch-gates changed-lines reading); delta vs origin/main e6dfeb08f: 66 files, +45/-211",
      "tests": "head cd984c91, verify lock, every VERDICT command-exit 0: types 29 files/781 tests; verify 46/393; plugin-auth 198/3779 (10 skipped); plugin-security 225/4920 (45 skipped); core 121/2778; runtime 455/7408 (19 skipped) (core/runtime/types --project local); dogfood the 41 touched files 41/345. Same set green on first head c91379fb. typecheck on the 7 touched packages after full pnpm build (119/119): all Done, VERDICT 0. Acceptance: git grep -c eslint-disable.*@typescript-eslint/no-explicit-any -- :!ui = no match (exit 1), was 66/211; pnpm lint exit 0 on clean origin/main e6dfeb08 worktree and on head, outputs identical after path normalisation (diff exit 0); same pair identical at c91379fb vs 601c7738. No ablation: comments only, no tested behaviour changed.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on cd984c91: 67 commands, all 67 exit 0 (exit captured before any pipe); --ran: 67 run, 0 NOT-MEASURED, 0 UNRUN (derived zero). Reruns: check-plugin-teardown-shape --self-test needed its pinned fixture commit fetched into the shallow clone (first-head run exit 3 PREREQUISITE, rerun 0); check:dts-closure / check:dual-build-cjs-loads read after the full build (first-head 1/3 on missing dist, rerun 0); check:type-check-debt queue-timeout exit 3 on the lock, rerun under the lock exit 0. check-governed-merges --test on the 66 paths: 0 of 66 hit the register. CI check-runs on the PR: in_progress at report time.",
      "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 relay strokes: pr_create (POST pulls draft + POST issues/26252/assignees + POST issues/26252/labels skip-changeset), this os-dev-report comment (POST issues/26082/comments); plus 2 git push (not REST)",
      "deviations": [
        "pnpm typecheck run on the 7 touched packages, not the whole workspace (os-dev local-verification scope); the workspace run is the required TypeScript Type Check job",
        "PR review request to os-steve not sent: the session asks for it through GitHub MCP, the dispatch order forbids MCP writes",
        "PR activity not subscribed: the dispatch contract overrides the platform subscription posture; patch rounds come through the seat",
        "first pre-change lint run read the worktree while the edit landed, so it was stopped by its own PID and redone in a separate clean origin/main worktree"
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    devx seat 2 · review: ACCEPT → PR #26252 (Fixes #26082) comment 6422574956 on head cd984c9181. Every check is green or skipped. Not governed. Landing: ready + auto-merge.


    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

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions