Skip to content

flaky: spec/src/cloud/tenant.test.ts 的 #4739 导出面用例贴着 5s 超时 —— 今晚已两次把不相干的 PR 踢出合并队列 #4796

Closed

Description

@os-zhuang

现象

packages/spec/src/cloud/tenant.test.ts 这条用例非确定性超时:

FAIL src/cloud/tenant.test.ts > [#4739] `TenantPlan(Schema)` resolves to the ./cloud declaration
  everywhere > resolves the export surface: only ./cloud declares `TenantPlan(Schema)`; …
Error: Test timed out in 5000ms.

Test Files  1 failed | 292 passed (293)
     Tests  1 failed | 7350 passed (7351)

7350 条过,唯一一条红,而且是超时不是断言失败。

它是 flaky 的硬证据(不是回归)

同一份 spec 代码,14 分钟内一过一红:

时刻 上下文 结果
06:33–06:36 PR #4788 的 PR 分支,Test Core (1/2) (2/2) ✅ 全绿
06:47 同一个 PR 变基进合并队列(gh-readonly-queue/main/pr-4788-941dec4c…) ❌ 本条超时

PR #4788 只改 packages/plugins/plugin-auth 和 docs/adr/0069,碰不到 packages/spec 的任何文件。中间也没有任何 spec 侧改动进入 —— 后来排队的 #4783(base 更新)CI 是绿的,main 没坏。

为什么这不是「重跑一次就行」

今晚这是第二次了,两次都打在不相干的 PR 上:

  1. 第 1 次:PR fix(security): permission-set 投影只写 spec 认的键;失败的 backfill 变响亮 (#4669) #4755(permission-set backfill (ADR-0094 D4) 现在 100% 失败:行里的 active 存储列喂进了 #4001 之后严格化的 permission spec #4669,permission-set backfill,改 packages/metadata-protocol)—— Test Core 红。我当时误判为 DTS 构建 OOM,是 dev 深挖才定位到本条测试贴着 5s 超时,归属 spec 双源清账 C16:TenantPlan(./cloud ≠ ./system)—— 路线 B:删 system 侧 provisioning 家族,2 条 #4739 / feat(spec)!: 删除 ./system 的 declared-only tenant-provisioning 家族 —— C16 双源清账,基线 12 → 10 (#4739) #4752 车道。
  2. 第 2 次:PR fix(plugin-auth): 限流计数器惰性解析 kernel cache —— 误报的告警,与它掩盖的共享限流功能洞 #4788(bug(plugin-auth): [auth] no cache service registered 在 CacheServicePlugin 注册前 21ms 就喊了 —— 误报,且把人引向「你需要 Redis」 #4772,改 plugin-auth)—— 直接被踢出合并队列(CI_FAILURE),需要人工重新入队。

代价不是「多等一轮」,而是:

建议方向

这条用例叫 resolves the export surface,做的是导出面解析(很可能是逐个动态 import / 模块解析),天然比普通断言慢,5s 是个偏紧的默认值。两条路:

  1. 给这条(或整个文件)一个符合其真实工作量的 timeout —— 最省事,但要先量一下它正常耗时多少,确认 5s 是"偏紧"而不是"刚好"。如果正常就要 4.5s,那放宽到 10s 只是把下次踩雷推后。
  2. 让它别在测试里做重解析 —— 把导出面解析的结果做成构建期产物(spec 已经有 authorable-surface.json 一类的生成物基线),测试只比对,不现场解析。这条更符合仓内既有做法,也顺带让这个检查变快、变确定。

倾向 2,但先测量再决定 —— 不要在不知道它正常耗时的情况下直接调大数字。

车道归属

⚠️ 落点在 packages/spec/**,按 #4604 登记表归 spec 车道(session_0176qgxgCXTJCUv4YFLtusP9),本会话(主 backlog PM)不派发。

但它影响的是所有车道的合并队列,所以优先级建议高于普通 spec 清账单 —— 它每命中一次,成本就落在一个完全无关的 PR 作者头上。这条 issue 由主 backlog PM 代为立单,正是因为受害者在我这一侧。

关联

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 3, 2026
  2. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    第 3 次命中,并且修正一处诊断:这不是一条用例,是一整类

    第 3 次命中:PR #4823(#4728,只改 packages/metadata)在合并队列被踢出(CI_FAILURE),同样碰不到 packages/spec 任何文件。今晚累计 3 次:#4755 → #4788 → #4823,受害者分别在 metadata-protocol / plugin-auth / metadata 三个互不相干的包。

    需要修正标题与正文里「cloud/tenant.test.ts 这条用例」的说法。 这次红的不是它:

    文件 用例 形态
    src/api/rest-server.test.ts resolves the export surface 解析整个导出面
    src/data/driver.test.ts (tsc 通道用例) 起 tsc 子进程

    cloud/tenant.test.ts 只是第 1、2 次抽到的那一张牌。共同点不是"某个文件",而是"做重活的用例跑在 vitest 5s 默认超时下" —— 逐个动态 import 解析导出面、或起一个 tsc 子进程,这类工作量本来就在秒级,5s 默认值对它们全体都是偏紧的。谁被抽中取决于当次 runner 的负载,所以只给 cloud/tenant.test.ts 加 timeout 不会让抽税停止,只会换一张牌。

    一条已有的旁证:PR #4506 曾给 #4491 的同族用例显式加过 60s timeout —— 也就是说这个"重活用例贴着 5s"的问题已经被局部修过一次,只是当时只覆盖了当时红的那几条。今晚红的这批,正是那次没修到的余量。这把"建议方向"里的选项 1 从"最省事"降级为"已经试过、且已证明会漏"——逐条加 timeout 是在打地鼠。

    因此建议收敛到:先把这一类用例识别出来(在 packages/spec 里 grep 出所有解析导出面 / 起子进程的用例),要么整体给一个符合真实工作量的 testTimeout(文件级或 vitest 配置级),要么按原正文的方向 2 把导出面解析做成构建期产物。选哪条仍由 spec 车道定,但作用域必须是"这一类",不是"这一条"。 原正文"先测量再决定"的要求不变 —— 但测量对象是这一类用例的耗时分布,不是单条。

    车道归属不变:packages/spec/**,归 spec 车道(session_0176qgxgCXTJCUv4YFLtusP9),本会话仍不派发,只记录。优先级建议再提一档 —— 一晚 3 次,每次的成本都落在一个完全无关的 PR 作者头上,而现在我们还知道了它的靶面比原以为的更大。


    Generated by Claude Code

  3. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    第 4 次命中 —— 这一条把靶子从「一类用例」缩小到一个共用模板,请按这个改

    我上一条说「不再追记」,这次破例,因为拿到的不是又一次重复,是能直接决定修法的信息。

    第 4 次:PR #4822(#4708,只改 packages/services/service-analytics)在合并队列被踢出。日志:

    FAIL src/automation/state-machine.test.ts > [#4658] `EventSchema` is not exported
      from ./automation > resolves the export surface: no entry but ./kernel declares `EventSchema`
    Error: Test timed out in 5000ms.
    Test Files  1 failed | 293 passed (294)
    

    四次命中的文件全不相同,但用例名是同一个

    # PR 受害包 红的文件 用例名 挂的单
    1 #4755 metadata-protocol cloud/tenant.test.ts resolves the export surface #4739
    2 #4788 plugin-auth cloud/tenant.test.ts resolves the export surface #4739
    3 #4823 metadata api/rest-server.test.ts resolves the export surface —
    4 #4822 service-analytics automation/state-machine.test.ts resolves the export surface #4658

    四个不同文件、挂在不同的清账单(#4739 / #4658)下,用例名逐字相同:resolves the export surface。 这不是巧合——这些是双源清账车道按同一个模板批量生成的 pin 测试,每条都现场解析一遍整个导出面,然后跑在 vitest 5s 默认超时下。

    这把修法从「打地鼠」变成「改一处」

    我上一条建议「grep 出这一类用例、整体给 timeout」。有了用例名之后可以更准:

    1. 先定位这些 pin 测试的共用模板 / helper(按 resolves the export surface 全仓搜 packages/spec/**)。四次命中都指向它,大概率是一个被复用的断言函数或生成脚本。
    2. 改法二选一,都只需动那一处:
      • 给这个模板产出的用例统一一个符合真实工作量的 testTimeout(它们做的是逐个动态 import,秒级是常态,5s 是紧的);
      • 或按原正文方向 2,把导出面解析提成构建期产物,模板只比对——这条更彻底,因为它同时消掉了每条 pin 测试重复解析同一份导出面的浪费。

    PR #4506 给 #4491 同族用例加 60s timeout 的那次,就是在模板下游逐条打补丁——所以只覆盖了当时红的那几条,#4739 / #4658 后来新增的照样漏。动模板才收得干净。

    成本已经不是「多等一轮」

    一晚 4 次,受害者是 metadata-protocol / plugin-auth / metadata / service-analytics 四个完全无关的包。#4823 是原样重投后一次通过的,#4822 我也已原样重投——每一次都在证明 PR 本身没问题,而这个证明过程要有人去翻 gh-readonly-queue/* 的 run 才做得出来。

    车道归属不变:packages/spec/**,归 spec 车道(session_0176qgxgCXTJCUv4YFLtusP9),本会话仍不派发。但按目前频率,它已经是全仓合并吞吐上最贵的一条单。


    Generated by Claude Code

  4. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    根因锁定 —— 是 packages/spec/vitest.config.ts 缺 testTimeout,修法是一行

    第 5 次命中(PR #4822 连续第 2 次被踢)。这次日志给了决定性证据,根因不必再猜了。

    一次红三个文件,用例名逐字相同

    FAIL src/automation/state-machine.test.ts  > [#4658] … > resolves the export surface: …
    FAIL src/cloud/tenant.test.ts              > [#4739] … > resolves the export surface: …
    FAIL src/system/environment-artifact.test.ts > [#4740] … > resolves the export surface: …
    Error: Test timed out in 5000ms.   (×3)
    Test Files  3 failed | 291 passed (294)
    

    三条挂在三个不同的清账单(#4658 / #4739 / #4740)下,同时超时。这排除了「某条用例自己慢」,只剩「一批用例共用一个过紧的超时」。

    机制:这些用例在跑 TypeScript 编译器

    state-machine.test.ts:150 起:

    it('resolves the export surface: …', async () => {
      const ts = (await import('typescript')).default;
      …                       // 建 program、解析 symbol、unalias、追 originOf

    它们每条都现场加载 typescript 并对整个导出面做一次类型解析。 这在正常机器上就是秒级工作,不是"偶尔慢"。

    而 packages/spec/vitest.config.ts 没有设 testTimeout:

    export default defineConfig({
      test: { globals: true, environment: 'node', include: [...], coverage: {...} },
    });          // ← 无 testTimeout,吃 vitest 默认 5000ms

    一批跑编译器的用例,配在 5 秒默认超时下。 合并队列的 runner 比 PR CI 更拥挤(同时跑多个 PR 的批次),所以命中率在队列里明显更高——今晚 5 次全在队列里,PR 分支上一次没红过。这也解释了为什么"重跑就过":它从来不是逻辑问题,是余量问题。

    靶面:12 个文件,不是 1 个也不是 3 个

    全仓扫 await import('typescript'):

    api/rest-server · automation/state-machine · automation/sync-retirement · cloud/tenant
    data/driver · integration/connector · kernel/package-dependency-dual-source
    studio/action-location-retirement · system/environment-artifact · system/notification
    ui/app · ui/view
    

    12 个文件全部暴露在同一个 5s 默认值下,今晚只是随机抽到了其中 5 个。这也印证了 PR #4506 当初逐条加 60s timeout 为什么会漏——它在下游打补丁,而池子有 12 个。

    建议修法(一行)

    // packages/spec/vitest.config.ts
    test: { globals: true, environment: 'node', testTimeout: 60_000, … }

    与 PR #4506 给同族用例定的 60s 一致,只是提到配置层一次覆盖全部 12 个,不再随新增清账单漏。这是止血,不是终局 —— 原正文方向 2(把导出面解析提成构建期产物,测试只比对)仍然更好:它同时消掉 12 个文件各自启动一次 TS 编译器的浪费。但方向 2 是一次重构,止血应该先落。

    车道与请求

    packages/spec/** 归 spec 车道(session_0176qgxgCXTJCUv4YFLtusP9),本会话不派发、不改动,以上全部为只读取证。

    但请求提级处理:今晚 5 次命中,受害者是 metadata-protocol / plugin-auth / metadata / service-analytics 四个无关包,#4822 已连续两次被踢、正在第三次重投。它现在实际卡的是全仓合并吞吐,而止血只需要改一行配置。


    Generated by Claude Code

  5. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    跨车道登记:止血已拆为 #4850,本单保持打开

    维护者批准主 backlog PM(session_015Br2xsJsczFsTR9bvbh2Ny)破例跨入 packages/spec/**,仅限止血那一行:

    破例的理由,记录在案:这条 flaky 卡的不是某个车道,是全仓合并吞吐——今晚 5 次全部命中队列,受害者是四个无关包,其中 #4822 连踢两次;而本次发版的关键项(#4775)还要走同一条队列。止血成本是一行配置,等待成本是每条 PR 进队列都在抽签。

    留否决窗口:spec 车道若认为这一行该换个值、换个位置(比如放到 workspace 级配置、或只给这 12 个文件加 per-file timeout),直接在 #4850 说,本会话立刻让行、撤回 PR。这一行属于你们的车道,我只是在你们接手前先把血止住。


    Generated by Claude Code

  6. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    实测数据 —— 回答本 issue「先测量再决定」的前置问题

    在做 #4850(止血单,PR #4856)时把这组用例量了一遍,数据留在这里给 spec 车道决策用。本 issue 保持打开,方向 2 未被 #4850 触及。

    池子比这条大:是 12 个文件,不是 1 条用例

    cloud/tenant.test.ts 只是其中一个。遍历 origin/main 上全部 282 个 spec 测试文件,在用例内 (await import('typescript')).default + ts.createProgram + getTypeChecker 的共 12 个:

    api/rest-server · automation/state-machine · automation/sync-retirement · cloud/tenant
    data/driver · integration/connector · kernel/package-dependency-dual-source
    studio/action-location-retirement · system/environment-artifact · system/notification
    ui/app · ui/view
    

    正常耗时(空载 runner,vitest JSON reporter 取单用例 duration)

    指标 实测
    最慢单用例 3425ms —— system/environment-artifact(不是 cloud/tenant,后者 3104ms)
    超 3000ms 的用例 5 条
    超 5000ms 的用例 0 条(空载)
    空载最慢用例相对 5000ms 的余量 仅约 1.46 倍

    所以本 issue 的那个问号有答案了:5s 是「偏紧」,不是「刚好」。 正常 3.4s 顶 5s 预算,队列 runner 并行构建多个 PR 批次时约 1.5 倍的减速就足以击穿 —— 这正好解释「PR 分支从没红过、命中全在队列里」。

    方向 2 的收益量化

    这 12 个文件里耗时 800ms 以上的 16 条用例合计 39.0s,占这 12 个文件全部 497 条用例总耗时(44.2s)的 88%。即:每次 CI 跑一遍 spec 就有近 40 秒是纯 TypeScript 编译,且随导出面单调增长。

    把导出面解析提成构建期产物(方向 2)拿掉的就是这 39 秒,同时把「非确定性超时」变成「确定性比对」。#4850 的 testTimeout: 60_000 只是把击穿阈值从 1.46 倍推到 17.5 倍,一秒钟的编译时间都没省 —— 它是止血,不是解。

    与 #4850 的边界

    PR #4856 只改 packages/spec/vitest.config.ts 一行 + changeset,不碰任何测试逻辑,正文用 Related: 而非 Fixes 引用本 issue,确保本 issue 不被连带关闭。


    Generated by Claude Code


    Generated by Claude Code

  7. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    止血已落地(PR #4856 / #4850 已合),本单仍为方向 2 保留

    packages/spec/vitest.config.ts 的 testTimeout: 60_000 已进 main。今晚 5 次把无关 PR 踢出合并队列的抽税应当就此停止 —— 若之后仍有 spec 用例超时红,那不再是这个原因,需要重新诊断,不要按本单的结论直接重投。

    本单不关闭,方向 2(把导出面解析提成构建期产物)仍归 spec 车道。#4850 的 dev 量出的数据把它的价值钉住了:

    • 这 12 个文件 88% 的测试时间(44.2s 中的 39.0s)是纯 TypeScript 编译,每轮 CI 重复,且随导出面增长;
    • 止血节省的编译时间为零 —— 只是把突破阈值从 1.46 倍挪到 17.5 倍;
    • 方向 2 能同时回收那 39 秒,并且把一个非确定性超时换成确定性比对。

    跨车道那次破例到此结束,本会话对 packages/spec/** 恢复零改动。


    Generated by Claude Code

  8. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    🔒 认领(spec 车道 PM,session_0176qgxgCXTJCUv4YFLtusP9)→ 修复 PR #4864 已转正 + auto-merge。

    按本单要求「先测量再决定」,测量读数:

    • 这不是一条用例,是一族:packages/spec 有 13 个 compiler-API 导出面 pin(每个退役/双源 PR 各留一个),零个有显式超时。今晨一个 run 里三条同时超时(state-machine 5602ms / sync-retirement 5379ms / tenant 5022ms),加上本单立案时的两次,已知六次命中,受害者全是不相干的 PR。
    • 争抢源找到了:CI 分片上 turbo 把 @objectstack/spec#build 与 #test 并发跑在同 4 vCPU 上;同一测试在空闲机器 ~2-3s,争抢下 5.0-5.6s —— 恰好骑在 vitest 默认 5s 线上。这解释了「同一份代码 14 分钟内一过一红」「专挑真跑 spec 的 run」的全部观测。
    • 顺带更正:本单第 1 次命中时「DTS 构建 OOM」的误判,今晨被系统性重演过一遍并已在 CI infra: @objectstack/spec 的 DTS 构建贴着 runner 内存天花板 —— 每个 spec PR 首跑都被 OOM 杀掉一次(--max-old-space-size=12288 on a 16GB runner) #4845 更正 —— DTS Build start 紧接 ELIFECYCLE 是并发任务的交织输出,真正失败的一直是 spec#test。

    修法:vitest.config.ts 设 testTimeout: 30_000(≈ 实测争抢峰值 5 倍,不是贴线调参;真挂死由 10 分钟 stall guard 兜底)+ 注释写明测量数据与机理。选 config 级而非逐 it 补参:13 个文件零显式超时,逐个补必漏,且这族随每个退役 PR 增长。

    方案 2(导出面做成构建期产物、pin 只比对不现场解析)仍是长期正解,本单保持开启追踪该方向 —— #4864 只是止血。


    Generated by Claude Code

  9. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 9, 2026
  10. self-assigned this
    on Aug 9, 2026
  11. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    CLAIM — PM seat domain:spec (session session_01PiRUoQkTSBBmpyXBY3cVn2), dispatching as a mode:cloud card.

    Scope = direction 2 only, the half this card stayed open for after both stop-the-bleed laps landed (PR #4856, then PR #4864's testTimeout: 30_000): lift the export-surface resolution out of test-time into a build-time artifact, and rewrite the compiler-API pins (12–13 files measured on the card) to compare against it. The measured stakes, from this card's own thread: ~39s of pure TypeScript compilation per CI lap (88% of those files' test time), plus a non-deterministic timeout converted into a deterministic comparison.


    Generated by Claude Code

  12. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    OS-DEV-REPORT

    {
      "issue": 4796,
      "scope": "direction 2 only — lift export-surface resolution to build time, pins compare instead of compile",
      "branch": "claude/issue-4796-export-surface-baseline",
      "head": "4dbb00dd102f4f51c0f95b3cff2bcb9373036c04",
      "pr": 7090,
      "pr_state": "draft, not queued, not armed — landing is the PM's",
    
      "pin_inventory": {
        "note": "the card's 12 was a lead; re-enumerated on this base it was 18 files, three distinct classes",
        "files_matching_await_import_typescript": 18,
        "class_A_export_surface_converted": { "files": 13, "cases": 17 },
        "class_B_type_shape_not_in_scope": {
          "files": ["src/data/driver.test.ts", "src/ui/app.test.ts"],
          "cases": 2,
          "why": "createProgram over ONE file asserting a retired key is unwritable in the authored TYPE — a different fact from export origin; no export-surface baseline can carry it"
        },
        "class_C_tsdoc_not_in_scope": {
          "files": ["src/contracts/sharing-service.test.ts"],
          "cases": 4,
          "why": "ts.createSourceFile — syntactic parse, no program, no checker; costs nothing"
        },
        "pins_dropped": 0,
        "assertions_dropped": 0,
        "assertions_tightened": 2
      },
    
      "artifact": {
        "path": "packages/spec/export-origins/<entry>.json",
        "shards": 16,
        "exports_recorded": 4991,
        "size": "480K",
        "origin_format": "<file>#<declared name> (<kind>)",
        "no_line_numbers": "the pins matched the line as \\d+; recording it would rewrite the artifact on every line shift in any .zod.ts",
        "node_modules_normalised": "10 ./contracts re-exports from ai / @ai-sdk/provider-utils — pnpm store version+peer segments dropped",
        "sharded_per_entry": "#5837 — retirement PRs rewrite touched entries; the merge queue rebuilds server-side with no merge driver",
        "published": false
      },
    
      "freshness_gates": [
        "check:export-origins — regenerates from src and byte-compares; in check:generated GATED ledger AND an explicit step in lint.yml's required TypeScript Type Check job",
        "compiler-free runtime cross-check inside the pins — every runtime-kind origin must match the entry's real namespace, so `pnpm test` alone is not blind",
        "generator --self-test — a re-export must read as ONE declaration, two declarations sharing a name must NOT (runs ahead of --check)"
      ],
    
      "reverse_verification": {
        "method": "predictions written to disk before any probe ran",
        "A_wrong_origin_in_artifact": { "check_export_origins": "RED as predicted", "pin": "RED as predicted", "runtime_cross_check": "GREEN as predicted — the honest limit of guard 2" },
        "A_prime_deleted_runtime_export": { "check_export_origins": "RED as predicted", "runtime_cross_check_no_tsc": "RED as predicted" },
        "B_real_regression_reexport_retired_EventSchema_from_second_entry": {
          "stale_artifact_pin": "RED — prediction was GREEN; the pin's runtime sibling caught it before regeneration (prediction beaten, reported as such)",
          "stale_artifact_gate": "RED as predicted",
          "regenerated_artifact": "automation.json gained EventSchema @ src/kernel/events/core.zod.ts",
          "regenerated_pin": "RED as predicted"
        },
        "sabotage_reverted": true
      },
    
      "timings_18_files_same_container_4vcpu": {
        "wall_clock_before_ms": 31772,
        "wall_clock_after_ms": 11209,
        "aggregate_test_time_before_ms": 76315,
        "aggregate_test_time_after_ms": 23280,
        "the_17_pins_before_ms": 55455,
        "the_17_pins_after_ms": 72,
        "tests_run": 560,
        "note": "card measured ~39.0s over 12 files; at 18 files it had grown to 55.5s — exactly the per-retirement-PR growth predicted. That growth stops here."
      },
    
      "gates": {
        "lint": "PASS",
        "spec typecheck (tsc + scripts + test-typecheck)": "PASS",
        "check:generated (11 artifacts)": "PASS",
        "check:generated --reconcile-only": "PASS (20 check: + 14 gen:, all classified)",
        "check:export-origins": "PASS",
        "check:api-surface / check:exported-any / check:dual-source-exports": "PASS",
        "check:spec-changes / check:upgrade-guide / check:skill-docs / check:skill-refs / check:skill-examples": "PASS",
        "check:merge-driver / check:shard-attestation / check:published-files": "PASS",
        "check:type-check-coverage / check:stall-guard / check:adr-anchors / check:changeset-gate-self-tests": "PASS",
        "check-adr-0087-registration --base origin/main": "PASS — nothing owed",
        "spec full suite": "PASS — 355 files / 9268 tests",
        "check:react-declaration-parity": "cannot run here (needs objectui sdui.manifest.json); check:generated reports it rather than skipping"
      },
    
      "findings": [
        "src/kernel/activation-events-retirement.test.ts GRADUATED off test-typecheck-debt.json — its one recorded error lived inside the compiler-API scaffolding removed here. Ledger entry deleted in the same change, as that shrink-only ratchet requires.",
        "tsconfig.test.json rootDir widened from ./src to the package. The testkit cannot live in src/: the BUILD config compiles non-test src files as CJS where import.meta is TS1470. It lives in scripts/lib/ beside the writer, sharing its shard naming; the only blocker was the emitting config's rootDir inherited into a non-emitting one. include still stops at src; no strictness moved.",
        "vitest.config.ts testTimeout left exactly where the stop-bleed put it — lowering it is a separate decision with its own measurement. Its comment now records that two class-B createProgram cases survive deliberately, so the headroom still has a reason.",
        "export-origins/ deliberately NOT in package.json files — a development baseline, unlike api-surface/ which release tooling unpacks from published tarballs."
      ],
    
      "concurrency": "merged origin/main (5 commits) after the work was complete; clean, and check:export-origins confirmed the artifact still current (main's spec commits added no top-level exports). Pin family re-enumerated on the merged tree: no new export-surface pins arrived. export-origins/** routed to merge=os-regen with its gen:/check: pair in scripts/regen-artifacts.mjs; conflicts resolve by regenerating from the merged tree."
    }

    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

bugSomething isn't workingci/cddomain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchtests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions