critical priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

Single record success: a record with valid registered_by and attributed_to is accepted and the service returns the persisted Activity with both fields populated
Missing registered_by: a record without registered_by throws AttributionValidationError with field='registered_by' in its payload
Missing attributed_to: a record without attributed_to throws AttributionValidationError with field='attributed_to' in its payload
Batch mixed valid/invalid: a batch of 3 records where 1 is invalid returns BatchPartialFailureResult listing the invalid record's index and error type, while the 2 valid records are reported as succeeded
Audit query – coordinator filter: getAuditLog(coordinatorId: X) returns only records where registered_by = X AND attributed_to ≠ X (i.e., proxy entries)
Audit query – mentor self-registered filter: getAuditLog(mentorId: X, selfOnly: true) returns only records where registered_by = X AND attributed_to = X
DuplicateDetectionService mock is injected to control duplicate-check outcomes in attribution tests
All tests pass with `flutter test` with zero warnings

Technical Requirements

frameworks
Flutter
Dart
flutter_test
data models
activity
performance requirements
All unit tests complete in under 5 seconds total
security requirements
Tests must verify that registered_by cannot be overridden by caller-supplied payload (service must always enforce its own source for this field)

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Dependents (28)
epic-proxy-activity-registration-orchestration-task-001 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-002 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-003 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-004 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-005 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-006 component Cross-Epic Component bulk-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-007 component Cross-Epic Component bulk-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-008 component Cross-Epic Component bulk-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-009 component Cross-Epic Component bulk-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-010 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-orchestration-task-011 component Cross-Epic Component bulk-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-001 component Cross-Epic Component bulk-participant-list depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-002 component Cross-Epic Component bulk-participant-list depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-003 component Cross-Epic Component bulk-participant-list depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-004 component Cross-Epic Component duplicate-warning-dialog depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-005 component Cross-Epic Component duplicate-warning-dialog depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-006 component Cross-Epic Component duplicate-warning-dialog depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-007 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-008 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-009 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-010 component Cross-Epic Component proxy-activity-form depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-011 component Cross-Epic Component proxy-activity-form depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-012 component Cross-Epic Component proxy-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-013 component Cross-Epic Component proxy-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-014 component Cross-Epic Component proxy-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-015 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-016 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-ui-task-017 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service

Implementation Notes

AttributionValidationError should carry a field name property so tests can assert which field caused the failure — this is critical for building meaningful error messages in the UI layer. For the audit query tests, the service method should accept a filter parameter (e.g., AuditFilter.proxyOnly, AuditFilter.selfOnly) rather than raw booleans to keep the interface extensible. Verify that batch tests use a list of exactly 3 records to keep fixtures minimal while covering all paths. Use fake UUIDs that are visually distinguishable (e.g., mentor-uuid-1111, coordinator-uuid-2222) to make test assertions readable.

Testing Requirements

Pure unit tests using flutter_test. Mock both ActivityRepository and DuplicateDetectionService. In tests that focus on attribution validation, configure DuplicateDetectionService mock to return no conflicts so it does not interfere. In integration-path tests (task-007 integration), configure it to return a conflict to verify error propagation.

Use expect(() => service.register(record), throwsA(isA())) pattern for error assertions. Group tests: attribution validation, batch handling, audit queries.

Component
Activity Attribution Service
service low
Epic Risks (2)
medium impact medium prob scope

Overly strict duplicate matching (exact date + type) may flag legitimate back-to-back sessions of the same activity type on the same day as duplicates, frustrating coordinators and undermining trust in the feature.

Mitigation & Contingency

Mitigation: Confirm with product owners whether the matching key should be (mentor_id, date, activity_type_id) only or should also consider duration and time-of-day. Document the chosen threshold in the service and surface it in the duplicate warning dialog for transparency.

Contingency: If false-positive rates are high in user testing, add a duration-window tolerance parameter to the detection query that can be tuned without code changes.

high impact low prob security

If the current session token is invalidated between the coordinator starting the proxy form and submitting it, the activity-attribution-service may fail to resolve the coordinator's user ID, causing a silent attribution error.

Mitigation & Contingency

Mitigation: Read the coordinator's user ID from the session at service call time rather than at form-open time. Validate the session is still active before committing the insert, and surface a clear re-authentication prompt if it has expired.

Contingency: If a mis-attributed record is detected post-submission, the audit log retains the original session metadata, allowing a corrective record to be created with accurate attribution.