Skip to content

Conversation

@devondragon
Copy link
Owner

@devondragon devondragon commented Sep 22, 2025

This pull request adds robust support for advanced recurring task patterns in the Motion API integration. The main focus is on expanding the frequency object to handle all patterns supported by the Motion API, including biweekly, quarterly, and custom patterns, and introducing a utility for transforming and validating these frequency objects. The changes ensure that recurring task creation is both flexible and reliable, with validation and correct transformation of input data.

Recurring Task Frequency Support

  • Expanded the frequency object in CreateRecurringTaskData, MotionRecurringTasksArgs, and tool definitions to support new types (biweekly, quarterly, custom) and additional fields (weekOfMonth, monthOfQuarter, customPattern). This enables all Motion API recurrence patterns and more granular scheduling options. [1] [2] [3]

  • Updated the recurringTasksToolDefinition schema to include new frequency types and fields, improving documentation and validation for API consumers.

Frequency Transformation and Validation

  • Added a new utility module frequencyTransform.ts with functions to transform a frequency object into the Motion API string format and validate frequency objects before use. This ensures only valid and correctly formatted patterns are sent to the API.

  • Integrated frequency transformation and validation into the MotionApiService.createRecurringTask method, so tasks are created with the correct API-compatible frequency string and input errors are caught early.

Test and Import Updates

  • Updated imports in relevant files (motionApi.ts, utils.spec.ts) to use the new transformation and validation utilities, and added basic test coverage for these functions. [1] [2]

Configuration

  • Added "WebFetch(domain:github.com)" to the .claude/settings.local.json allowlist, likely to support new API interactions or testing.

devondragon and others added 2 commits September 21, 2025 16:51
Implements comprehensive frequency transformation system to convert
frequency objects to Motion API's expected string patterns.

Key changes:
- Add FrequencyObject interface supporting all Motion API patterns
- Create transformFrequencyToApiString() with 40+ pattern support
- Add validateFrequencyObject() with type-specific validation
- Update createRecurringTask to use transformation and preserve endDate
- Extend tool definitions to support biweekly, quarterly, custom types

API Pattern Support:
- Daily: daily_every_day, daily_every_week_day, daily_specific_days_[...]
- Weekly: weekly_any_day, weekly_any_week_day, weekly_specific_days_[...]
- Biweekly: biweekly_first/second_week_* patterns
- Monthly: monthly_1-31, monthly_first_MO, monthly_any_day_*_week, etc.
- Quarterly: quarterly_first_day, quarterly_last_FR, quarterly_*_week, etc.
- Custom: Direct API pattern passthrough

Backward Compatibility:
- Legacy interval mapping: weekly + interval:2 → biweekly patterns
- Preserves endDate and other fields during transformation

Validation Fixes:
- Biweekly validation restricted to 'first'/'second' weekOfMonth only
- Monthly weekOfMonth-only patterns properly handled
- Prevents silent coercion of invalid patterns

Comprehensive test coverage for all patterns and edge cases.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 22, 2025 01:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes Issue 39 by implementing proper frequency type handling for recurring tasks. The main issue was that frequency objects were not being properly transformed into the API string format required by the Motion API.

  • Added comprehensive frequency transformation utilities to convert frequency objects to Motion API string format
  • Expanded frequency type support to include biweekly, quarterly, and custom patterns
  • Updated type definitions across the codebase to support the enhanced frequency structure

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/utils/frequencyTransform.ts New utility module with comprehensive frequency transformation and validation logic
tests/utils.spec.ts Extensive test suite covering all frequency transformation patterns and validation scenarios
src/types/motion.ts Updated frequency type definition to support new patterns and fields
src/types/mcp-tool-args.ts Updated MCP tool args frequency type to match motion types
src/tools/ToolDefinitions.ts Enhanced tool definition with new frequency fields and better documentation
src/services/motionApi.ts Integrated frequency transformation into recurring task creation
.claude/settings.local.json Added WebFetch permission for GitHub domain

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

}

if (daysOfWeek && isWeekdaysPattern(daysOfWeek)) {
return 'quarterly_first_week_day';
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

This return statement is unreachable code. The function will always return at line 227 (quarterly_first_day) before reaching this line, since there's no condition that would execute this path.

Suggested change
return 'quarterly_first_week_day';
// unreachable: removed

Copilot uses AI. Check for mistakes.
- Fix unreachable quarterly pattern logic that prevented weekdays-only patterns
- Add biweekly validation to restrict weekOfMonth to 'first'/'second' only
- Remove unused dayOfMonth parameter from transformQuarterlyPattern
- Add test coverage for previously unreachable quarterly_first_week_day pattern
- Prevent silent coercion of invalid biweekly patterns to 'first' week

Changes:
- Restructured quarterly pattern conditional logic for proper execution flow
- Added type-specific biweekly validation preventing invalid week values
- Enhanced test suite with edge cases for biweekly and quarterly patterns
- Updated Claude settings to include zen:analyze tool permissions

Addresses feedback about unreachable code and silent pattern coercion.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@devondragon devondragon requested a review from Copilot September 22, 2025 01:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 173 to 175
// Default to first week for multiple specific days
const dayAbbrevs = formatDayAbbreviations(daysOfWeek);
return `monthly_first_${dayAbbrevs.split(', ')[0]}`; // Take first day
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

The fallback for multiple specific days in a month without weekOfMonth collapses the user’s full selection to only the first day (e.g. [MO, WE, FR] -> monthly_first_MO), losing intent and producing an inaccurate recurrence. A safer approach would be to either throw/require weekOfMonth, map to a supported aggregate pattern, or explicitly document unsupported multi-day monthly patterns instead of silently narrowing.

Suggested change
// Default to first week for multiple specific days
const dayAbbrevs = formatDayAbbreviations(daysOfWeek);
return `monthly_first_${dayAbbrevs.split(', ')[0]}`; // Take first day
// Multiple specific days without weekOfMonth is not supported: throw or return explicit error
throw new Error('Unsupported multi-day monthly pattern without weekOfMonth. Please specify weekOfMonth or select a supported pattern.');
// Alternatively, could return a string: return 'UNSUPPORTED_MULTI_DAY_MONTHLY_PATTERN';

Copilot uses AI. Check for mistakes.
Comment on lines 191 to 224
function transformQuarterlyPattern(daysOfWeek?: number[], weekOfMonth?: string, monthOfQuarter?: number): string {
// Handle quarterly with specific day-of-week
if (daysOfWeek && daysOfWeek.length === 1) {
const dayAbbrev = DAY_ABBREVIATIONS[daysOfWeek[0] as keyof typeof DAY_ABBREVIATIONS];
if (weekOfMonth === 'first') {
return `quarterly_first_${dayAbbrev}`;
}
if (weekOfMonth === 'last') {
return `quarterly_last_${dayAbbrev}`;
}
// Default to first if no week specified
return `quarterly_first_${dayAbbrev}`;
}

// Handle quarterly with week patterns
if (weekOfMonth) {
if (daysOfWeek && isWeekdaysPattern(daysOfWeek)) {
return `quarterly_any_week_day_${weekOfMonth}_week`;
}
return `quarterly_any_day_${weekOfMonth}_week`;
}

// Handle quarterly with month patterns
if (monthOfQuarter) {
return `quarterly_any_day_${getMonthOrdinal(monthOfQuarter)}_month`;
}

// Handle remaining patterns
if (daysOfWeek && isWeekdaysPattern(daysOfWeek)) {
return 'quarterly_first_week_day';
}

// Default pattern (includes dayOfMonth cases)
return 'quarterly_first_day';
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

dayOfMonth is never considered for quarterly patterns (line 224 comment states it “includes dayOfMonth cases”), so providing a valid quarterly frequency with dayOfMonth (and monthOfQuarter or weekOfMonth, which validation allows) will silently discard that intent. Either incorporate dayOfMonth into the pattern generation or reject quarterly inputs containing dayOfMonth to avoid silent data loss.

Copilot uses AI. Check for mistakes.
Comment on lines 223 to 225
// Default pattern (includes dayOfMonth cases)
return 'quarterly_first_day';
}
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

For quarterly patterns where daysOfWeek has multiple specific (non-weekday-pattern) entries (e.g. [MO, WE, FR]) this falls through to 'quarterly_first_day', dropping all selected days. This mirrors the monthly multi-day issue; consider explicitly rejecting unsupported multi-day selections or mapping to a closest valid pattern instead of silently narrowing.

Suggested change
// Default pattern (includes dayOfMonth cases)
return 'quarterly_first_day';
}
// Explicitly reject unsupported multi-day selections
if (daysOfWeek && daysOfWeek.length > 1 && !isWeekdaysPattern(daysOfWeek)) {
throw new Error('Unsupported multi-day selection for quarterly patterns: ' + JSON.stringify(daysOfWeek));
}
// Default pattern (includes dayOfMonth cases)
return 'quarterly_first_day';

Copilot uses AI. Check for mistakes.
Comment on lines 1927 to 1928
if (!validateFrequencyObject(taskData.frequency)) {
throw new Error('Invalid frequency object provided');
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

The error message is generic and gives no actionable detail; exposing which field failed (or returning an error code) would aid debugging. Consider enhancing validateFrequencyObject to return a discriminated result (e.g. { valid: false, reason: 'weekOfMonth not allowed for daily' }) and include that in the thrown error.

Suggested change
if (!validateFrequencyObject(taskData.frequency)) {
throw new Error('Invalid frequency object provided');
const freqValidation = validateFrequencyObject(taskData.frequency);
if (!freqValidation.valid) {
throw new Error(`Invalid frequency object: ${freqValidation.reason || 'Unknown reason'}`);

Copilot uses AI. Check for mistakes.
type: "array",
items: { type: "number" },
description: "0-6 for Sunday-Saturday (for weekly)"
description: "0-6 for Sunday-Saturday. Used with daily/weekly/biweekly for specific days"
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

Description omits that daysOfWeek is also used for monthly and quarterly patterns in transform logic (e.g. monthly_first_MO, quarterly_first_MO). Update to reflect all supported contexts to prevent under-documenting feature capability.

Suggested change
description: "0-6 for Sunday-Saturday. Used with daily/weekly/biweekly for specific days"
description: "0-6 for Sunday-Saturday. Used with daily/weekly/biweekly for specific days, and with monthly/quarterly patterns (e.g., monthly_first_MO, quarterly_first_MO) for specifying days in those recurrence types"

Copilot uses AI. Check for mistakes.
dayOfMonth: {
type: "number",
description: "1-31 for monthly recurrence"
description: "1-31 for monthly/quarterly recurrence on specific day of month"
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

States quarterly support, but quarterly transform currently ignores dayOfMonth entirely; either implement quarterly dayOfMonth handling or narrow this description to monthly only to avoid misleading API consumers.

Suggested change
description: "1-31 for monthly/quarterly recurrence on specific day of month"
description: "1-31 for monthly recurrence on specific day of month"

Copilot uses AI. Check for mistakes.
weekOfMonth: {
type: "string",
enum: ["first", "second", "third", "fourth", "last"],
description: "Which week of month/quarter for monthly/quarterly patterns with daysOfWeek"
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

The implementation supports weekOfMonth without daysOfWeek for both monthly (monthly_any_day_first_week, etc.) and quarterly (quarterly_any_day_first_week). Remove “with daysOfWeek” or clarify that it is optional.

Suggested change
description: "Which week of month/quarter for monthly/quarterly patterns with daysOfWeek"
description: "Which week of month/quarter for monthly/quarterly patterns; daysOfWeek is optional (e.g., monthly_any_day_first_week or monthly_monday_first_week)"

Copilot uses AI. Check for mistakes.
This commit comprehensively addresses all 9 Copilot review comments by improving error handling, validation consistency, and documentation accuracy for recurring task frequency patterns.

## Key Improvements

**Error Handling & User Experience:**
- Replace silent data loss with descriptive error messages for unsupported multi-day patterns
- Enhanced validation with detailed, actionable error descriptions instead of generic failures
- Consistent error handling between transformer and validator functions

**Implementation Consistency:**
- Fixed quarterly patterns to properly reject dayOfMonth (not implemented in transform logic)
- Added explicit rejection of unsupported multi-day selections with clear error messages
- Transformer now throws errors for invalid days instead of silently filtering them

**Documentation & Type Safety:**
- Updated tool definition descriptions to accurately reflect actual behavior
- Centralized FrequencyObject type definition across all files to prevent drift
- Added backward compatibility function to maintain existing API

**Validation Improvements:**
- Enhanced validateFrequencyObject to return detailed validation results
- Added specific type-based validation rules that match implementation capabilities
- Improved field validation with precise error messages for debugging

## Technical Changes

- **src/utils/frequencyTransform.ts**: Centralized imports, enhanced error handling, detailed validation
- **src/types/motion.ts**: Added central FrequencyObject interface
- **src/types/mcp-tool-args.ts**: Updated to use centralized type definition
- **src/tools/ToolDefinitions.ts**: Corrected field descriptions to match implementation
- **src/services/motionApi.ts**: Updated to use detailed validation results
- **tests/utils.spec.ts**: Updated tests to reflect new validation behavior

All tests passing ✅ | TypeScript compilation clean ✅

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@devondragon devondragon requested a review from Copilot September 22, 2025 01:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

… links

Implemented Copilot's suggestions to improve user experience with more helpful error messages:

## Enhanced Error Messages

**Monthly Multi-Day Patterns:**
- Added specific pattern examples (monthly_1-31, monthly_first_MO, monthly_last_TU)
- Included documentation link to Motion API frequency cookbook
- Provides clear guidance on supported alternatives

**Quarterly Multi-Day Patterns:**
- Explains why multi-day selection is unsupported
- Lists specific supported patterns (single day-of-week, weekdays, any day)
- Includes direct link to quarterly patterns documentation

## Testing
- Added tests to verify improved error message content
- All existing tests continue to pass
- TypeScript compilation successful

These changes significantly improve developer experience by providing actionable guidance when users encounter unsupported frequency patterns.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@devondragon devondragon self-assigned this Sep 22, 2025
@devondragon devondragon added bug Something isn't working enhancement New feature or request labels Sep 22, 2025
@claude
Copy link

claude bot commented Sep 28, 2025

Code Review for PR #43: Recurring Task Frequency Support

Thank you for this comprehensive PR that addresses issue #39! The implementation adds robust support for advanced recurring task patterns in the Motion API. Here's my review:

✅ Strengths

  1. Excellent Architecture: The separation of concerns with a dedicated frequencyTransform.ts module is clean and maintainable. The transformation logic is well-organized and follows the single responsibility principle.

  2. Comprehensive Pattern Support: The implementation supports all Motion API frequency patterns including biweekly, quarterly, and custom patterns - a significant improvement over the previous limited support.

  3. Strong Validation: The dual validation approach (validateFrequencyObject with detailed errors and legacy isValidFrequencyObject) provides good error handling while maintaining backward compatibility.

  4. Good Documentation: Well-documented functions with clear JSDoc comments explaining the supported patterns and linking to Motion API documentation.

  5. Thoughtful Error Messages: Error messages are descriptive and helpful, pointing users to the Motion API documentation when encountering unsupported patterns.

  6. Test Coverage: The test suite is comprehensive, covering basic patterns, edge cases, validation scenarios, and error conditions.

🔍 Observations & Suggestions

  1. endDate Handling: The code correctly preserves endDate when creating the API payload (line 1949 in motionApi.ts). This is good, but consider documenting this behavior more explicitly in the function comments.

  2. Legacy Support: The interval mapping (weekly + interval:2 → biweekly) is a nice backward compatibility feature. Consider adding a deprecation notice in the tool definition documentation to guide users toward the new biweekly type.

  3. Type Safety: The TypeScript types are well-defined with the new FrequencyObject interface. The union types for the frequency patterns provide good compile-time safety.

  4. Performance: The validation and transformation logic is efficient with no performance concerns. The functions are pure and have minimal overhead.

🐛 Potential Issues

  1. Missing Validation for dayOfMonth: When monthly type is used with both dayOfMonth and daysOfWeek, the current logic prioritizes dayOfMonth (line 138-140 in frequencyTransform.ts). Consider validating this scenario to prevent confusion:

    // Currently allows both but only uses dayOfMonth
    { type: 'monthly', dayOfMonth: 15, daysOfWeek: [1] }
    
  2. Biweekly Week Default: When using biweekly without specifying weekOfMonth, it defaults to 'first' (line 62). This is reasonable but should be documented in the tool definition.

💡 Recommendations

  1. Consider adding a migration guide or examples in the README for users transitioning from the old frequency format to the new one.

  2. The test dependencies issue (vitest not found) should be addressed separately - tests can't run in the CI environment currently.

  3. Consider adding integration tests with actual Motion API calls (perhaps in a separate test file) to ensure the transformed patterns work correctly with the API.

✅ Security & Best Practices

  • No security concerns identified
  • Proper input validation prevents injection attacks
  • Error handling follows best practices with detailed logging
  • No sensitive data exposure in error messages

Verdict

APPROVED ✅ - This is a well-implemented feature that significantly improves the recurring task functionality. The code is clean, well-tested, and follows the project's architectural patterns. The minor suggestions above are optional improvements that could be addressed in a follow-up PR if desired.

Great work on this implementation! The attention to detail in validation and error handling is particularly commendable.

@devondragon devondragon merged commit 04f1893 into main Sep 28, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants