Review: Schedule image digestion: Claude Vision OCR to WorkQueueItems
Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, extends Upload tab (#33)
- [x] Repo -- ldraney/landscaping-assistant
- [x] User Story -- crew lead schedule parsing
- [x] Context -- thorough, covers column-overflow, handwritten additions, existing infra
- [x] File Targets -- create 3, modify 5, explicit do-not-touch list
- [x] Feature Flag -- none, justified (extension of existing upload flow)
- [x] Acceptance Criteria -- 8 criteria
- [x] Test Expectations -- 4 test expectations with run command
- [x] Constraints -- Claude model, API key source, fuzzy matching approach
- [x] Checklist -- standard 3-item
- [x] Related -- references project and parent issue #33
Traceability
- [x] story:schedule-upload label -- present on board item
- [x] story note verified -- found in project-landscaping-assistant user-stories section: "Snap a photo of the paper schedule for later reference"
- [ ] story note OUTDATED -- [SCOPE] The user story summary says "Snap a photo of the paper schedule for later reference" but this ticket extends the story to include AI-powered parsing into WorkQueueItems. The user story success metric should be updated to reflect schedule digestion, not just photo upload.
- [x] arch:rails-app label -- present on board item
- [ ] arch note MISSING -- [SCOPE] No architecture note found for arch-rails-app in pal-e-docs. Search returned zero results. Create architecture note arch-rails-app for the Rails application component.
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/landscaping-assistant/issues/204, state: open
File Targets
Files to create:
- [x]
app/services/schedule_digester.rb-- directoryapp/services/does not exist yet (must be created). This is standard Rails convention, acceptable. - [x]
app/views/uploads/digest.html.erb-- parent directory exists, confirmed - [x]
db/migrate/TIMESTAMP_add_week_start_to_uploads.rb-- standard migration, OK
Files to modify:
- [x]
Gemfile-- verified exists. Noanthropicgem present currently. Correct target. - [x]
app/controllers/uploads_controller.rb-- verified exists. Currently has index/show/create/edit/update/destroy. Adding digest and confirm_digest actions is appropriate. - [ ]
app/models/upload.rb-- ISSUE: ticket says "add has_many :work_queue_items through digest" but there is no digest join model defined anywhere in the issue. The Upload model currently has onlyhas_one_attached :photoand no associations. The relationship between Upload and WorkQueueItems needs clarification -- is it a direct has_many or through a join table? [BODY] - [x]
config/routes.rb-- verified exists. Currentlyresources :uploads, only: [:index, :show, :create, :edit, :update, :destroy]. Adding member routes for digest/confirm_digest is correct. - [x]
app/views/uploads/show.html.erb-- verified exists. Adding "Digest Schedule" button is straightforward.
Do-not-touch files:
- [x]
app/models/property.rb-- confirmed, no schema changes needed. Property already hasvalidates :client_name, presence: true. - [x]
app/controllers/weeks_controller.rb-- confirmed, week view stays unchanged.
Repo Placement
OK -- issue filed on ldraney/landscaping-assistant, all file targets are in this repo. Single-repo change, no cross-repo concerns.
Dependencies
- [x] Issue #33 (Upload tab) -- done, in done column on board. Upload model and controller exist and work.
- [x] WorkQueueItem model -- exists with work_date, property_id (unique per date), position fields.
- [x] Property model -- exists with client_name field for fuzzy matching.
- [x] Anthropic API key -- confirmed at ~/secrets/anthropic/credentials.env, key present.
- No blocking items found on the board. No items in in_progress that conflict.
Acceptance Criteria
8 acceptance criteria. All are testable by an agent:
- AC1-3: Vision API call and response parsing -- testable via mocked API response in unit tests
- AC4: Fuzzy matching -- testable with known property fixtures
- AC5: Confirmation screen -- testable via system/request spec checking HTML response
- AC6: WorkQueueItem creation -- testable via request spec with confirm action
- AC7: No new Property records -- testable via assertion on Property.count
- AC8: Duplicate detection -- testable via uniqueness constraint (already exists:
validates :property_id, uniqueness: { scope: :work_date })
Missing criteria: No AC for error handling when Claude Vision API is unavailable or returns malformed JSON. Should add resilience AC.
Blast Radius
- WorkQueueItem uniqueness constraint already exists (
index_work_queue_items_on_work_date_and_property_id, unique: true) -- AC8 duplicate detection is already enforced at DB level. The service should handle ActiveRecord::RecordNotUnique gracefully. - Upload model gains a new field (week_start) and potentially new associations -- existing upload tests (if any) should still pass.
- No existing fuzzy matching patterns in the codebase -- this is net-new functionality.
- Adding the anthropic gem adds an external API dependency. No other external AI/ML gems exist in the project currently.
Decomposition Assessment
File count: 3 new + 5 modified = 8 files in 1 repo. AC count: 8 acceptance criteria + 4 test expectations. This is a substantial ticket but all within one repo and one logical feature. The service object pattern (ScheduleDigester) encapsulates the core complexity. Estimated agent work: ~8-10 minutes due to Vision API integration, fuzzy matching implementation, and confirmation UI.
Borderline on decomposition. The ticket could be split into: (1) ScheduleDigester service + tests, (2) controller actions + views + routes. However, the two halves are tightly coupled (the view renders ScheduleDigester output). Recommending single pass with careful AC ordering, but flagging for awareness.
Recommendations
[BODY]Clarify the Upload-to-WorkQueueItem relationship in File Targets. The issue says "has_many :work_queue_items through digest" but no digest join model is defined. Either: (a) define a direct association with an upload_id foreign key on work_queue_items, or (b) make the relationship implicit (ScheduleDigester creates WorkQueueItems but Upload has no ActiveRecord association to them). Option (b) is simpler and matches the "digestion" metaphor -- the upload is consumed, not permanently linked.[BODY]Add an acceptance criterion for error handling: "When Claude Vision API returns an error or malformed response, the user sees a clear error message and no WorkQueueItems are created."[SCOPE]Update the schedule-upload user story on project-landscaping-assistant to reflect AI-powered parsing. Current summary: "Snap a photo of the paper schedule for later reference." Proposed: "Photograph the paper schedule and parse it into daily work queues via AI vision."[SCOPE]Create architecture note arch-rails-app for the Rails application component.