Skip to content

fix(contribute): explain share hints with friction context - #282

Merged
jeff-r2026 merged 5 commits into
Tencent:mainfrom
hupicake:fix/contribute-hint-context
Aug 6, 2026
Merged

fix(contribute): explain share hints with friction context#282
jeff-r2026 merged 5 commits into
Tencent:mainfrom
hupicake:fix/contribute-hint-context

Conversation

@hupicake

@hupicake hupicake commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary / 摘要

The contribute decision is already driven primarily by friction signals, but the user-facing hint still explains it with tool-call volume and tool diversity. This PR carries a validated friction snapshot and a sanitized first-task summary through the existing cache path, so cache hits and cache misses both explain why the hint appeared and which task it refers to without changing scoring or trigger behavior. The hint itself is now English, following the repository's CLI output policy.

贡献提示的判定已经主要由摩擦信号驱动,但用户看到的文案仍使用工具调用量和工具多样性解释。本 PR 将经过校验的 friction 快照和脱敏后的首个任务摘要贯通现有缓存链路,使 cache hit 与 cache miss 都能准确说明提示原因和任务上下文,同时不改变评分与触发行为。提示文案使用英文,以符合仓库的 CLI 输出规范。

Example / 示例:

[teamai] This session may contain a problem worth documenting: you interrupted the AI twice, the AI retried failing tools 8 times.

Task: Fix auth retry for <REDACTED:gh_tok> then add regression coverage

Consider running /teamai-share-learnings to summarize what you learned and share it with your team.

Type of Change / 变更类型

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature causing existing behavior to change)
  • Documentation only
  • Refactor / internal cleanup

This fixes the mismatch between the data used to qualify a session and the explanation shown to the user. The persisted-state additions are optional and backward compatible.

本次修改修复了“session 判定依据”与“展示给用户的解释”不一致的问题。新增的持久化状态字段均为可选字段,并保持向后兼容。

Test Plan / 测试计划

Validated on PR head 5899e81f68e2cd8e171ccb67b5d65306ace7b61c, after merging upstream/main at e9a60891b35822723b3ecdda4a667472ddbba0f4.

Environment / 环境:

  • macOS 26.5.2 (Build 25F84)
  • Node.js v23.11.0
  • npm 10.9.2

Results / 结果:

  • npm ci — exit 0; 391 packages installed, 392 audited. npm reported 11 dependency audit findings (3 moderate, 6 high, 2 critical); this PR does not change dependencies.
  • npx tsc --noEmit — exit 0
  • npx vitest run — exit 0; 145 test files passed, 1,924 tests passed
  • Added/updated tests for the change
  • npm run build — exit 0; tsup build succeeded
  • npm run test:e2e — exit 0; 11 test files passed, 1 skipped; 64 tests passed, 23 skipped
  • Relevant unit and Phase 2 tests — 2 files, 51 tests passed
  • Contribute-check CLI E2E — 1 file, 7 tests passed
  • npx vitest run --coverage — exit 0; 1,924 tests passed. src/contribute-check.ts: 89.97% lines, 92.30% branches, 91.66% functions
  • git diff --check upstream/main...HEAD — exit 0
Supplemental Windows baseline / 补充 Windows 基线

Before the macOS run, npx vitest run was compared with the then-current upstream/main in the same Windows environment. Both revisions had the same 59 existing failures in the same 19 test files, caused by POSIX path, Linux process, permission, symlink, and colon-in-filename assumptions. The branch added five passing tests and no new failures.

在 macOS 验证前,曾在同一 Windows 环境对比当时的 upstream/main 与本分支。两个版本均在相同的 19 个测试文件中出现相同的 59 个既有失败,来源为 POSIX 路径、Linux 进程、权限、符号链接和文件名冒号等平台假设;本分支新增 5 个通过测试,没有新增失败。

  • Then-current upstream/main: 1,832 passed, 59 failed
  • This branch at that point: 1,837 passed, 59 failed

The all-green macOS run above is the current authoritative result. / 以上全绿的 macOS 结果为当前权威验证结果。

Regression coverage includes / 回归覆盖包括:

  1. a fresh high-friction session with a multiline prompt containing a GitHub token;包含多行 prompt 和 GitHub Token 的全新高摩擦 session;
  2. a complete cache hit with no events.jsonl;不存在 events.jsonl 时的完整缓存命中;
  3. migration of legacy or malformed state without valid friction;缺少合法 friction 的旧状态或畸形状态迁移;
  4. a knowledge-gap-only session with zero friction;friction 全为零的纯知识空白 session;
  5. singular, dual, and plural English friction wording;英文摩擦次数的单数、两次和复数文案。

The raw token is absent from both Hook output and persisted contribute state. 原始 Token 不会出现在 Hook 输出或持久化的 contribute state 中。

Related Issues / 关联 Issue

Closes #228.

Notes for Reviewers / 审核说明

Cache compatibility / 缓存兼容

  • A fresh cache hit requires smartScore, toolCount, a valid friction snapshot, and a fresh lastEvaluated value.

  • promptSummary is intentionally optional so tools without one do not cause permanent cache misses.

  • Legacy state without friction and malformed friction both fail closed and re-scan events.jsonl.

  • uniqueTools remains in state for backward compatibility but is no longer required to render the hint.

  • 新缓存命中要求存在 smartScoretoolCount、合法的 friction 快照,以及未过期的 lastEvaluated

  • promptSummary 保持可选,避免无法提供摘要的工具永久 cache miss。

  • 缺少 friction 的旧状态和畸形 friction 都会 fail closed 并重新扫描 events.jsonl

  • uniqueTools 继续保留以兼容旧状态,但不再是生成提示的必要字段。

Prompt safety / 摘要安全

Before persistence or display, the first task summary is scrubbed with redactWithEnv(), stripped of control characters, flattened to one line, whitespace-normalized, trimmed, and limited to 160 UTF-16 code units. Truncated summaries end with an ellipsis and never retain a dangling high surrogate. The writer normalizes it again as defense in depth.

首个任务摘要在持久化或展示前会经过 redactWithEnv() 脱敏、控制字符清理、单行化、空白归一、首尾裁剪和 160 个 UTF-16 code unit 限制;发生截断时会附加省略号,并移除边界处孤立的高代理项。状态写入时会再次标准化,作为纵深防御。

Intentionally unchanged / 明确保留

  • computeSmartScore() and all friction weights

  • CONTRIBUTE_SMART_THRESHOLD and the tool-count hard gate

  • Phase 2 score-adjustment logic in applyPhase2Adjustments()

  • hint deduplication, re-read-before-write concurrency protection, and Stop-hook JSON protocol

  • computeSmartScore() 与所有摩擦权重

  • CONTRIBUTE_SMART_THRESHOLD 与工具调用数 hard gate

  • applyPhase2Adjustments() 中的 Phase 2 分数调整逻辑

  • 提示去重、写前重读并发保护和 Stop hook JSON 协议

One pre-existing behavior remains out of scope: Phase 2 score adjustments are re-applied to cached scores on cache hits.

一个不在本 PR 范围内的预存行为是:cache hit 时会对缓存分数再次应用 Phase 2 调整。

@jeff-r2026
jeff-r2026 requested a review from m0Nst3r873 August 5, 2026 08:26
@hupicake
hupicake marked this pull request as ready for review August 5, 2026 08:44

@m0Nst3r873 m0Nst3r873 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the PR against #228 and it lands the goal: the hint now explains why it fired (friction reasons, only the non-zero ones) and what the session was about (promptSummary), the scoring path (computeSmartScore, CONTRIBUTE_SMART_THRESHOLD, the tool-count gate, applyPhase2Adjustments) is untouched, all four friction signals render, and the bilingual docs are in sync. I also confirmed the redaction ordering is correct — redactWithEnv() runs before the truncation, so a cut can never resurrect a raw secret.

Two non-blocking notes on the truncation in normalizePromptSummary, both on the same line. Neither leaks plaintext and neither affects the #228 outcome.

Comment thread src/contribute-check.ts Outdated
Comment thread src/contribute-check.ts Outdated
@jeff-r2026
jeff-r2026 merged commit df6813b into Tencent:main Aug 6, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

contribute 提示语固定、不结合上下文:应展示摩擦信号 + 任务摘要,让用户能判断要不要分享

3 participants