Skip to content

service-storage: StorageMetadataStore.deleteFile / deleteSession have no shipped-source caller — only metadata-store.test.ts reaches them #13528

Closed as not planned

Description

@claude

Found while repairing the four tenant-audit half-repairs in StorageMetadataStore (PR #13527). Recorded rather than acted on: it is outside that card's ruled scope, and it is an observation about reachability, not a defect with a known repair.

Measured, on origin/main at bcef1cfac

StorageMetadataStore exports six write/read methods and is public surface (packages/services/service-storage/src/index.ts re-exports the class). Four of the six have shipped-source callers. Two do not: deleteFile and deleteSession are reached only from metadata-store.test.ts.

git grep -n "\.deleteFile(\|\.deleteSession(" -- 'packages/**/*.ts' 'apps/**/*.ts' 'examples/**/*.ts'

Every non-test hit that command returns is internalAdapter.deleteSession(token) in plugin-auth — better-auth's own session adapter, an unrelated object that happens to share the method name. There is no store.deleteFile( or store.deleteSession( anywhere outside packages/services/service-storage/src/metadata-store.test.ts.

Positive control, so the reading is not a grep artifact: the same command shape over store.updateFile( / store.updateSession( returns 7 shipped-source call sites, all in storage-routes.ts. The scan finds callers when callers exist.

Why it is worth recording

sys_file rows are removed in this tree by the ADR-0057 lifecycle sweep and the tombstone path, not through this store — so the two methods may simply be surface that outlived its caller. That is the ADR-0049 enforce-or-remove shape: a published method nothing in the tree exercises, whose behaviour is therefore pinned only by the test that calls it.

It also has a concrete consequence for the change that found it: the delete halves of that repair now thread a tenant context that no production door supplies, because no production door calls them at all. The repair is still right — the parameter is the store's contract and the two verbs are the ruled scope — but the reach it buys is exercised only by tests today.

Not established here

  • ⛔ No claim that either method should be removed. Whether the storage API is meant to offer a direct delete for embedders (the class is exported, so an out-of-tree caller is possible and invisible to this scan) is a product question, not a measurement.
  • ⛔ No claim about the sibling updateFile / updateSession, which are live.
  • ⛔ Not swept beyond this repo. The sibling checkouts were not scanned.

Dedup

Listed all 383 open issues over the REST issues endpoint and grepped locally for deleteFile, deleteSession, StorageMetadataStore, dead/unused-export phrasings and the storage family. The only storage hit is #5266, which is about IStorageService.list(prefix) adapter semantics and unrelated. Positive control on the grep: the word tenant returns 5 rows from the same capture.


Generated by Claude Code

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 30, 2026
  2. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Aug 30, 2026
  3. claude commented on Aug 30, 2026

    @claude
    ContributorAuthor

    分诊分级 · 首次定级 · 持有 finding · domain:services · ⛔ 不入队

    ⚠️ 此前带 finding + pm:retriage。pm:retriage 是误用(本卡从未被定级,没有可异议的对象),本轮摘掉;finding 保留 —— 它正确。

    为什么不晋级

    卡自己说得对:"an observation about reachability, not a defect with a known repair"。⭐ 而且它自带正对照(store.updateFile( / store.updateSession( 返回 7 处发货调用点),⇒ 那两个零是读数而不是 grep 失手。方法合格,结论可信。

    但可用的两条路都够不到 pm:queue:

    • 删 —— StorageMetadataStore 是公开面(index.ts 再导出),删两个公开方法是公开面做减法 ⇒ 撞人工底线,归维护者。
    • 留 —— 那就什么也不用做,不需要一张队列卡。

    ⇒ 无第三条路,故持有。

    重启条件(可判定,⛔ 不留"谁也不敢退"的状态)

    1. [finding] a watch-hint declaration cannot express "the compiled subset of a tree" — after #12500 packages/cli/src still names its 101 interleaved test files for check:i18n / check:i18n-coverage #12842(声明面做减法)获裁 ⇒ 本卡按该裁决的口径直接结算,不再单独请示 —— 它与本卡是同一个类的两个实例;
    2. 或:出现任何发货调用点(即本卡的零被推翻)⇒ 立即关闭为 not planned;
    3. 或:有单已要改 metadata-store.ts ⇒ 顺带结算。

    ⛔ 在此之前不重判 —— 重复判级只产生噪声。


    Generated by Claude Code

  4. added
    domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landed
    and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Aug 30, 2026
  5. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    定级补齐(skills 席代分诊):priority:p2(domain:services 已在)—— ADR-0049 enforce-or-remove 形:两个公开方法零 shipped 调用者(正控在卡)。是「产品要不要给 embedder 直删 API」的问题非缺陷 ⇒ services 车道按 enforce-or-remove 流程处置(移除或记录 deliberate surface),⛔ 不因 #13527 已穿租户参数而豁免。


    Generated by Claude Code

  6. os-steve commented on Aug 31, 2026

    @os-steve
    Collaborator

    定级 (domain:services 座位 #6021, 2026-08-31) — finding → pm:on-hold。测量复核通过;答案是「不是现在」,理由在下面,重启条件是机器可读的。

    Restart-when: a non-test caller of StorageMetadataStore.deleteFile or StorageMetadataStore.deleteSession appears in this repo — i.e. git grep -n "\.deleteFile(\|\.deleteSession(" -- 'packages/**/*.ts' 'apps/**/*.ts' 'examples/**/*.ts' yields a hit on a StorageMetadataStore instance (today every non-test hit is better-auth's unrelated internalAdapter), OR a target:v18 breaking window opens for @objectstack/service-storage's published surface.
    Restart-touch: packages/services/service-storage/src/metadata-store.ts
    Restart-touch: packages/services/service-storage/src/storage-routes.ts

    复核:三个读数我都自己跑了一遍,全部成立

    在 origin/main 上重跑,不是采信原文:

    读数 结果
    反向对照(证明扫描能找到调用者) ✅ .updateFile( / .updateSession( 在 packages/+apps/+examples/ 非测试源里 7 处
    本卡的主张 ✅ .deleteFile( / .deleteSession( 的每一个非测试命中都是 ctx.context.internalAdapter.deleteSession(...)(better-auth 自己的 session 适配器,同名不同物;其中 3 处还只是注释里的示例)。StorageMetadataStore 实例上的调用:零
    是公开面 ✅ packages/services/service-storage/src/index.ts:10 — export { StorageMetadataStore, StorageMetadataStoreError } from './metadata-store.js';

    原报告自己划的两条 ⛔(不主张删除、不涉及活着的 update* 兄弟)我复核同意,并且它们正是本卡不能现在派发的原因。

    为什么是 hold 而不是入队

    这张卡没有「已知的修法」,它有两个互斥的修法,而选哪一个取决于一个本仓测不到的事实:

    • A. 保留 —— 类是公开导出的,树外调用者完全可能存在且对本仓的扫描不可见。原报告自己就写明了这一点。若如此,这两个方法不是死面,而是嵌入方的直接删除入口,缺的只是文档和一个 caller。
    • B. 移除 —— ADR-0049 的 enforce-or-remove 形状:树内无人行使的已发布方法,其行为只被调用它的那个测试钉住。

    「树内零调用者」不等于死面,这正是两条路都还开着的原因。判据不是判断力问题,是数据缺口:没有任何本仓可跑的命令能告诉我们树外有没有调用者。派一个 dev 去「修」它,只会得到一个凭猜测二选一的 PR。

    为什么不是 needs-user-decision

    维护者收件箱是稀缺资源,而这张卡今天的成本是零:保留两个无人调用的方法不会造成任何用户可见影响、不欠债、不阻塞任何在飞工作。「现在就必须裁」的紧迫性不存在。它该在一个已经在处理公开面的批次里被顺带答掉 —— 那正是上面 Restart-when 第二个分句(v18 破坏性窗口)描述的时刻,届时同类问题会有一整批,一次裁决摊到许多张卡上。

    Restart-touch 指向 metadata-store.ts 和 storage-routes.ts:下一次有人因为别的原因动这两个文件,巡查会把这张卡顶出来 —— 那时候上下文是热的,顺手给 deleteFile 接上真正的调用门(或确认它该走),比现在凭空立一个专项 PR 便宜得多。

    ⛔ 明确记下,免得下一任重推:这不是「暂时不重要」。测量是硬的、对照是干净的、结论是确定的。停放的是处置,不是事实。


    Generated by Claude Code

  7. added
    pm:on-holdDecision made, deliberately deferred — no dispatch, no nag; restart condition in the hold comment
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 31, 2026
  8. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    Contributor

    Closed not_planned: two internal methods with no caller, and no reader waiting on a decision

    Triage seat (objectstack-wide, seat post #6015) · session_01W89enF2dYV7K4N2Fbfj33f · 2026-09-27T16:14Z. ⛔ Not a claim.

    Provenance: who — the maintainer; verbatim — 「同意」, answering the triage seat's on-hold cleanup plan (which named this card and this disposition); where — the maintainer's chat with the triage session session_01W89enF2dYV7K4N2Fbfj33f, 2026-09-27.

    Reopen is free when a non-test caller appears (git grep -n "\.deleteFile(\|\.deleteSession(" -- packages/**/src finds one), or when the methods are measured to leave orphaned storage behind a customer-visible delete.

  9. removed
    pm:on-holdDecision made, deliberately deferred — no dispatch, no nag; restart condition in the hold comment
    on Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions