[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与 - #581

Closed
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order
Closed

[ドラフト縮小 2/7] ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与#581
yusuke0610 wants to merge 1 commit into
mainfrom
feat/562-draft-selection-order

Conversation

@yusuke0610

@yusuke0610yusuke0610 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes#562

概要

ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時の降順だったため、「昨日 README を直しただけのチュートリアル」が「半年前に作り込んで完成させた本命」に勝っていた。チュートリアル・todo アプリ・写経リポジトリが上位を占めうる状態を解消する。

変更内容

1. 選定順(select_repos

順位キー変更
第 1継続期間(pushed_at − created_at新規。主キー
第 2language_bytes_total#561 の永続化値を参照(repo_technologies からの都度算出をやめた)
第 3pushed_at主キー → タイブレークへ降格
最終full_name 昇順現行の決定論保証を引き継ぎ

重み付き和や積は採らなかった。係数の恣意性が入り、「継続 1000 日 × 1KB」と「10 日 × 100KB」が並んでしまう。段階比較なら「まず続いたか、次に作り込んだか」という判断順を素直に表せる。

stars は使わない(ADR-0026 決定 3。個人開発では本命でも 0〜1 が普通で判別力が無い)。

2. ノイズ判定(evaluate_noise / 新規)

NoiseVerdict(selected_by_default: bool, reasons: tuple[str, ...]) を返す純関数。

  • 継続期間が閾値(30 日)未満 → 理由「継続期間が短い」
  • topics に学習用途語 → 理由「学習用途の topics」
  • 複数該当なら理由を全て返す(順序も決定論)

topics は小文字化 + 区切り除去して完全一致で判定する。hands-on / Hands_On / HANDSON を同一視しつつ、部分一致は採らない(sample-api-server のような本命を誤判定するため)。

機械は候補を落とさない(ADR-0026 決定 2)。本判定は UI のデフォルト選択状態と理由表示にのみ影響させ、select_repos の結果からは除外しない。専用テストで「判定が結果件数を変えない」ことを固定している。

3. 定義事項

issue が「本 issue で定義しテストで固定する」としていた項目を確定した。正本は mapper.py の定数で、ADR に数値は複製していない

項目決定
スコア式重み付けせずタプルの段階比較
実装量language_bytes_total(単一フィールド・重みなし)
継続期間の閾値30 日未満を非選択(テストから threshold_days= で注入可)
学習用途 topicstutorialpracticesamplestudylearninghandsonexampledemoplaygroundboilerplate
正規化小文字化 + -_ 除去 → 完全一致
完全順序全キー同値でも full_name 昇順で一意

4. mutmut スコープ

backend/pyproject.toml[tool.mutmut] only_mutateresume_draft/mapper.py を追加した。以降この経路は make lint-tdd の対象になる。

TDD(ADR-0019)

2 サイクル実施し、いずれも red の失敗出力を確認してから実装した。

サイクルred の失敗
並び順At index 0 diff: 'o/tutorial' != 'o/flagship'
ノイズ判定assert True is False / assert [] == ['継続期間が短い', '学習用途の topics']

2 サイクル目は関数未定義で collection error になったため、.claude/rules/common/tdd.md の指示(collection error はテスト自体の不備)に従い最小スタブを置き直し、振る舞いで落ちる red を確認してから green へ進んでいる。

テストは 30 件 pass。旧契約(pushed_at 第 1 キー)を固定していた既存テスト 2 件は新契約へ置き換え、旧契約を固定化したテストは残していない。

検証

  • make cilint-tdd 含む): pass

注意点

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Improved repository selection to prioritize sustained activity, language usage, recent updates, and consistent name ordering.
    • Added clearer handling for repositories with invalid dates and short-lived activity.
    • Repositories focused on learning or experimentation can now be identified and excluded by default.
    • Added configurable thresholds and consistent, understandable reasons for repository selection decisions.
    • Preserved eligible repositories when applying selection limits.

@coderabbitai

coderabbitaiBot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The resume-draft mapper returns deterministic noise verdicts and ranks repositories by active duration, language byte volume, push time, and full name. Tests cover thresholds, topic normalization, invalid dates, tie-breaking, and candidate retention.

Changes

Resume draft repository selection

Layer / File(s)Summary
Repository noise evaluation
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py
Adds NoiseVerdict, configurable short-lived thresholds, normalized learning-topic matching, deterministic reasons, and candidate-retention tests.
Repository ranking
backend/app/services/agent/resume_draft/mapper.py, backend/tests/test_resume_draft_mapper.py, backend/pyproject.toml
Ranks repositories by active duration, language byte total, push time, and full name. Tests cover invalid dates, complete ordering, and project limits. The mapper is included in mutation-testing targets.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the repository selection-order change and noise evaluation added by the pull request.
Linked Issues check✅ PassedThe changes satisfy #562 by updating deterministic ranking, adding noise evaluation, preserving candidates, normalizing topics, and covering the behavior with tests.
Out of Scope Changes check✅ PassedThe mapper, mutation-testing configuration, and tests all directly support the requirements in #562.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/562-draft-selection-order

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.

@github-actionsgithub-actionsBot added backend バックエンド test テスト追加・修正 agent DevForge Agent labels Aug 4, 2026
ADR-0026 決定 3。select_repos の第 1 キーが最終 push 日時だったため、
「昨日 README を直しただけのチュートリアル」が「作り込んで完成させた本命」に
勝っていた。継続期間を主キーに据え、直近性はタイブレークへ降格する。
- select_repos: 継続期間(pushed_at − created_at)→ 言語バイト合計 →
最終 push 日時 → full_name の段階比較に変更。重み付き和や積は係数の恣意性が
入るため採らない。stars は判別力が無いので使わない(ADR-0026 決定 3)
- 実装量は #561 で永続化した language_bytes_total を参照する
- evaluate_noise を追加。継続期間が閾値未満 / 学習用途 topics をデフォルト
非選択にし、理由を返す。topics は小文字化 + 区切り除去して完全一致で判定
- 機械は候補を落とさない。判定はデフォルト選択状態と理由表示にのみ影響させ、
select_repos の結果からは除外しない(ADR-0026 決定 2)
- mapper.py を [tool.mutmut] only_mutate に追加
TDD: 並び順・ノイズ判定それぞれで red('o/tutorial' != 'o/flagship' /
assert True is False)を確認してから実装した。閾値・語彙・スコア式は
mapper.py の定数が正本で、ADR には数値を複製していない。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yusuke0610
yusuke0610force-pushed the feat/562-draft-selection-order branch from 0b4d9cc to 2a4bd58CompareAugust 4, 2026 22:55
@coderabbitai

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@backend/app/services/agent/resume_draft/mapper.py`:
- Around line 93-94: Update the timestamp parsing in the mapper around created
and pushed so it parses complete repository timestamps rather than slicing to
dates, then calculate duration as pushed_at minus created_at. Add a boundary
test covering a sub-day difference that falls just below the 30-day threshold.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21da54b8-e4e9-4da2-ab26-676f9b458b66

📥 Commits

Reviewing files that changed from the base of the PR and between 1bdf1ac and 2a4bd58.

📒 Files selected for processing (3)
  • backend/app/services/agent/resume_draft/mapper.py
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/pyproject.toml
  • backend/tests/test_resume_draft_mapper.py

Comment on lines +93 to +94
created = date.fromisoformat(repo.created_at[:10])
pushed = date.fromisoformat(repo.pushed_at[:10])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Calculate the duration from complete timestamps.

repo.created_at[:10] and repo.pushed_at[:10] discard the time component. A repository created at 2026-06-01T23:59:00Z and pushed at 2026-07-01T00:00:00Z has a duration of 29 days and 1 minute. The current code returns 30 days and incorrectly selects it by default at the 30-day threshold.

Parse the complete timestamps before subtraction. Add a sub-day boundary test.

Based on PR objectives, the duration is pushed_at − created_at.

🤖 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 `@backend/app/services/agent/resume_draft/mapper.py` around lines 93 - 94,
Update the timestamp parsing in the mapper around created and pushed so it
parses complete repository timestamps rather than slicing to dates, then
calculate duration as pushed_at minus created_at. Add a boundary test covering a
sub-day difference that falls just below the 30-day threshold.

@yusuke0610Claude

Copy link
Copy Markdown
OwnerAuthor

本 PR の内容は #585 に取り込まれ、main へマージ済みのためクローズします。

#585 には本 PR のコミットに加えて、本 PR で CodeRabbit が指摘した「_active_dayscreated_at[:10] / pushed_at[:10] で時刻成分を切り捨てる」問題の修正(完全な ISO 8601 パース + 閾値直下の境界テスト)が含まれています。

コンフリクト表示について: #585 が squash マージされたため本 PR の 2a4bd58 は main の履歴に含まれず、git が「同じ変更が両側で別々に入った」と判定しています。解消しても main と完全一致(差分ゼロ)になるため、マージではなくクローズが適切と判断しました。


Generated by Claude Code

yusuke0610 pushed a commit that referenced this pull request Aug 5, 2026
#585(PR #581 相当)が main に squash マージされ、同じ #562 の実装が両側に
別コミットとして入ったためコンフリクトしていた。
- mapper.py / test_resume_draft_mapper.py: 本ブランチ側を採用した。main 側の
select_repos / evaluate_noise は本ブランチの rank_repos /
evaluate_default_selection / build_candidates に置き換わっており、候補一覧 API・
選択 UI がこちらの API に依存しているため
- ただし main 側にしか無かった修正(継続期間の時刻成分切り捨て / PR #581 の
CodeRabbit 指摘)は本ブランチの duration_days へ移植した。_parse_datetime を
追加して UTC の aware datetime で減算する。日粒度でよい「参画中」判定は
_parse_date のまま残す
- 移植分のテスト 2 件(閾値直下 29 日 1 分の境界 / タイムゾーン混在表記)を
本ブランチの evaluate_default_selection の契約に合わせて追加した
- pyproject.toml: only_mutate の同一エントリで、コメント文言のみ本ブランチ側を採用
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaqnCny4wsD6AkBkJeTEEV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentDevForge Agentbackendバックエンドtestテスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ドラフト縮小 2/7] backend: ドラフトの選定順を「継続期間 × 実装量」へ変更しノイズ判定を付与

1 participant

@yusuke0610