Skip to content

feat: Enable to register tasks shared across multiple contests (#2346)#2775

Merged
KATO-Hiro merged 12 commits intostagingfrom
#2346
Nov 1, 2025
Merged

feat: Enable to register tasks shared across multiple contests (#2346)#2775
KATO-Hiro merged 12 commits intostagingfrom
#2346

Conversation

@KATO-Hiro
Copy link
Collaborator

@KATO-Hiro KATO-Hiro commented Nov 1, 2025

close #2346
See #662

Future tasks

  • Contest と Task のペアの情報を API 経由、かつ、管理者アカウントから投入・更新できるようにする(現状は、CSVファイルから追加)
  • /workbooks と /workbooks/[slug] ページも同様の処理ができるようにする

Summary by CodeRabbit

  • Documentation

    • Added detailed impact analyses, phased implementation and verification plans, manual UI/regression notes, and an implementation checklist for migrating to a composite contest+task key scheme.
  • Refactor

    • Consolidated merging logic into a single reusable flow and migrated result mappings to a composite contest+task key; added support for merging provided task subsets for incremental adoption.
  • Tests

    • Added fixtures and comprehensive tests validating composite-key behavior, merge outcomes, and status preservation across scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 1, 2025

Warning

Rate limit exceeded

@KATO-Hiro has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2951a5e and 03b2f47.

📒 Files selected for processing (1)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)

Walkthrough

Refactors task-result handling to use composite keys "contestId:taskId": adds ContestTaskPairKey type and createContestTaskPairKey helper, centralizes merging via getMergedTasksMap() and createTaskResults(), updates services to produce maps keyed by ContestTaskPairKey, adapts TaskTable.svelte to the composite-key maps, and adds fixtures plus Vitest tests for the new flow.

Changes

Cohort / File(s) Summary
Docs & Plans
docs/dev-notes/2025-10-26/impact-analysis/phase1-findings.md, docs/dev-notes/2025-10-26/impact-analysis/phase2-analysis.md, docs/dev-notes/2025-10-26/impact-analysis/plan.md, docs/dev-notes/2025-10-26/impact-analysis/report.md, docs/dev-notes/2025-10-26/impact-analysis/future_tasks.md
New impact analyses, phased implementation plan, risk assessment, migration checklist, testing strategy, and future tasks for switching to composite contest/task keys.
New types & util
src/lib/types/contest_task_pair.ts, src/lib/utils/contest_task_pair.ts
Adds ContestTaskPairKey, TaskMapByContestTaskPair, TaskResultMapByContestTaskPair, and createContestTaskPairKey() helper.
Services — tasks
src/lib/services/tasks.ts
Changes getMergedTasksMap() signature to accept an optional Tasks parameter (getMergedTasksMap(tasks?: Tasks)) and uses the provided tasks when present.
Services — task_results
src/lib/services/task_results.ts
Introduces createTaskResults(tasks, userId), replaces prior relate/inline merging, uses getMergedTasksMap(), and updates getTaskResults(), getTaskResultsByTaskId() and getTaskResultsOnlyResultExists() flows to work with merged maps and ContestTaskPairKey-keyed maps.
Component updates
src/lib/components/TaskTables/TaskTable.svelte
Imports ContestTaskPairKey and createContestTaskPairKey(), converts taskResultsMap and taskIndicesMap to use composite keys, and updates update-handling to compute/use the composite key for lookups/updates.
Test fixtures
src/test/lib/services/fixtures/task_results.ts
Adds mock tasks, submission statuses, answers, and derived EXPECTED_STATUSES fixtures for tests.
Tests
src/test/lib/services/task_results.test.ts
Adds Vitest suite with extensive mocks and fixture-driven cases validating merged results, preservation of contest_id/task_id, and status merging for map-based TaskResults.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Comp as TaskTable.svelte
    participant RSvc as task_results Service
    participant TSvc as tasks Service
    participant DB as Database

    Note over RSvc,TSvc: New flow uses merged task maps keyed by ContestTaskPairKey
    Comp->>RSvc: getTaskResults(userId)
    RSvc->>TSvc: getMergedTasksMap()
    TSvc->>DB: fetch tasks (or use provided subset)
    DB-->>TSvc: tasks[]
    TSvc->>TSvc: merge tasks & answers -> Map<ContestTaskPairKey, Task>
    TSvc-->>RSvc: mergedTaskMap
    RSvc->>RSvc: createTaskResults(mergedTaskMap, userId) -> TaskResults[]
    RSvc-->>Comp: TaskResults[]

    Comp->>Comp: for each result\nkey = createContestTaskPairKey(contest_id, task_id)
    Comp->>Comp: taskResultsMap.set(key, result)\ntaskIndicesMap.set(key, index)

    note right of Comp: Composite keys prevent collisions\nacross contests
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on:
    • Merging semantics in getMergedTasksMap() and createTaskResults() to ensure contest_id/task_id preservation.
    • Signature change and optional-parameter handling in src/lib/services/tasks.ts.
    • Map-key construction, lookup, and update propagation in src/lib/components/TaskTables/TaskTable.svelte.
    • Tests/fixtures in src/test/lib/services/task_results.test.ts for correctness and Vitest hoisting/fixture alignment.

Poem

🐰 I hop through maps both wide and neat,
Keys stitched as "contest:task" keep collisions beat,
Merged answers and tasks in tidy array,
Tests hum the tune and components play,
A rabbit's nibble—refactor hooray! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: Enable to register tasks shared across multiple contests (#2346)" accurately and specifically describes the primary change in this changeset. The code modifications introduce a composite key scheme (ContestTaskPairKey using "contestId:taskId" format) across service and UI layers to precisely enable tasks shared across multiple contests. The title is clear, concise, and directly communicates the main feature being implemented without unnecessary noise or vagueness.
Linked Issues Check ✅ Passed The changes comprehensively address the linked issue #2346 which requires enabling registration and processing of tasks shared across multiple contests. The implementation introduces a composite key structure (ContestTaskPairKey) using "contestId:taskId" to prevent collisions when the same taskId exists in different contests, updates service layer functions (getTaskResults, getTaskResultsByTaskId, getTasksWithTagIds) to work with this composite key, refactors the merging logic via getMergedTasksMap, and updates the UI component (TaskTable.svelte) to consume the new key structure. All coding-related requirements from the linked issue are implemented.
Out of Scope Changes Check ✅ Passed All code changes in this pull request are directly related to the stated objective of supporting tasks shared across multiple contests. The changes include type definitions (ContestTaskPairKey, TaskMapByContestTaskPair, TaskResultMapByContestTaskPair), utility functions (createContestTaskPairKey), service layer refactoring (task_results.ts, tasks.ts), UI component updates (TaskTable.svelte), and test fixtures—all of which are essential to implementing the composite key scheme. No unrelated refactoring, feature additions, or scope creep is evident.

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e9fe02a and b846a3d.

📒 Files selected for processing (10)
  • docs/dev-notes/2025-10-26/impact-analysis/future_tasks.md (1 hunks)
  • docs/dev-notes/2025-10-26/impact-analysis/phase1-findings.md (1 hunks)
  • docs/dev-notes/2025-10-26/impact-analysis/phase2-analysis.md (1 hunks)
  • docs/dev-notes/2025-10-26/impact-analysis/plan.md (1 hunks)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)
  • src/lib/components/TaskTables/TaskTable.svelte (3 hunks)
  • src/lib/services/task_results.ts (4 hunks)
  • src/lib/services/tasks.ts (2 hunks)
  • src/test/lib/services/fixtures/task_results.ts (1 hunks)
  • src/test/lib/services/task_results.test.ts (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
docs/dev-notes/2025-10-26/impact-analysis/report.md

31-31: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


455-455: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


754-754: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

docs/dev-notes/2025-10-26/impact-analysis/plan.md

13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


188-188: Multiple headings with the same content

(MD024, no-duplicate-heading)


536-536: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


782-782: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


801-801: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/dev-notes/2025-10-26/impact-analysis/phase1-findings.md

111-111: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/dev-notes/2025-10-26/impact-analysis/phase2-analysis.md

328-328: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: preview
🔇 Additional comments (2)
docs/dev-notes/2025-10-26/impact-analysis/phase1-findings.md (1)

1-199: Documentation aligns well with PR objectives and provides comprehensive impact analysis.

The Phase 1 findings document effectively catalogs function call origins, Map usage patterns across layers, and risk assessment for the proposed composite key refactoring. The phased approach and prioritized fix sequence should help guide implementation.

One consideration: Verify that internal cross-references (e.g., report.md at line 35, Phase 2/3 planning materials) are documented and accessible to team members, so this analysis document remains actionable.

src/lib/services/task_results.ts (1)

219-227: Nice extraction of the merge path.

Pulling the shared merge logic into createTaskResults keeps the answer lookup and merge behavior consistent across callers, which should make future adjustments to the merge flow much easier.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
docs/dev-notes/2025-10-26/impact-analysis/report.md (3)

31-63: Add language identifier to fenced code block (line 31).

The code block displaying the layer structure diagram is missing a language specification. Markdown linting standard MD040 requires a language identifier.

-```
+```text
 レイヤ0: サービス層

455-462: Add language identifier to fenced code block (line 455).

This code block outlining future workbook adaptation steps is also missing a language specification per MD040.

-```
+```text
 将来的に Workbook が複数 contestId:taskId ペアを持つようになった場合:

754-754: Convert emphasis to proper heading (line 754).

The line uses bold emphasis (**レポート終了**) where a proper heading level would be more appropriate per MD036. If this is intended as a section divider, consider using a heading instead.

-**レポート終了**
+## レポート終了
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b846a3d and 14c1df5.

📒 Files selected for processing (3)
  • docs/dev-notes/2025-10-26/impact-analysis/phase1-findings.md (1 hunks)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)
  • src/test/lib/services/task_results.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/lib/services/task_results.test.ts
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
docs/dev-notes/2025-10-26/impact-analysis/report.md

31-31: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


455-455: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


754-754: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: preview
🔇 Additional comments (2)
docs/dev-notes/2025-10-26/impact-analysis/phase1-findings.md (1)

1-233: Document structure and content look solid.

Phase 1 findings are well-organized with clear sections documenting call sites, dependency flow, risk classification, and remediation priorities. The referenced file paths and line numbers provide helpful navigation for developers. Language identifier is correctly applied to the code block at line 111.

docs/dev-notes/2025-10-26/impact-analysis/report.md (1)

1-754: Report content is comprehensive and well-structured overall.

The impact analysis effectively maps the contested task pair key refactoring across all system layers. The phased approach (Phase 1–5), risk stratification (critical/major/minor), and test strategy demonstrate thorough planning. Cross-references to related documentation and clear actionable items for developers are helpful. The past concern about test file path reference has been corrected.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/dev-notes/2025-10-26/impact-analysis/report.md (1)

1-20: Verify document currency and cross-reference accuracy.

This impact analysis report references implementation details and specific file modifications. Given that previous corrections were made to this document (per past review comments), conduct a final pass to ensure:

  1. All section references and line numbers are still accurate after modifications
  2. Referenced code examples match the actual implementations
  3. The implementation status of proposed changes (Phase 1-A, 1-B, etc.) is reflected in the document

Consider adding a "Last Updated" or "Implementation Status" note (beyond the creation date at line 3) to help readers understand how current this guidance is.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 14c1df5 and 7535f53.

📒 Files selected for processing (1)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: preview
🔇 Additional comments (2)
docs/dev-notes/2025-10-26/impact-analysis/report.md (2)

551-574: Verify page paths in visual test checklist are current.

The visual test checklist references specific routes (/problems, /workbooks/[slug], /users/[username]). Ensure these paths and the described page behavior remain accurate given the refactoring scope and any subsequent routing changes.


163-234: Implementation verified successfully.

Both helper functions are correctly implemented in the codebase:

  • createTaskResults() exists at src/lib/services/task_results.ts:219 and is integrated at lines 42 and 344, receiving merged task results and merging them with user answers.
  • getMergedTasksMap(tasks?: Tasks) is correctly extended at src/lib/services/tasks.ts:41 with optional parameter and fallback logic (const tasksToMerge = tasks ?? (await getTasks())).
  • Integration pattern is correct: filtered tasks are passed to getMergedTasksMap() at line 341, then merged results are passed to createTaskResults() at line 344.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/dev-notes/2025-10-26/impact-analysis/report.md (2)

532-543: Add fixture file reference and clarify test structure.

Section VI.2 mentions new test creation at src/test/lib/services/task_results.test.ts but doesn't reference the companion fixture file src/test/lib/services/fixtures/task_results.ts noted in the AI summary. Consider adding a note about fixture organization for clarity.


700-708: Consider adding delimiter collision mitigation guidance.

Section X.4 identifies a potential risk with contestId = "abc:123" producing keys like "abc:123:task_a", which could break naive split(':') parsing. While the warning is present, consider adding a concrete code example or recommending a utility function to safely reverse the key format (e.g., parseContestTaskPairKey(key: string) that splits only on the last colon).

Example mitigation approach:

export function parseContestTaskPairKey(key: ContestTaskPairKey): { contestId: string; taskId: string } {
  const lastColonIndex = key.lastIndexOf(':');
  if (lastColonIndex === -1) {
    throw new Error(`Invalid ContestTaskPairKey format: ${key}`);
  }
  return {
    contestId: key.substring(0, lastColonIndex),
    taskId: key.substring(lastColonIndex + 1),
  };
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 7535f53 and 2d723fe.

📒 Files selected for processing (1)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: preview

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
docs/dev-notes/2025-10-26/impact-analysis/report.md (2)

173-183: Clarify the responsibility boundary for createTaskResults() helper placement.

Section 3.2 proposes a new createTaskResults() helper function (lines 174-183), but it's presented as a local helper within getTasksWithTagIds(). Clarify whether this function should be:

  1. Exported from task_results.ts (if it will be reused across multiple functions like getTaskResults(), getTasksWithTagIds(), and potentially getTaskResultsOnlyResultExists())
  2. Local to getTasksWithTagIds() (if used only in one place)

If option 1, add it to the public API and ensure all call sites import and use it consistently.


623-642: Add missing function getTasksWithTagIds() and clarify deletion step in Phase 1-A.

The implementation phase list at lines 623-627 omits getTasksWithTagIds(), which is a critical modification described in section 3.2. Additionally, the deletion of relateTasksAndAnswers() is described in section 3.1 but not explicitly listed in the phase checklist.

Update the Phase 1-A list (lines 623-627) to include both omitted tasks:

  1. **Phase 1-A: サービス層**
     - `mergeTaskAndAnswer` - `relateTasksAndAnswers` のメソッドの代わりに共通して利用
     - `getTaskResults()` - キー形式変更、戻り値型変更
+    - `getTasksWithTagIds()` - getMergedTasksMap + mergeTaskAndAnswer 統合
     - `getTaskResultsByTaskId()` - キー形式変更、戻り値型変更
+    - Delete `relateTasksAndAnswers()` - 関数を削除(getTaskResults に統合)
     - テスト作成(新規)

This ensures the implementation checklist is complete and developers don't overlook critical modifications.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2d723fe and 8e8deea.

📒 Files selected for processing (1)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: preview
🔇 Additional comments (1)
docs/dev-notes/2025-10-26/impact-analysis/report.md (1)

295-299: The review comment misdiagnoses which code has the parameter order problem.

The actual implementation in src/lib/services/task_results.ts (lines 238-242) confirms the function signature is mergeTaskAndAnswer(task: Task, userId: string, answer: ...), which matches the documentation at lines 295-299.

However, all call sites in the documentation (lines 112, 181, 341) incorrectly pass parameters as (userId, task, answer). The review comment incorrectly suggested changing the function signature when the call sites are actually wrong.

The documentation call sites must be corrected to match the actual function signature:

- return mergeTaskAndAnswer(userId, task, answer);
+ return mergeTaskAndAnswer(task, userId, answer);

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 8e8deea and 2951a5e.

📒 Files selected for processing (1)
  • docs/dev-notes/2025-10-26/impact-analysis/report.md (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: preview
🔇 Additional comments (2)
docs/dev-notes/2025-10-26/impact-analysis/report.md (2)

1-50: Comprehensive and well-structured impact analysis.

This report demonstrates excellent foresight in breaking down a significant architectural change (composite key adoption) across all affected layers: service, page server, component, utility, and test. The phase-based implementation plan (Section VIII) with clear priority sequencing, risk assessment (Section VII), and detailed test strategy (Section VI) significantly reduce the likelihood of regressions. The decision to maintain backward compatibility for workbooks while documenting future extensibility (Section 10.3) is prudent.


712-722: Consider validating delimiter safety in contest-task-pair key generation.

The cautionary note about colon-delimited keys (e.g., contestId:abc:123:taskId) is sound. While the document suggests splitting by the last colon, confirm that createContestTaskPairKey() and any deserialization logic include guards against contestId/taskId values containing colons. If these fields are user-controllable, consider escaping or validation to prevent key ambiguity.

Can you verify that the implementation of createContestTaskPairKey() (referenced at line 692) includes safeguards against colon characters in input values, or document any assumptions about input constraints?

Copy link
Collaborator Author

@KATO-Hiro KATO-Hiro left a comment

Choose a reason for hiding this comment

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

LGTM

@KATO-Hiro KATO-Hiro merged commit c291fa1 into staging Nov 1, 2025
3 checks passed
@KATO-Hiro KATO-Hiro deleted the #2346 branch November 1, 2025 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

複数のコンテストで共有されている問題を登録・処理できるようにしましょう

1 participant