Skip to content

fix(analytics): make comment collaboration readable in Workspace reporting - #6731

Open
open-design-crew[bot] wants to merge 1 commit into
mainfrom
fix/comment-analytics-relation-groups
Open

fix(analytics): make comment collaboration readable in Workspace reporting#6731
open-design-crew[bot] wants to merge 1 commit into
mainfrom
fix/comment-analytics-relation-groups

Conversation

@open-design-crew

Copy link
Copy Markdown
Contributor

Why

Workspace 改版后我们想回答一个问题:团队里到底有多少人在别人的项目上评论? 这是协作是否真的发生的核心信号。

看板搭起来之后发现这个问题答不了。评论创建事件有两个缺口:

  1. 四分之一到三分之一的评论"判不出评的是谁的项目" —— 每天有 100 多条评论被记成"未知",多到把整张图变成噪音。
  2. 评论完全不进工作区维度的统计 —— 按工作区看活跃度时,评论这个动作整个是空的,像是没人评论过一样。

排查下来,两个缺口都不是"漏埋点",而是两处判断本身就不成立。

What users will see

用户侧没有任何变化 —— 不改界面、不改行为,只改我们自己看到的数据。

对看数据的人来说变化是:

  • "未知"这一类基本消失,取而代之的是一个新的、含义明确的分类:"这个项目本来就没有第二个人"。个人空间里的项目、还没加入任何工作区的本地项目,只有你一个人,"评的是不是别人的项目"这个问题根本不成立 —— 以前把它记成"未知",等于把"正常的单人使用"和"我们真的算错了"混成一堆。现在分开了,"未知"从此只剩一个含义:这是一个多人项目,但我们没能查出它的归属,属于真实缺陷,涨了就该有人去看。
  • 评论会开始计入工作区维度,工作区活跃度里第一次能看到评论这个动作。

另外顺手确认了一件事:"几乎没人评论别人的项目"是真的,不是被"未知"藏起来了。 我按数据把"未知"拆开看过,里面一条团队项目的评论都没有 —— 全部是个人空间和本地项目。真实的跨人评论近 14 天只有 15 条。所以这个修复不会让"评论他人项目"的数字变多,它的价值是让这张图从今往后可信。

Surface area

  • API / contractpackages/contracts 里评论事件的分类取值新增 not_applicable
  • UI
  • Keyboard shortcut
  • CLI / env var
  • Extension point
  • i18n keys
  • New top-level dependency
  • Default behavior change

看板不需要改:对应的图用的是开放式拆分,新分类会自动出现。

Bug fix verification

  • 复现测试:
    • apps/daemon/tests/project-comment-permissions.test.ts
    • apps/daemon/tests/analytics-env.test.ts
  • 在修复前红、修复后绿?是。 把两处源码临时还原成修复前的写法后,以下 4 条断言全部失败,还原修复后全绿:
    • reports a project with no owner to compare against as not_applicable
    • treats a personal workspace as having no second party
    • sends $groups written inline by a call site as posthog-node group affiliation
    • omits group affiliation when a call site sends no usable $groups
  • 另外补了 3 条回归保护(团队项目查不到归属仍记为"未知"、查询抛错仍记为"未知"、查不到调用方仍记为"未知"),这几条在修复前后都是绿的,属于防止后续把"真实缺陷"也一起吞掉。

两处根因

其一,分类逻辑把"没有答案"和"算不出来"当成了同一回事。
原来的写法是:作者和项目归属两边只要有一边取不到,就记"未知"。但个人空间只有一个成员、本地项目连工作区都没有 —— 这两种情况下"归属"根本不存在,不是查失败。占比最大的那块"未知"就是这么来的。

其二,工作区归属被 PostHog 的 SDK 悄悄丢掉了。
调用处其实是写了工作区归属的,写法也和网页端一致,所以看代码完全看不出问题。但 posthog-node 内部会用它自己的参数重新拼一遍事件,把写在属性里的那份无条件覆盖掉 —— 而我们从来没传过那个参数,于是每次都被覆盖成空。现在把工作区归属提到 SDK 要求的位置上,所有 daemon 事件都一起修好,不只是评论这一个 —— 后面任何服务端事件都会踩同一个坑。

Validation

  • pnpm guard — 通过
  • pnpm typecheck — 通过
  • pnpm --filter @open-design/daemon typecheck — 通过
  • 相关测试全绿(60 passed):project-comment-permissions / analytics-env / workspace-project-analytics / attribution / project-comment-workspace-gate
  • 数据侧需发版后 2–3 天回看:「未知」占比应显著下降且总量不变,评论事件在工作区维度不再为 0

Adjacent issues(本次不做)

comment_level 目前写死 top_level,而契约里声明了 top_level | reply。核对过:评论在产品上是画布批注,「回复」走的是编辑同一条记录、不产生新事件,所以 reply 是一个产品产不出来的死值。这是产品决策不是 bug —— 要么上线真正的讨论串,要么把这个维度删掉,等 Eli 定。

…rting

Two gaps made `project_comment_create_result` unusable for answering "who
comments on someone else's project".

`target_project_relation` reported `unknown` for ~2/3 of production comments.
Those were not failures: an unbound local project, or one in a personal
single-member workspace, has no second party to compare the author against.
They now report `not_applicable`, leaving `unknown` to mean only a shared
project whose owner genuinely failed to resolve. The owner lookup also no
longer swallows a thrown error into the same bucket as an absent owner.

Daemon events also carried no workspace group affiliation, so they were
missing from every workspace-scoped aggregation. The call site did set
`$groups` inline, but posthog-node rebuilds the payload as
`{ ...properties, $groups: groups }` and overwrote it with the unpassed
argument. Group affiliation is now lifted to that argument for every daemon
capture, so call sites can keep the inline form the web SDK uses.
@open-design-crew

Copy link
Copy Markdown
Contributor Author

补充:按客户端版本拆过之后,收益预期要修正

开 PR 之后又按 app_version 把 "unknown" 拆了一遍,结论会影响怎么验收这个改动,所以补在这里。代码不用改,但上面 Why 里"25-35% 的未知"这个说法把收益说大了。

"未知"其实是两批完全不同的东西混在一起(近 14 天):

版本 事件量 unknown 占比 其中「无工作区绑定」 其中「个人空间」
0.18.0 609 67.7% 333 79
0.18.1 1164 22.2% 11 247

按天看更清楚,0.18.1 从 8/07 起接管流量:

日期 0.18.0 量 0.18.1 量 新版「无工作区」 新版「个人空间」
08-06 244
08-08 24 257 3 63
08-10 55 359 1 70
08-11 27 96 0 14

两个结论:

  1. 「无工作区绑定」那批是老版本的问题,已经在自愈。 新版本上每天只剩 0~1 条,等老用户升完就归零了 —— 这部分不是本 PR 的功劳
  2. 「个人空间」那批跟版本无关。 在最新版本上稳定每天 60~70 条,一条没少。这才是本 PR 真正解决的部分。

所以准确的预期是:光等用户升级,"未知"会从 ~35% 掉到 ~22% 然后永远卡住;本 PR 解决的是卡住的这 22%。

对验收的影响(重要)

发版后回看数据时必须按 app_version 过滤,只看新版本。如果把所有版本混在一起看,老版本自然衰减带来的下降会被误记成本 PR 的效果,从而高估收益。

@lefarcen lefarcen added size/L PR changes 300-700 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/bugfix Bug fix labels Aug 11, 2026
@lefarcen
lefarcen requested a review from nettee August 11, 2026 06:33
@lefarcen lefarcen added the skip-validation Maintainer override: bot will not auto-add needs-validation on this PR. label Aug 11, 2026

@nettee nettee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found one blocking analytics-classification issue: the new relation helper still classifies normal bound personal-project comments as self/other, so the PR's intended not_applicable bucket is not reached for that production path. The focused daemon tests and typechecks pass, but they do not cover a populated personal binding.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

workspaceContext: WorkspaceCollabContext | null;
ownerLookupFailed: boolean;
}): TrackingProjectRelationOrNotApplicable {
if (input.authorMemberId && input.ownerMemberId) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comparison runs before the personal-workspace check, but the route seeds ownerMemberId from localBinding.createdByWorkspaceMemberId before calling this helper (the binding is populated for projects created in a personal workspace). As a result, a normal personal-project comment has both IDs and is emitted as self or other; not_applicable is only returned when the owner happens to be null. That leaves the main personal-traffic bucket misclassified and defeats the stated goal of separating single-member projects from real resolution failures. Check the workspace type before comparing IDs (or only use the binding owner for team contexts), and add a regression with workspaceType: 'personal' plus a populated owner/binding ID.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen

Copy link
Copy Markdown
Contributor

Quick triage catch-up: the blocking item on this head is already covered by @nettee's review, so the next step is to fix that personal-workspace classification path and add the regression they called out.

Once there's a new push, we can re-check from there.

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

Labels

risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/L PR changes 300-700 lines skip-validation Maintainer override: bot will not auto-add needs-validation on this PR. type/bugfix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants