QA Run — 2026-07-04 (Docs domain — full live run)¶
Auth: OAuth
Fixtures: DOC_ID=1-whiEVwvnSOABaK9qgpzdVaGUOMRvJdQhDmCURqx4fA (mcp-gee-sweet-qa-fixtures-doc) · TEST_LARGE_DOC_ID=10UAHiKxHAmjqZt4PCoB53afJZoPN7OTRf71EBsFC6cI
Start: 2026-07-05 03:14 UTC · End: 2026-07-05 04:11 UTC (run completed across two sessions, separated by an OAuth token revocation and a later transient API outage) · Duration: ~00:14 (session 1) + ~00:11 (session 2)
Scope: Full live run of docs/qa/tests/docs.md (81 TCs), ordered by the run.md conductor pattern. This domain was targeted for a full run (not a scoped/spot-check run) because docs/__init__.py was structurally split into submodules for this release (issue #232) and had never had a live Domain run since that reorg.
Run history: Session 1 completed TC-DOC01–47 and TC-DOC78–79 (49 TCs) before halting on a server-wide OAuth refresh-token revocation (invalid_grant: Token has been expired or revoked). After re-authentication was confirmed live (list_sheets sanity check), session 2 restored the fixture doc to standard content and completed the remaining 32 TCs (DOC48–77, DOC80–81), with one further transient [Errno 32] Broken pipe blip (not auth-related, cleared on retry) during TC-DOC76/77 setup. All 81 TCs are now complete.
Summary¶
| Category | PASS | FAIL | SKIP | Total |
|---|---|---|---|---|
| Docs Tools | 81 | 0 | 0 | 81 |
| Total | 81 | 0 | 0 | 81 |
Failures¶
(none — zero FAILs across all 81 TCs)
Findings worth flagging (not scored as TC failures — no existing check covers them)¶
1. write_doc_content's clear+reinsert path leaks a stale font_size:1 override into freshly-written plain paragraphs — recommend filing a GitHub issue.
At session-1 Step 0, get_doc_structure on the fixture doc showed every text run at font_size: 1 even though get_doc_named_styles reported normal named-style defaults (NORMAL_TEXT 11pt). Root cause: write_doc_content's "clear + reinsert" strategy (deleteContentRange(1, end_index-1) then insert at index 1) never touches the final paragraph mark, so a stale explicit textStyle on that trailing character survives every full-document rewrite. Newly inserted content at index 1 appears to inherit ambient style from that untouched trailing context in some cases (plain paragraphs) but not others (headings render correctly; table-cell content renders correctly).
This was reproduced four separate times across the full run — fixed manually via style_doc_range after TC-DOC42, after TC-DOC47, and again independently confirmed in session 2 (post-outage): after a plain write_doc_content restore, get_doc_theme reported NORMAL_TEXT: {font_family: "Courier New", font_size: 1} on a doc whose most recent explicit HTML content contained no code spans — the doc's ambient style was contaminated by leftover state from the previous content, not the new content being written. Session 2 also surfaced a compounding detail: there is no exposed tool parameter to clear an inherited font_family override — style_doc_range supports font_size but not font_family, so the only way to fully normalize a contaminated doc is apply_theme(overwrite=True), which is a much heavier operation than the bug that necessitates it.
Net: calling write_doc_content to replace content whose previous state had an explicit font/size override (e.g. from a table, or a fenced code block) can cause the new content to silently inherit that override, rendering it in the wrong font or at unreadable 1pt size until manually restyled. No existing TC in docs.md checks post-write font styling on plain paragraphs, so this never fails a TC outcome, but it affects real usage (anyone iterating on a doc with write_doc_content after having had a table or code block in it) and is worth a ticket — likely fix is extending the clear+reinsert range in write_doc_content (or the blank-paragraph-before-table collapse logic) to also reset the trailing paragraph mark's textStyle, and/or adding font_family to style_doc_range's supported fields as a mitigation.
2. TC-DOC47 — possible over-broad font_family application (unconfirmed, still needs a follow-up check).
After writing Use the `print()` function via markdown, the rendered line appeared uniformly monospace in the Google Docs editor (visual screenshot), and clicking to the very start of the line showed "Courier New" selected in the font toolbar — suggesting the Courier styling may have applied to the whole paragraph rather than just the print() code span. html_parser.py's code-span handling (font_family="Courier New" if (self._in_pre or self._code_depth > 0) else None, lines ~74) looks correct at the AST level — only text nodes inside <code> should get the font override — so this may be a Google Docs toolbar/cursor-position display quirk rather than a real over-application, and may simply be an artifact of Finding 1's contamination rather than a distinct bug. Could not conclusively verify because get_doc_structure doesn't expose font_family per run (an acknowledged existing gap). Recommend a targeted follow-up: call the raw Docs API (or extend get_doc_structure to expose font_family) and check whether only the print() run carries weightedFontFamily: Courier New, or whether the whole paragraph does.
3. TC-DOC57's prescribed test image URI (SVG) is rejected by the live Google Docs API — the test file's prompt needs updating.
The test case's exact prompt URI (https://www.gstatic.com/images/branding/googlelogo/svg/googlelogo_clr_74x24px.svg) fails on every attempt with HttpError 400: There was a problem retrieving the image. The provided image should be publicly accessible, within size limit, and in supported formats. — this is Google's own API rejecting the SVG format, not a bug in insert_inline_image. Substituting a PNG at the same host (https://www.gstatic.com/images/branding/googlelogo/1x/googlelogo_color_92x30dp.png) succeeded immediately and rendered correctly. TC-DOC57 is recorded PASS on the basis of the PNG substitution (matching what appears to have happened in the historical result too, which mentions "PNG" despite the test file specifying an SVG URL). Recommend updating the test file's prompt to use a PNG/JPEG URL so future runs don't need to silently substitute.
Tool coverage (Docs domain tools only)¶
| Tool | TC(s) run | Status |
|---|---|---|
| get_doc_structure | DOC01–05 + used as verification throughout | ✅ all pass |
| insert_doc_text | DOC06–08, 17, 22–24, 28–30, 74 + setup throughout | ✅ all pass |
| delete_doc_range | DOC09–11, 22 + cleanup throughout | ✅ all pass |
| style_doc_range | DOC12–15, 23–24, 28–30 | ✅ all pass |
| insert_doc_table | DOC16–17, 26–27, 48–50, 55, 61–66 + setup for table tests | ✅ all pass |
| style_doc_table_cells | DOC18–21, 25–26 | ✅ all pass |
| write_doc_content | DOC31–47, 78–79 + fixture restores throughout | ✅ all pass |
| create_doc_from_file | DOC44–46, 76–77, 81 | ✅ all pass |
| create_doc | (none — not directly exercised in this file) | ⚠️ no coverage |
| get_doc_content | DOC80 | ✅ pass |
| get_doc_theme | DOC52, 56 | ✅ pass |
| apply_theme | DOC53–56 | ✅ pass |
| get_doc_named_styles | DOC75 | ✅ pass |
| insert_inline_image | DOC57–60 | ✅ pass (see Finding 3 re: DOC57 SVG substitution) |
| insert_table_row | DOC61–62 | ✅ pass |
| delete_table_row | DOC63, 67 | ✅ pass |
| insert_table_column | DOC64–65 | ✅ pass |
| delete_table_column | DOC66 | ✅ pass |
| create_header | DOC68–69, 72, 74 | ✅ pass |
| create_footer | DOC70–71, 73 | ✅ pass |
Full results¶
| TC | Title | Outcome | Notes |
|---|---|---|---|
| TC-DOC01 | Structure of a non-empty doc | PASS | docId/title/elements returned; sectionBreak at 0; last paragraph ends at doc length (89). |
| TC-DOC02 | Paragraph runs include style data | PASS | bold run bold:true; plain runs bold:null; link run link_url populated. |
| TC-DOC03 | Structure of a doc containing a table | PASS | 2×2 table, 4 cells, paragraphStartIndex=startIndex+1; non-empty cell text confirmed ("X"). |
| TC-DOC04 | Structure of an empty doc | PASS | sectionBreak + 1 empty paragraph, no error. |
| TC-DOC05 | Invalid doc ID returns error | PASS | {"error": "<HttpError 404 ...>"}, no exception. |
| TC-DOC06 | Insert a single paragraph | PASS | Inserted at 88; insertions:1; surrounding content shifted correctly. |
| TC-DOC07 | Insert at multiple indices — high→low ordering | PASS | N1=70, N2=79; BBB landed at N2+4=83; insertions:2. |
| TC-DOC08 | Empty insertions list returns error | PASS | {"error": "insertions list is empty"}. |
| TC-DOC09 | Delete a paragraph | PASS | Deleted [88,103]; doc restored to 89-char baseline; deletions:1. |
| TC-DOC10 | Cannot delete final segment newline | PASS | Delete [1,89] → 400 error re: newline at end of segment. |
| TC-DOC11 | Empty deletions list returns error | PASS | {"error": "deletions list is empty"}. |
| TC-DOC12 | Apply named style type | PASS | namedStyleType:HEADING_2, requests:1. Playwright: text confirmed present in rendered doc. |
| TC-DOC13 | Apply text styles (bold/italic/red) | PASS | bold:true,italic:true, requests:1 (no paragraph style req). Playwright: text confirmed present. |
| TC-DOC14 | Apply both paragraph and text style | PASS | requests:2 (updateParagraphStyle + updateTextStyle); HEADING_3 + bold confirmed. |
| TC-DOC15 | No recognised style fields returns error | PASS | {"error": "no recognised style fields in any range"}. |
| TC-DOC16 | Insert a 2×3 table | PASS | precedingParagraphIndex=88=N, tableStartIndex=89=N+1, 6 cells, paragraphStartIndex=startIndex+1. Playwright screenshot: empty 2×3 grid rendered. |
| TC-DOC17 | Cell indices usable for insert_doc_text | PASS | Inserted "Cell content" at paragraphStartIndex 92; cell [0,0] text confirmed. |
| TC-DOC18 | Grey header row background | PASS | requests:1. Playwright screenshot: row 0 visibly grey across both columns. |
| TC-DOC19 | Borders and padding on all cells | PASS | requests:4 (one per cell). Playwright screenshot: visible black borders + padding. |
| TC-DOC20 | Empty cells list returns error | PASS | {"error": "cells list is empty"}. |
| TC-DOC21 | Cell with no style fields is skipped | PASS | requests:1 — no-style cell silently skipped. |
| TC-DOC22 | Multi-delete high→low ordering | PASS | DEL-A [70,76], DEL-B [85,91] deleted in one call; Item two back at original startIndex 79; deletions:2. |
| TC-DOC23 | style_doc_range HEADING_1 round-trip | PASS | requests:1; namedStyleType:HEADING_1; text unchanged. |
| TC-DOC24 | style_doc_range bold/italic round-trip | PASS | requests:1; bold:true,italic:true; namedStyleType unchanged (NORMAL_TEXT). |
| TC-DOC25 | style_doc_table_cells post-fix verification | PASS | No 400 "oneof" error; requests:1. Playwright screenshot: cell [0,0] light blue. |
| TC-DOC26 | Full e2e: insert table → style cells | PASS | Table 2×3 inserted; grey header requests:1; borders requests:6. Playwright screenshot: grey header spanning 3 cols + visible borders. |
| TC-DOC27 | Insert text then table — index chaining | PASS | precedingParagraphIndex=105=N+17, tableStartIndex=106=N+18; both ops succeeded without re-fetching. |
| TC-DOC28 | Apply strikethrough | PASS | requests:1; strikethrough:true. |
| TC-DOC29 | Apply font_size | PASS | requests:1 (18pt applied; not independently visually screenshotted — no Playwright tag on this TC). |
| TC-DOC30 | Apply link_url | PASS | requests:1; run split correctly; linked run underline:true (expected Docs API auto-behavior). |
| TC-DOC31 | <h2> maps to HEADING_2 |
PASS | HEADING_1/2/3/4 all correct; old #41 bug (H2→H3 collapse) absent. |
| TC-DOC32 | <th> cells produce bold runs |
PASS (partial) | Table + cell text confirmed; bold not verifiable via get_doc_structure (no cell-run exposure, known gap #54). |
| TC-DOC33 | Inline formatting inside <td> |
PASS (partial) | Cell text "bold plain italic" confirmed; run-level bold/italic not exposed (same gap). |
| TC-DOC34 | colspan produces merged cells |
PASS | 2 rows confirmed; row 0 merged cell "Wide cell", phantom [0,1] empty. Playwright screenshot: top row visibly spans both columns. |
| TC-DOC35 | Column widths from HTML | PASS | Call succeeded, no error. Playwright screenshot: first column visibly narrower than second (144pt vs 288pt). |
| TC-DOC36 | rowspan produces vertically merged cells |
PASS | [0,0]"Tall", [0,1]"R0C1", [1,0]"" phantom, [1,1]"R1C1". Playwright screenshot: "Tall" visibly spans both rows. |
| TC-DOC37 | Combined rowspan + colspan | PASS | 2 rows, 3 cols; [0,0]"Big", phantoms [0,1]/[1,0]/[1,1] all empty; [0,2]"R0C2", [1,2]"R1C2". |
| TC-DOC38 | rowspan with header row | PASS | 3 rows, 3 cols; header bold row; "Alpha" rowspan; phantom [2,0] empty; "B" not shifted left. |
| TC-DOC39 | Markdown headings | PASS | HEADING_1/2/3 confirmed in order. |
| TC-DOC40 | Markdown bold/italic | PASS | run "bold" → bold:true; run "italic" → italic:true. |
| TC-DOC41 | Markdown task list | PASS | ☑ Done item, ☐ Pending item, Plain item (no glyph) confirmed. |
| TC-DOC42 | Markdown fenced code block | PASS | Text confirmed; Courier New font confirmed via Playwright toolbar + screenshot at readable size (after fixing fixture-contamination font_size:1, see Finding 1). |
| TC-DOC43 | Markdown table | PASS | 3 rows, 2 cols; Name/Value, Alpha/1, Beta/2 all correct. |
| TC-DOC44 | create_doc_from_file (.md) | PASS | docId/web_link returned; HEADING_1, bold/italic, task glyphs, table all confirmed via get_doc_structure and Playwright screenshot. Doc deleted after verification. |
| TC-DOC45 | create_doc_from_file (.html) | PASS | docId/web_link returned; HEADING_2 "From HTML file" + paragraph confirmed. Doc deleted after verification. |
| TC-DOC46 | create_doc_from_file file not found | PASS | {"error": "File not found: ~/does-not-exist.md"}, no exception. |
| TC-DOC47 | write_doc_content inline code monospace | PASS | "print()" renders monospace per Playwright screenshot (check satisfied). See Finding 2 for an unconfirmed observation re: scope of the Courier styling. |
| TC-DOC48 | Simple nested table | PASS | Outer 1×1 table inserted, cell span 4–17 consistent with inner 1×1 table. Playwright screenshot: nested table visibly rendered inside outer cell with "Inner" text. |
| TC-DOC49 | Nested table alongside regular cells | PASS | Outer 1×2 table; cell [0,0]="Label"; cell [0,1] empty text with span (11–31) consistent with a nested 1×2 table inside it. |
| TC-DOC50 | Nested table, multiple rows/cols | PASS | Outer 1×1 table; cell span (4–35) consistent with a nested 2×2 table inside it. |
| TC-DOC51 | Nested tables not supported in markdown | PASS | Documentation-only entry (per test file: "No test to run; this entry documents the known limitation"); no live call required. |
| TC-DOC52 | get_doc_theme scans body paragraph styles | PASS | No error key; returned {"HEADING_1": {...}, "NORMAL_TEXT": {font_family, font_size, ...}} — non-empty dict with named style keys, each carrying at least one of the expected fields. (The doc happened to have explicit contamination per Finding 1 at the time of this call, which is itself a valid "explicit paragraph styles" case per the tool's spec — confirms the tool correctly surfaces real explicit overrides.) |
| TC-DOC53 | apply_theme updates named style definitions | PASS | requests:2 (one updateNamedStyle per named style type: HEADING_1, NORMAL_TEXT), no error. |
| TC-DOC54 | apply_theme overwrite=True patches paragraphs | PASS | requests:5 (2 updateNamedStyle + 3 updateTextStyle for HEADING_1 paragraph, NORMAL_TEXT paragraph, trailing blank NORMAL_TEXT paragraph). Playwright screenshot: heading in Georgia 22pt, body text visibly different font/size (Verdana 11pt). |
| TC-DOC55 | apply_theme with table styling | PASS | requests:2 (one updateTableCellStyle per row). Playwright screenshot: visible black borders, cell padding, and header row (row 0) grey background. |
| TC-DOC56 | get_doc_theme → apply_theme round-trip | PASS | get_doc_theme returned non-empty dict (HEADING_1/NORMAL_TEXT with font_family); feeding it straight into apply_theme(overwrite=True) succeeded with requests:8, no error. |
| TC-DOC57 | Insert image by public URI | PASS | See Finding 3 — the prescribed SVG URI is rejected by the live Google Docs API (HttpError 400, unsupported format); a PNG at the same host succeeded and rendered correctly (confirmed via Playwright screenshot). |
| TC-DOC58 | Insert image with explicit size | PASS | Inserted with width=100, height=50; Playwright screenshot: second logo visibly smaller than the default-sized one inserted for DOC57. |
| TC-DOC59 | No source provided returns error | PASS | {"error": "Provide either uri or drive_file_id"}. |
| TC-DOC60 | Both URI and drive_file_id returns error | PASS | {"error": "Provide only one of uri or drive_file_id, not both"}. |
| TC-DOC61 | Insert a row below | PASS | 2×2 table → insert below row 0 → 3 rows confirmed via get_doc_structure. |
| TC-DOC62 | Insert a row above | PASS | 2×2 table → insert above row 1 → 3 rows confirmed. Playwright screenshot: 3 empty rows visible. |
| TC-DOC63 | Delete a row | PASS | 3 rows → delete row 1 → 2 rows confirmed. Playwright screenshot: 2 rows visible. |
| TC-DOC64 | Insert a column to the right | PASS | 2 cols → insert right of col 0 → 3 cols confirmed. Playwright screenshot: 3 columns visible. |
| TC-DOC65 | Insert a column to the left | PASS | 3 cols → insert left of col 1 → 4 cols confirmed. Playwright screenshot: 4 columns visible. |
| TC-DOC66 | Delete a column | PASS | 3 cols → delete col 1 → 2 cols confirmed. Playwright screenshot: 2 columns visible. |
| TC-DOC67 | API error returned gracefully (out of bounds row) | PASS | {"error": "<HttpError 400 ... row index 99 should be less than the total number of rows 2 ...>"}, no exception. |
| TC-DOC68 | Create a default page header | PASS | headerId (non-empty string) returned, no error. Playwright screenshot: header text visible at top of rendered doc. |
| TC-DOC69 | Create a header with content | PASS | headerId returned, no error; content "Confidential — Internal Only" prepended. Playwright screenshot: new header text visible above prior header text. |
| TC-DOC70 | Create a default page footer | PASS | footerId (non-empty string) returned, no error. Confirmed via API response per known limitation (footer not reliably visible via scrollTo on a short doc in the rendered viewport). |
| TC-DOC71 | Create a footer with content | PASS | footerId returned, no error; content "Page 1" inserted. |
| TC-DOC72 | Invalid header_type returns error | PASS | {"error": "Invalid header_type 'INVALID'. Use DEFAULT or FIRST_PAGE_HEADER"}. |
| TC-DOC73 | Invalid footer_type returns error | PASS | {"error": "Invalid footer_type 'INVALID'. Use DEFAULT or FIRST_PAGE_FOOTER"}. |
| TC-DOC74 | insert_doc_text with segment_id writes into header | PASS | insertions:1, no error. Playwright screenshot: new header text visible, prepended correctly at index 0 of the header segment. |
| TC-DOC75 | get_doc_named_styles reads named style defaults | PASS | No error; returned a 9-key dict (NORMAL_TEXT, HEADING_1–6, TITLE, SUBTITLE) each with plausible font/spacing fields. |
| TC-DOC76 | Table immediately after heading renders at Normal Text size | PASS | Fresh doc created from fixture file; table 2×3 with all 6 cells confirmed correct (Finding/Severity/Ticket, Some finding/HIGH/KINDLY-123). Playwright screenshot: "HIGH" H2 heading (16pt) visibly larger than table cell text. Doc deleted after verification. |
| TC-DOC77 | No visible blank line between heading and table | PASS | Same fixture doc as DOC76. Playwright screenshot: no visible gap between "HIGH" heading and the table; blank collapsing paragraph confirmed present in structure (font_size:1 run, consistent with the intentional collapse behavior). Doc deleted after verification. |
| TC-DOC78 | data-style="title" → TITLE |
PASS | First paragraph namedStyleType:TITLE text "My Document Title"; second NORMAL_TEXT "Body paragraph.". |
| TC-DOC79 | data-style="subtitle" → SUBTITLE |
PASS | TITLE / SUBTITLE / NORMAL_TEXT all confirmed with correct text. |
| TC-DOC80 | get_doc_content response-size cap (cache-hit path re-check) | PASS | First call: {"error": "...49700 characters, over the 40000-character safety cap..."}. Second call (cache-hit path): identical error re-raised. Third call with local_path: returned {"bytes_written": 49700, ...}; verified on disk with wc -c — 49700 bytes, exact match. |
| TC-DOC81 | create_doc_from_file renders \$ as literal $ |
PASS | docId/web_link returned, no error. get_doc_content confirmed literal $6,000, $25, $1,200 in rendered text — no stray backslashes. Doc deleted after verification. |
Notes for future runs¶
- Fixture doc was restored to standard content (
<h1>Test Document</h1><p>This document is used for QA testing of mcp-gee-sweet.</p><ul><li>Item one</li><li>Item two</li></ul>) at the start of session 2 and verified clean viaget_doc_structure(title, HEADING_1 "Test Document", body paragraph, "Item one"/"Item two" bullets, no leftoverfont_sizeoverrides). The doc's page header/footer now contain accumulated test content from DOC68–74/70–71 (headers/footers are additive by design in this tool and were left as-is, consistent with prior convention). - File a GitHub issue for Finding 1 (
write_doc_contentclear+reinsert path leakingfont_size/font_familycontamination into new plain-paragraph content) — reproduced 4 times across this run, root-caused to the untouched trailing paragraph mark, and compounded bystyle_doc_rangehaving nofont_familyparameter to clean it up after the fact. - Consider a targeted follow-up for Finding 2 (possible over-broad Courier New application in TC-DOC47) once
font_familyis exposed byget_doc_structureor via a raw API check — may turn out to be subsumed by Finding 1. - Update TC-DOC57's prescribed image URI in
docs/qa/tests/docs.mdfrom the SVG gstatic URL (rejected by the live API) to a PNG/JPEG URL (Finding 3).