Skip to content

feat: スキル表示名の畳み込み確定を解除(バラす)できるようにする(ADR-0016 D11 / #496)#516

Merged
yusuke0610 merged 2 commits into
mainfrom
feat/skill-display-decision-reset
Jul 20, 2026
Merged

feat: スキル表示名の畳み込み確定を解除(バラす)できるようにする(ADR-0016 D11 / #496)#516
yusuke0610 merged 2 commits into
mainfrom
feat/skill-display-decision-reset

Conversation

@yusuke0610

@yusuke0610 yusuke0610 commented Jul 20, 2026

Copy link
Copy Markdown
Owner

概要

スキル表示名の human-in-the-loop 確定(ADR-0016 D11 / #476)で、一度確定した表示名・畳み込みグループを「解除(バラす)」する導線が無い問題(#496)を解消する。upsert(削除しない)設計で確定行が残り続け、機械デフォルトへ完全リセットできなかったギャップを埋める。

Closes #496

設計方針

「解除」= 対象 identity の Layer 3 確定行を DELETE して機械デフォルトへ戻す単一アクション。グループの全メンバー identity をまとめて送ることで「グループ解除(バラす)」と「確定リセット(表示名を戻す)」を同時に満たす。issue の案1(DELETE エンドポイント)を主軸に採用し、案3のメンバー個別分割 UI は作らない(ADR に残課題として明記)。

変更点

Backend

  • DELETE /skills/display-decisions を新設(identity 群指定で確定行を削除)。authz は confirm と同一(当該ユーザーの検出済みスキルに属すること/存在しない確定行は冪等に無視)。リセット後の最新一覧を返す
  • repositories/skill.pydelete_by_identities(user_id 固定・ORM 削除)
  • schemasSkillDisplayResetRequest 追加 → make codegen-typesgenerated.ts 再生成

Web

  • utils/skillDisplay: isResettableGroup / buildResetIdentities(TDD)
  • hooks/useGitHubSkills: reset / resetting(TDD)
  • スキル一覧の確定済みチップに「解除」ボタン追加

Docs

  • ADR-0016 D11 に項 (g)(解除)と変更履歴を追記

テスト

  • backend: 5 ケース(401 / 422 / リセット反映 / グループ全バラし / 冪等)
  • web: util 5・hook 2 ケース(red→green で TDD)
  • E2E: 解除フロー 1 本

ローカル make ci green(backend 729 / web 389 / build OK)、E2E(github-link)8 passed。

レビュー観点

  • API 契約追加: body 付き DELETE の新設(generated.ts は同 PR に再生成済み)
  • 設計分岐: 削除ベースの全リセットを採用、メンバー個別分割 UI は未実装(残課題)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a reset option for confirmed GitHub skill display names.
    • Resetting restores machine-generated names and can ungroup related skills.
    • Reset buttons show progress states and are unavailable during other updates.
  • Bug Fixes

    • Reset operations are validated, idempotent, and preserve existing data when they fail.
  • Documentation

    • Documented the reset behavior, authorization, and fallback display rules.
  • Tests

    • Added coverage for authentication, validation, grouped skills, failures, and end-to-end reset behavior.

一度確定した表示名・畳み込みグループを機械デフォルトへ戻す導線が無く、
upsert(削除しない)設計で確定行が残り続け完全リセットできなかったギャップを埋める。

Backend:
- DELETE /skills/display-decisions を新設(identity 群指定で Layer 3 確定行を削除)。
  authz は confirm と同一(当該ユーザーの検出済みスキルに属すること/存在しない
  確定行は冪等に無視)。リセット後の最新スキル一覧を返す
- repositories/skill.py に delete_by_identities を追加(user_id 固定・ORM 削除)
- schemas に SkillDisplayResetRequest を追加、make codegen-types で generated.ts 再生成

Web:
- utils/skillDisplay に isResettableGroup / buildResetIdentities を追加(TDD)
- useGitHubSkills に reset / resetting を追加(TDD)
- スキル一覧の確定済みチップに「解除」ボタンを追加。グループ全メンバーを
  まとめて解除するため畳み込みも解ける

Docs:
- ADR-0016 D11 に項 (g)(解除)と変更履歴を追記

テスト: backend 5 ケース / web util 5・hook 2 ケース / E2E 解除フロー 1 本を追加

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added feature 新機能 documentation Improvements or additions to documentation backend バックエンド web フロントエンド (web) test テスト追加・修正 labels Jul 20, 2026
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yusuke0610, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fd3e8a7b-a58b-4e27-955e-c4e0ace210f1

📥 Commits

Reviewing files that changed from the base of the PR and between 5c9251a and 97b01f7.

📒 Files selected for processing (1)
  • web/src/components/github-link/SkillDisplaySection.tsx
📝 Walkthrough

Walkthrough

Adds an authenticated DELETE flow for resetting confirmed GitHub skill display decisions. The backend removes matching records and returns refreshed skills, while the generated client, hook, grouped UI controls, tests, and ADR support the reset behavior.

Changes

Skill display reset

Layer / File(s) Summary
Backend reset contract and deletion flow
backend/app/schemas/github_skill.py, backend/app/repositories/skill.py, backend/app/routers/github_link/endpoints.py, backend/tests/test_skill_display_api.py, docs/adr/0016-github-skill-inference.md
Adds the reset request schema, identity-based deletion, endpoint validation, refreshed skill responses, authorization/idempotency tests, and ADR documentation.
Generated client and hook integration
web/src/api/generated.ts, web/src/api/types.ts, web/src/api/githubLink.ts, web/src/hooks/useGitHubSkills.ts, web/src/hooks/useGitHubSkills.test.ts
Adds the DELETE API contract and wrapper, then exposes reset state and error-preserving reset behavior through useGitHubSkills.
Grouped reset controls and user-facing validation
web/src/utils/skillDisplay.ts, web/src/components/github-link/SkillDisplaySection.tsx, web/src/components/github-link/*.css, web/src/constants/messages.ts, web/src/utils/skillDisplay.test.ts, web/e2e/github-link.spec.ts
Determines resettable groups, builds member identities, renders disabled/in-progress reset controls, adds messages and styling, and verifies fallback display behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SkillDisplaySection
  participant useGitHubSkills
  participant GitHubLinkAPI
  participant Backend
  User->>SkillDisplaySection: Click reset
  SkillDisplaySection->>useGitHubSkills: Reset group identities
  useGitHubSkills->>GitHubLinkAPI: Send DELETE request
  GitHubLinkAPI->>Backend: Delete display decisions
  Backend-->>GitHubLinkAPI: Return refreshed skills
  GitHubLinkAPI-->>useGitHubSkills: Updated skill list
  useGitHubSkills-->>SkillDisplaySection: Render machine defaults
Loading

Possibly related PRs

  • yusuke0610/devforge#495: Introduced the display-decision model and confirmation workflow extended by this reset flow.

Suggested labels: agent

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 主要変更であるスキル表示名の確定解除機能を具体的に示しており、PR内容と一致しています。
Linked Issues check ✅ Passed DELETE API、repo削除、UIの解除導線、生成型更新、テスト追加が #496 の要件を満たしています。
Out of Scope Changes check ✅ Passed テスト、ADR、生成型、UI補助ユーティリティはいずれも解除機能に直接関連しており、明らかな逸脱はありません。
Docstring Coverage ✅ Passed Docstring coverage is 94.74% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/skill-display-decision-reset

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
web/src/components/github-link/SkillDisplaySection.tsx (1)

60-73: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Polish reset button text state.

Because resetting is a single global boolean coming from the hook, clicking "解除" on one group will simultaneously change the text of all visible reset buttons to "解除中...". You can track the clicked group locally to only change the text of the button that was actually clicked, while still keeping all buttons disabled during the request.

✨ Proposed optional polish

Add a local state at the top of the component (e.g., around line 37):

  const [resettingKey, setResettingKey] = useState<string | null>(null);

Then update the button rendering to use the local state for its text:

-                {/* 確定済みグループのみ、機械デフォルトへ戻す「解除」を出す(#496) */}
-                {isResettableGroup(group) && (
-                  <button
-                    type="button"
-                    className={styles.resetButton}
-                    onClick={() => void reset(buildResetIdentities(group))}
-                    disabled={resetting || confirming || proposing}
-                    aria-label={SKILL_DISPLAY_MESSAGES.resetAriaLabel(group.label)}
-                  >
-                    {resetting
-                      ? SKILL_DISPLAY_MESSAGES.RESETTING
-                      : SKILL_DISPLAY_MESSAGES.RESET}
-                  </button>
-                )}
+                {/* 確定済みグループのみ、機械デフォルトへ戻す「解除」を出す(#496) */}
+                {isResettableGroup(group) && (
+                  <button
+                    type="button"
+                    className={styles.resetButton}
+                    onClick={async () => {
+                      setResettingKey(group.key);
+                      await reset(buildResetIdentities(group));
+                      setResettingKey(null);
+                    }}
+                    disabled={resetting || confirming || proposing}
+                    aria-label={SKILL_DISPLAY_MESSAGES.resetAriaLabel(group.label)}
+                  >
+                    {resettingKey === group.key
+                      ? SKILL_DISPLAY_MESSAGES.RESETTING
+                      : SKILL_DISPLAY_MESSAGES.RESET}
+                  </button>
+                )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/github-link/SkillDisplaySection.tsx` around lines 60 - 73,
Update SkillDisplaySection’s reset-button state using a local resettingKey state
tied to the clicked group, and use it to show RESETTING only for that group’s
button. Keep the existing global resetting value for disabling all reset buttons
during the request, and clear the local key when the reset operation completes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@web/src/components/github-link/SkillDisplaySection.tsx`:
- Around line 60-73: Update SkillDisplaySection’s reset-button state using a
local resettingKey state tied to the clicked group, and use it to show RESETTING
only for that group’s button. Keep the existing global resetting value for
disabling all reset buttons during the request, and clear the local key when the
reset operation completes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d4c189f7-4199-4f82-84e4-44800f6f5404

📥 Commits

Reviewing files that changed from the base of the PR and between 6955c4c and 5c9251a.

📒 Files selected for processing (16)
  • backend/app/repositories/skill.py
  • backend/app/routers/github_link/endpoints.py
  • backend/app/schemas/github_skill.py
  • backend/tests/test_skill_display_api.py
  • docs/adr/0016-github-skill-inference.md
  • web/e2e/github-link.spec.ts
  • web/src/api/generated.ts
  • web/src/api/githubLink.ts
  • web/src/api/types.ts
  • web/src/components/github-link/SkillDisplaySection.module.css
  • web/src/components/github-link/SkillDisplaySection.tsx
  • web/src/constants/messages.ts
  • web/src/hooks/useGitHubSkills.test.ts
  • web/src/hooks/useGitHubSkills.ts
  • web/src/utils/skillDisplay.test.ts
  • web/src/utils/skillDisplay.ts

global resetting は全解除ボタンの無効化に使い、押されたグループの区別は
ローカルの resettingKey で行う。確定済みグループが複数ある場合に全ボタンへ
「解除中...」が出ていたのを、対象グループのボタンだけに出るよう修正。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yusuke0610
yusuke0610 merged commit aa78d18 into main Jul 20, 2026
20 checks passed
@yusuke0610
yusuke0610 deleted the feat/skill-display-decision-reset branch July 20, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend バックエンド documentation Improvements or additions to documentation feature 新機能 test テスト追加・修正 web フロントエンド (web)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

スキル表示名の畳み込みグループを解除(バラす)できる導線がない(ADR-0016 D11 残課題)

1 participant