fix: exclude html_content from list_boards response (#276) #277
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/pal-e-api!277
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/list-boards-exclude-html"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
list_boardsreturned 57K chars because every board includedhtml_content. One board alone carried 10K of HTML. This exceeded the MCP token limit, breaking the tool call. Fix excludeshtml_contentfrom the listing endpoint; detail endpoint is unchanged.Changes
BoardListOutschema (inheritsBoardOutminushtml_content)GET /boardsusesBoardListOut— 70% smaller response (57K -> 17K chars)GET /boards/{slug}still returns fullBoardOutwithhtml_content_board_counts()helper to deduplicate count logicTest Plan
list_boardsMCP tool returns inline after deploy (no overflow)get_board(slug)still includeshtml_contentReview Checklist
Related Notes
Closes #276
PR #277 Review
DOMAIN REVIEW
Tech stack: Python / FastAPI / Pydantic / SQLAlchemy
Schema design (schemas.py):
The inheritance direction is correct --
BoardListOutis the base with shared fields,BoardOutextends it by addinghtml_content. This is clean Pydantic inheritance and means any future shared field additions only need to touchBoardListOut. Themodel_configon the base class is inherited byBoardOut, which is correct behavior.Helper extraction (boards.py):
_board_counts()is cleanly extracted. The count loop logic is now in one place, called by both_board_to_list_out()and_board_to_out(). No behavioral change in the count logic itself.Route change:
GET /boardsswitches fromresponse_model=list[BoardOut]toresponse_model=list[BoardListOut]and uses the new_board_to_list_out()helper.GET /boards/{slug}andPOST /boardsare unchanged and still return fullBoardOut. Correct.BLOCKERS
None.
NITS
DRY in helper functions:
_board_to_list_out()and_board_to_out()duplicate the same field mapping (id, slug, name, project_slug, item_counts, created_at, updated_at). SinceBoardOutinherits fromBoardListOut,_board_to_outcould construct aBoardListOutfirst and unpack it:This keeps the field mapping in one place. Not blocking since the field list is short and localized.
Test coverage for the new behavior: No existing test validates that
html_contentis absent fromGET /boardsresponses or present inGET /boards/{slug}responses. The existingtest_list_boards(line 85) only checks status code and count. Thetest_existing_fields_preserved(line 1130) validatesPOST /boards(which still returnsBoardOut), not the listing endpoint. Adding two assertions would lock down the contract:GET /boardsresponse items do NOT containhtml_contentGET /boards/{slug}response DOES containhtml_contentNot a blocker since this is a subtractive change with 709 passing tests, but it would prevent accidental regressions.
Blank line removal (boards.py): The original
_board_to_outhad a blank line between the query and thecounts = BoardItemCounts()line. The new_board_countsremoves it. Trivial, but consistent with the rest of the file style (no blank lines between sequential statements in helpers).SOP COMPLIANCE
Closes #276in PR bodyPROCESS OBSERVATIONS
VERDICT: APPROVED