Skip to content

Apply 4-layer ResourceId decoupling to Cloze activity#201

Merged
davidortinau merged 2 commits intomainfrom
fix/cloze-resourceid-decoupling-200
May 3, 2026
Merged

Apply 4-layer ResourceId decoupling to Cloze activity#201
davidortinau merged 2 commits intomainfrom
fix/cloze-resourceid-decoupling-200

Conversation

@davidortinau
Copy link
Copy Markdown
Owner

Closes #200

Summary

Implements full vocabulary-driven mode for Cloze when launched from Today's Plan, matching the established pattern from VocabQuiz (#190 fix) and VocabMatching fixes.

The 4 Layers

Layer 1 - DeterministicPlanBuilder.cs (~line 505):
Set ResourceId = outputActivity == "Cloze" ? null : resource.Id when stamping the planned activity.

Layer 2 - PlanConverter.cs (~line 140):
Add Cloze branch that sets DueOnly = true and passes SkillId but NOT ResourceId.

Layer 3 - Index.razor (~line 986):
Extend the existing exclusion list to include PlanActivityType.Cloze so persisted plan items can't leak a stale ResourceId.

Layer 4 - Cloze.razor + ClozureService:

  • Add DueOnly query parameter to Cloze.razor
  • Add GetSentencesFromDueWords() method that loads due vocab globally
  • Add GenerateSentencesFromWords() helper to eliminate code duplication
  • When DueOnly=true, generate sentences from full user vocab pool using SRS logic
  • When DueOnly=false, preserve existing resource-filtered behavior (backward compatible)

Implementation Details

  • No database migration needed — persisted DailyPlan rows with old ResourceId are masked by Layer 3 guard at the UI boundary
  • Backward compatible — direct (non-plan) Cloze launches still go through the resource-driven path
  • No breaking changes — all existing ClozureService signatures preserved, new overload added

Testing

✅ Build passes (0 errors, 397 warnings - all pre-existing)
✅ E2E smoke test via webapp:

  • Today's Plan → Cloze loads sentences successfully (8 sentences generated)
  • Vocab Quiz from plan still works (regression test passed)
  • Screenshot evidence attached

References

  • Decision spec: .squad/decisions/inbox/keaton-200-cloze-resourceid-decoupling.md
  • Pattern documentation: .squad/skills/resource-id-decoupling/SKILL.md
  • VocabQuiz decoupling: commits 88a0272, c081a63
  • VocabMatching decoupling: commit 0c8e197

davidortinau and others added 2 commits May 3, 2026 09:39
Implements full vocabulary-driven mode for Cloze when launched from Today's Plan,
matching the established pattern from VocabQuiz and VocabMatching fixes.

Layer 1 - DeterministicPlanBuilder: Set ResourceId=null for Cloze planned activities
Layer 2 - PlanConverter: Add Cloze branch with DueOnly=true, skip ResourceId
Layer 3 - Index.razor: Extend guard to prevent ResourceId leak from persisted plans
Layer 4 - Cloze.razor + ClozureService:
  - Add DueOnly query parameter to Cloze.razor
  - Add GetSentencesFromDueWords() method that loads due vocab globally
  - Add GenerateSentencesFromWords() helper to eliminate code duplication
  - When DueOnly=true, generate sentences from full user vocab pool
  - When DueOnly=false, preserve existing resource-filtered behavior

No database migration needed - persisted DailyPlan rows with old ResourceId
are masked by Layer 3 guard at the UI boundary.

Closes #200

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Fenster's history and decision documentation for issue #200:
- Create .squad/agents/fenster/history.md with learnings from Cloze fix
- Create .squad/decisions/inbox/fenster-200-shipped.md documenting what shipped
- Update .squad/skills/resource-id-decoupling/SKILL.md with Cloze examples
  for all 4 layers (builder, converter, Index guard, page defense)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidortinau davidortinau merged commit 2995cad into main May 3, 2026
2 of 6 checks passed
@davidortinau davidortinau deleted the fix/cloze-resourceid-decoupling-200 branch May 3, 2026 15:35
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.

Today's Plan launches empty Cloze activity

1 participant