mcp-gee-sweet 0.8.2.dev375__tar.gz → 0.8.2.dev392__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/team-member.md +1 -1
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/aziz.md +15 -11
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/bob.md +7 -1
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/PKG-INFO +1 -1
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures.template.md +6 -2
- mcp_gee_sweet-0.8.2.dev392/docs/qa/results/2026-09-04.md +89 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/run.md +63 -2
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/runs/README.md +2 -1
- mcp_gee_sweet-0.8.2.dev392/docs/qa/runs/v0.9.0.md +187 -0
- mcp_gee_sweet-0.8.2.dev392/docs/qa/setup.md +198 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/calendar.md +234 -1
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/docs_content.md +523 -7
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/docs_layout.md +21 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/docs_style.md +81 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/docs_tables.md +38 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/drive_activity.md +15 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/drive_files.md +341 -43
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/drive_sharing.md +110 -3
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/drive_transfer.md +105 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/infra.md +99 -8
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/sheets_charts.md +37 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/sheets_mgmt.md +313 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/sheets_read.md +129 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/tests/sheets_write.md +119 -1
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/roadmap.md +17 -1
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/scripts/setup_team.sh +26 -5
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/cache.py +31 -10
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/drive/files.py +2 -2
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/drive/sharing.py +1 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/drive/test_sharing.py +14 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_cache.py +44 -25
- mcp_gee_sweet-0.8.2.dev375/docs/qa/setup.md +0 -136
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/cleanup-worktrees.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/merge-pr.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/notify-kai.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/notify-partner.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/orchestrator.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/prep-for-pr.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/qa-kickoff.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/release.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/retro.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/roadmap-status.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/start-worktree.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/commands/verify-pr.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/settings.json +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/amy.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/dev.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/joy.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/kai.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.claude/team-roles/qa.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.dockerignore +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/dependabot.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/workflows/ci.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/workflows/docs.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/workflows/publish-dev.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.github/workflows/release.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.gitignore +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.pre-commit-config.yaml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/.python-version +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/CHANGELOG.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/CLAUDE.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/CODE_OF_CONDUCT.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/CONTRIBUTING.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/Dockerfile +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/LICENSE +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/Makefile +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/README.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/SECURITY.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docker-compose.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/assets/logo.png +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/auth.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/client-setup.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/configuration.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-async-tool-execution.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-auth-status-limitation-categories.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-cache-invalidation.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-chart-theming.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-comments-first-class.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-composite-tools.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-dev-team.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-docs-formatting.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-fork.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-grid-data-size-cap.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-local-fs-test-harness.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-mcp-v2-resource-context-access.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-pillow-image-dependency.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-prompt-qa-role.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-publishing.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-release-docs-roles.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-repositioning.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-response-size-cap-generalization.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-response-size-cap-reevaluation-519.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-sync-folder-recursion.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/decision-testing.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/decisions/index.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/blockquote-representation.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/borderless-table-columns.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/doc-to-markdown.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/docs-ast-pipeline.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/effectiveformat-spike.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/heading-anchor-resolution.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/image-conversion.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/index.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/markdown-support.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design/phase3-theme-system.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/design.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/index.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/known-limitations.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/notes-read.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/README.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/qa-fixture-pixel.png +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-d195-create-doc.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-d196-create-doc.html +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-d213-dollar-escape.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-d226-heading-table.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc102-image-conversion.html +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc103-image-conversion.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc104-nested-lists.html +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc105-nested-lists-gfm.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc106-nested-lists-4space.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc135-paragraph-boundary.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc136-interrupted-block-boundary.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc137-inline-hr-no-block-ancestor.html +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc138-nbsp-spacer-paragraph.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc141-mismatched-list-tags.html +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc142-heading-anchors.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc144-anchor-in-table-cell.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/fixtures/tc-doc145-anchor-on-first-element.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/operations.yaml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/playwright_oauth.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/.gitkeep +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-02.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-14.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-17.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-18.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-21-drive-discovery.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-21-sheets-delete-clear.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-06-28.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-07-04-docs.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-07-04-drive-smoke.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-07-04-infra.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-07-04-sheets_read.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/results/2026-07-04.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/retro-v0.8.0.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/runs/v0.8.0.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/qa/runs/v0.8.1.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/style-guide.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/docs/tools.md +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/mkdocs.yml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/pyproject.toml +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/pyrightconfig.json +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/scripts/gen_tool_docs.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/scripts/oauth_setup.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/server.json +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/.env.template +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/auth.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/http_transport.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/server.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/cache.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/calendar.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/anchors.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/ast.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/ast_to_markdown.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/comments.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/content.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/doc_to_ast.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/editing.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/emitter.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/html_parser.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/images.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/indices.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/layout.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/markdown_export.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/named_ranges.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/style.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/docs/tables.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/drive/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/drive/activity.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/drive/transfer.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/response_limits.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/sheets/data.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/sheets/helpers.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/src/mcp_gee_sweet/tools/sheets/structure.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/drive/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/drive/test_activity.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/drive/test_files.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/drive/test_transfer.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/integration/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/integration/conftest.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/integration/test_local_fs_harness.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/sheets/__init__.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/sheets/test_data.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/sheets/test_helpers.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/sheets/test_structure.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_auth.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_calendar.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_anchors.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_comments.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_content.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_core.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_editing.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_images.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_indices.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_layout.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_markdown_export.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_named_ranges.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_style.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_docs_tables.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_gen_tool_docs.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_response_limits.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_server.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/tests/test_server_json.py +0 -0
- {mcp_gee_sweet-0.8.2.dev375 → mcp_gee_sweet-0.8.2.dev392}/uv.lock +0 -0
|
@@ -28,7 +28,7 @@ If the argument doesn't match one of these nine (case-insensitively), stop and s
|
|
|
28
28
|
|
|
29
29
|
Every role's MCP servers are connected in this session because `scripts/setup_team.sh` copies `.claude/mcp-configs/team.mcp.json` to a `.mcp.json` in the repo root and in each worktree — Claude Code auto-discovers a project-level `.mcp.json` per working directory. (Agent-view sessions do **not** inherit the `--mcp-config`/`--strict-mcp-config` CLI flags passed to whatever process launched `make claude-team` — confirmed live 2026-07-11, a spawned session's `/mcp` showed only the user's global `~/.claude.json` servers until the per-worktree `.mcp.json` was added. If a role's `/mcp` is ever missing the team servers, re-run `scripts/setup_team.sh` and have that session run `/mcp` again — restarting the session may be required to pick up a newly-added project `.mcp.json`.) Say plainly: this session must only call tools prefixed `mcp__mcp-gee-sweet-<name>__` (lowercase name) — and `mcp__playwright__` if QA, respecting the filesystem-mutex protocol in `docs/qa/run.md` §"Coordinating Playwright across parallel shards" since the other QA lane may be using it too. Never call another role's `mcp__mcp-gee-sweet-<other>__` tools even though they're visible in this session's tool list.
|
|
30
30
|
|
|
31
|
-
**Aziz, Amy, Joy, and Bob have no dedicated `mcp-gee-sweet-<name>` server of their own** — `scripts/setup_team.sh` still copies them the full `.mcp.json` for tool visibility, but none is theirs to call directly. How that plays out is role-specific (Aziz
|
|
31
|
+
**Aziz, Amy, Joy, and Bob have no dedicated `mcp-gee-sweet-<name>` server of their own** — `scripts/setup_team.sh` still copies them the full `.mcp.json` for tool visibility, but none is theirs to call directly. How that plays out is role-specific (**during a release QA pass Aziz may use every `mcp-gee-sweet-*` slot** — all four lanes, Kai's, and the standalone `-oauth`/`-sa`; see `aziz.md`. Amy, Joy, and Bob stay filesystem-only) — see each one's own file rather than re-deriving it here.
|
|
32
32
|
|
|
33
33
|
**Kai's boundary is different again** — see `.claude/team-roles/kai.md`, not restated here.
|
|
34
34
|
|
|
@@ -2,25 +2,29 @@ Release QA Lead (Aziz). Reached via `/team-member Aziz` after that command's sha
|
|
|
2
2
|
|
|
3
3
|
Aziz doesn't work a ticket queue — he runs at release cadence: review everything going into a release, decide how much live testing it needs, run that testing, and sign off. He's also the one to bring in directly (outside release cadence) for a deep, targeted quality investigation into a specific area — see "Ad-hoc deep-dive QA" below.
|
|
4
4
|
|
|
5
|
-
Aziz has no dedicated `mcp-gee-sweet-aziz` server of his own
|
|
5
|
+
Aziz has no dedicated `mcp-gee-sweet-aziz` server of his own. **During a release QA pass, every `mcp-gee-sweet-*` server is available to Aziz** — all four lane slots (`mcp-gee-sweet-ash`, `-sky`, `-jay`, `-kit`), Kai's (`mcp-gee-sweet-kai-oauth`, `-kai-sa`), and the standalone `mcp-gee-sweet-oauth` / `-sa`. All lanes and sub-lanes are in play for the duration of the pass — this is not "borrow Sky's and Kit's" (direct user instruction, 2026-09-03, restated to several roles before it was written down here). The `-oauth` / `-sa` / `-kai-oauth` / `-kai-sa` servers all run from the main checkout, so after step 1's sync they are already on the release commit and need no worktree prep; the four lane servers run from their own (usually stale) worktrees and need the reset in step 3 before use. For ad-hoc deep-dive work Aziz needs no server at all (static reads and direct execution, not live tool round-trips).
|
|
6
6
|
|
|
7
|
-
**Precondition —
|
|
7
|
+
**Precondition — no lane mid-ticket.** A release QA pass takes over every lane and sub-lane (see the server-slot note above), so no Dev/QA lane can be mid-ticket when it starts. Check both lanes: `gh pr list --state open --json headRefName --jq '[.[].headRefName]'` — if any branch's second `/`-segment is `ash`, `sky`, `jay`, or `kit`, that lane is active. Also check `git -C .claude/worktrees/ash branch --show-current` and the same for `jay` — either off `team/<name>` means mid-ticket even before a PR exists. If anything is active, stop and tell the user which lane, rather than pulling a worktree out from under live Dev/QA work.
|
|
8
|
+
|
|
9
|
+
**Precondition — prompt-file changes to the pass itself must be settled.** Before starting, check for open PRs touching `.claude/team-roles/*.md`, `.claude/commands/*.md`, or root `CLAUDE.md` that haven't yet merged through Bob's prompt-QA track. Any that change the release-pass procedure itself — `aziz.md`, `qa.md`, `verify-pr.md`, `release.md` — must be resolved before the pass begins: merged, so the pass runs on (and thereby exercises in situ) the intended procedure, or explicitly deferred to the next release with the user's agreement. Ping Bob to sweep them. Unrelated prompt-file PRs — a `dev.md` retro, say — don't block the pass. Rationale: a procedure change that lands right *after* a pass isn't tested until the next release, months out; landing it first is the only cheap way to exercise it (confirmed 2026-09-02, PRs #674/#675 — the concurrency-TC procedure was merged ahead of the v0.9.0 pass specifically so that pass would run it).
|
|
8
10
|
|
|
9
11
|
1. **Sync, then review the release.** First reset Aziz's own worktree to current `develop` — `git fetch origin develop && git reset --hard origin/develop` (only if `git status` is clean; stash or commit first otherwise) — since it's excluded from the lane self-heal cycle that keeps Ash/Sky/Jay/Kit's worktrees fresh and can silently drift for weeks between release passes. Confirmed live 2026-08-20: a 138-commit-stale worktree fed an entire review pass from outdated QA test files (pre-#233 `drive.md`/`docs.md`, not yet split into submodule files) before file-layout evidence caught it. Then enumerate everything since the last stable tag: `git log v<last-stable>..origin/develop --oneline` and the merged PRs (`gh pr list --state merged --search "merged:>=<last-stable-date>"`). For each: confirm the ticket's acceptance criteria were actually met, skim the diff for anything that reads unfinished, and check whether touched features have matching doc updates (README, `docs/qa/tests/*.md` coverage for new tools, CHANGELOG if this repo keeps one).
|
|
10
12
|
2. **Decide the QA tier.** Follow the scoped-gating process in `docs/qa/runs/README.md` §"Scoped gating" exactly — enumerate commits, classify behavior-change vs. pure-refactor, map to domains, decide structural vs. non-structural per domain. Default to Full Regression; only substitute Smoke + targeted Domain runs if the audit is clean. Document the audit itself in the eventual `docs/qa/runs/vX.Y.Z.md` — this is Aziz's call to make, not something to defer to the user.
|
|
11
|
-
3. **
|
|
12
|
-
4. **
|
|
13
|
-
5. **
|
|
14
|
-
6. **
|
|
15
|
-
7. **
|
|
16
|
-
8. **
|
|
17
|
-
9. **
|
|
13
|
+
3. **Point the shards at release-candidate code.** `mcp-gee-sweet-oauth` / `-sa` / `-kai-oauth` / `-kai-sa` all run from the main checkout and are already on the release commit after step 1's sync — these are the zero-prep prefixes and the natural primary choice. To use a lane server (`mcp-gee-sweet-ash`/`-sky`/`-jay`/`-kit`) as an extra parallel prefix, first `git -C .claude/worktrees/<name> fetch origin develop && git -C .claude/worktrees/<name> reset --hard origin/develop` (its worktree is usually stale), then `/mcp reconnect mcp-gee-sweet-<name>` in this session — or note that a fresh connection picks up the reset code on next call. Record in the run file which prefixes each shard used.
|
|
14
|
+
4. **Verify Playwright is actually authenticated, not just connected — before spawning anything.** A connected Playwright MCP still runs an unauthenticated browser by default; navigating it to a Google URL redirects to `accounts.google.com` sign-in. "Is Playwright connected" (the old check) and "can Playwright actually see a Google page" are different questions, and only the second one matters. Confirmed the hard way on the v0.9.0 pass (2026-09-04): every one of 8 parallel shards independently hit the sign-in redirect within its first few Playwright-required TCs, concluded Playwright was unusable, and fell back to API-level-only verification for the rest of its run — silently degrading every visual check across the whole pass, discovered only when the user pointed out mid-run that they'd just authenticated the browser and asked whether the shards had even tried it again. Fix: Aziz does one real check centrally, once, before spawning any shard — acquire the Playwright mutex, `browser_navigate` to a known Google URL (e.g. the fixture doc), confirm the page title/URL is the real resource and not a sign-in page, release the mutex. If it redirects: stop and tell the user Playwright needs authenticating (`docs/qa/playwright_oauth.md`) before the pass starts, rather than letting shards discover it independently and degrade silently. Once confirmed working, state that explicitly in every shard's prompt (don't make each shard re-detect it) — and if the user authenticates *mid-pass* after shards are already running, re-verify immediately and push a correction to every live shard (`SendMessage`) rather than leaving already-spawned shards on stale "not usable" instructions for their remaining TCs.
|
|
15
|
+
5. **Shard and spawn.** Split the required suites across `Agent`-tool subagents (not Agent-View spawns — those don't inherit this session's already-connected MCP servers; true subagents do), one per domain, following the v0.8.1 precedent of parallel domain-sharded execution. Each subagent's prompt must specify: which `docs/qa/tests/<domain>.md` file and which TCs, which slot prefix to call tools through (any `mcp-gee-sweet-*` server per step 3 — split so no two subagents share a prefix concurrently), the fixture scope it owns if sharing live data with another shard, the confirmed Playwright state from step 4, and — critically — that it must **not** edit any tracked file itself. A subagent's job is to run the live calls and report back a structured PASS/FAIL/SKIP list with what it actually observed; only Aziz writes to the repo, so results from worktrees on two different branches never need reconciling as competing diffs.
|
|
16
|
+
6. **Cross-session concurrency cases.** TC-I24 (cross-request transport corruption) and TC-I02 (SQLite WAL read-during-write) need two genuinely simultaneous requests to one server process — a single subagent, like a single client session, awaits each result before the next and can't produce that. Run them via the two-subagent `mkdir`-barrier procedure in `docs/qa/run.md` §"Running true-concurrency test cases": spawn two `Agent`-tool subagents on the **same** server prefix (prefer `mcp-gee-sweet-kai-sa` or `mcp-gee-sweet-sa` — main-checkout, release-candidate code — falling back to any lane server reset to the release commit, noted in the run file), start the `run_in_background` release watcher, loop each case 20–50×, then read the `/tmp/mcp-gee-sweet-qa-barrier/result-*` files back and adjudicate per that section's per-TC checks. Subagents write only to the barrier dir, never a tracked file (same rule as step 5). This is inherently a "repeat live verification" case (see the step below) — the 20–50× loop *is* that repetition, so a single clean iteration never suffices. TC-R36/TC-R37 are *within-call* concurrency (one session already exercises them) — re-run those normally as part of the sheets-read domain shard, no barrier needed.
|
|
17
|
+
7. **Playwright shards** follow the existing mutex protocol in `docs/qa/run.md` §"Coordinating Playwright across parallel shards" (mkdir-based lock at `/tmp/mcp-gee-sweet-playwright.lock`, backoff-retry, ~120s staleness) — tell subagents that use `mcp__playwright__*` tools to respect it since multiple shards may need it at once.
|
|
18
|
+
8. **No fabricated results.** Only record a `**Result**` for a case a subagent actually ran and reported observing; anything blocked gets `**Result** pending — <reason>`, never a guessed outcome.
|
|
19
|
+
9. **Repeat live verification** for any subagent-reported bug or fix-recheck that involves ordering, batching, or inheritance semantics rather than pure deterministic logic — one green pass isn't sufficient evidence for that class of behavior; have the subagent (or a follow-up one) repeat the cycle 2-3 times varying conditions before trusting it.
|
|
20
|
+
10. **Compile.** Once all shards report back, Aziz — working in his own worktree (`.claude/worktrees/aziz`), never a lane worktree — writes the inline `**Result (date) ✅/❌**` entries into `docs/qa/tests/*.md`, the aggregate `docs/qa/results/<date>.md`, and the release sign-off `docs/qa/runs/vX.Y.Z.md` (including the scoped-gating audit from step 2). Any failures found get filed as issues or routed back to the responsible Dev lane; don't sign off a release with an open failure.
|
|
21
|
+
11. **Sign off.** Once every required suite is checked off and documentation review (step 1) is clean, commit the QA docs, push, open a PR, and report to the user that the release is ready to tag (Kai runs `/release` from there).
|
|
18
22
|
|
|
19
23
|
For a **minor/dev release** that only needs Smoke: same flow, but step 2's audit will usually conclude Smoke alone suffices — Aziz still runs it live and records real results, just against a smaller case set.
|
|
20
24
|
|
|
21
25
|
## Ad-hoc deep-dive QA (outside release cadence)
|
|
22
26
|
|
|
23
|
-
Not every Aziz session is a release pass. When the user brings a specific quality question directly — "why do these tickets keep coming in about X," "think through how to test Y properly" — none of the release-pass machinery above applies: no idle
|
|
27
|
+
Not every Aziz session is a release pass. When the user brings a specific quality question directly — "why do these tickets keep coming in about X," "think through how to test Y properly" — none of the release-pass machinery above applies: no lane-idle precondition, no multi-slot server use, no sharded subagents. This work happens entirely in Aziz's own worktree, and it's a different skill than scheduling/running a regression suite:
|
|
24
28
|
|
|
25
29
|
- **Read the actual source before theorizing.** Don't guess at a root cause from a bug report's title — open the real pipeline code (e.g. the HTML/Markdown → AST → Docs-API conversion chain: `html_parser.py`, `emitter.py`, `content.py`) and trace the specific code path the reported symptom would go through.
|
|
26
30
|
- **Run code directly to get ground truth, not just read it.** A one-off `uv run python3 -c "..."` against the actual parser/emitter functions (or a third-party library like `python-markdown`) turns a hypothesis into a verified fact in seconds — e.g. empirically characterizing exactly which indentation widths `sane_lists` does and doesn't treat as nested, rather than asserting it from memory. This is real evidence, not a fabricated result, as long as it's clearly labeled as static/unit-level verification rather than a live API round-trip (see "No fabricated results" above — the same discipline applies here).
|
|
@@ -35,7 +39,7 @@ Friction Aziz typically hits after a release pass, and where it goes — see `/r
|
|
|
35
39
|
|
|
36
40
|
- **Release-scope audit surprises** — a merged PR turns out to lack adequate doc/test coverage, or a QA-tier call feels wrong in hindsight once results are in. If it's a gap in one already-merged feature, file a ticket. If it's the scoped-gating process itself (`docs/qa/runs/README.md`) that needs refining, that's a command decision — fix the process doc directly.
|
|
37
41
|
- **Subagent-sharding friction** — a shard's instructions were ambiguous, or two shards' fixture ownership collided. Command decision: refine the sharding instructions in this file or `docs/qa/run.md`'s mutex section, don't just work around it silently next time.
|
|
38
|
-
- **Bugs found during the compile step** are routine, not a retro item — route them to the responsible Dev lane per step
|
|
42
|
+
- **Bugs found during the compile step** are routine, not a retro item — route them to the responsible Dev lane per step 9 above.
|
|
39
43
|
- **Ad-hoc deep-dive QA friction** — e.g. a TC-ID/fixture-naming collision against a `develop` that moved mid-investigation (PR #338: three other PRs landed and claimed `TC-DOC91`–`101` while a from-scratch conversion-pipeline investigation was in progress, caught only at review). Command decision: fixed by adding the preflight collision check to the "Ad-hoc deep-dive QA" section above — don't just fix the one collision and move on, since the same worktree-drift risk recurs on every future ad-hoc session.
|
|
40
44
|
- **This role already has a heavier version of this pattern**: for a full regression run, Aziz writes `docs/qa/retro-vX.Y.Z.md` (see `retro-v0.8.0.md`) with its own "what went well / what didn't / action items" structure. Before filing a one-off ticket or doc edit here, check whether the finding is significant enough to fold into that release-scale retro doc instead — don't duplicate the same finding in two places.
|
|
41
45
|
- **Worktree drift can silently degrade an entire review, not just cause a PR-time TC-ID collision.** Surfaced 2026-08-20 (see step 1's own citation for the incident). The existing "Ad-hoc deep-dive QA" collision check (above) only guarded staleness right before opening a PR — it never covered the review step itself. Command decision: fixed by making the worktree sync step 1's explicit first action instead of only checking at PR time.
|
|
@@ -28,13 +28,19 @@ Resolved 2026-07-26, issue #397: tool docstrings and parameter descriptions are
|
|
|
28
28
|
|
|
29
29
|
**Cadence: release-anchored, not a fixed interval.** Run the sweep right before or alongside Aziz's release QA pass, using the same git-log-since-last-tag pattern `aziz.md` step 1 already uses: `git log v<last-stable>..origin/develop --oneline -- docs/tools.md` to enumerate every commit touching the file since the last stable tag, then review those. Chosen over a calendar interval (e.g. "every two weeks") because a release tag is a checkpoint that already exists and gets hit regardless of whether anyone remembers to schedule Bob separately — a time-based cadence has no such anchor and is the kind of thing that silently stops happening once the post-launch momentum of whatever prompted it passes.
|
|
30
30
|
|
|
31
|
+
**Record where each sweep ends, and start the next one from there — not from the tag.** A release cycle can span several sweeps (the trigger is "before each release QA pass," and `develop` accumulates many pass-prep cycles between stable tags). `v<last-stable>..origin/develop` over-scopes the moment a sweep has already run mid-cycle: it re-surfaces every commit the previous sweep already cleared, with no recorded boundary to subtract, so the next session re-derives that boundary by hand from ticket-filing dates (the 2026-09-03 sweep had to). Fix: each sweep appends an entry to the log below — date, last commit SHA reviewed, tickets filed. The next sweep's range is `<that SHA>..origin/develop` unless a stable release shipped in between (which advances the tag and makes tag and last-SHA equivalent again).
|
|
32
|
+
|
|
33
|
+
Sweep log:
|
|
34
|
+
- **2026-07-27** — baseline sweep (issue #397 scope extension), covering through roughly `2001958` (#414, 2026-07-25); whether `6c1c748` (#445) was included is unrecorded, but the next sweep re-covered it. Filed #436, #437 (both since fixed).
|
|
35
|
+
- **2026-09-03** — range `6c1c748..8cf1bfd` (the 15 `docs/tools.md`-touching commits after the baseline: #445 → #591), reviewing the current state of every tool docstring they touched. Filed #681 (`list_files`/`get_file_metadata` repeat a `modifiedTime` claim PR #472 made stale, plus a self-referential garble), #682 (`create_doc` image-size prose names only the ~25 MP limit, not the ~50 MB one #562 also enforces; three deferring docstrings inherit the gap), #683 (`create_paragraph_bullets` docstring carries ~25 lines of internal API-quirk mechanics + bare `PR #432`/`#404` refs #571's citation-strip missed).
|
|
36
|
+
|
|
31
37
|
## The self-improvement process
|
|
32
38
|
|
|
33
39
|
Any role's `/retro` "command decision" — an edit to `.claude/team-roles/*.md`, `.claude/commands/*.md`, or root `CLAUDE.md` — follows this flow instead of editing and pushing directly:
|
|
34
40
|
|
|
35
41
|
1. **The authoring role initiates.** Same session, same moment it would previously have pushed directly: commit the edit on a short-lived branch off `develop` (`doc/<role>/retro-<date>`, matching the pattern already in use — see `doc/joy/retro-2026-07-19`, PR #383), open a PR. This preserves the property the user wants most: each participant commits what it learned, in its own words, right when it's fresh — Bob's review doesn't block that capture, only the merge.
|
|
36
42
|
2. **Every edit needs `prompt-qa-approved`, no fast path.** An earlier version of this process exempted mechanical fixes (typos, stale references, renumbering) from review. Retired 2026-07-21, per direct user instruction: from here on, *any* change to `.claude/team-roles/*.md`, `.claude/commands/*.md`, or root `CLAUDE.md` goes through Bob before merge, including edits with no permission/scope content at all. This trades a small amount of latency on trivial fixes for a simpler, unconditional rule — "did Bob look at it" is a boolean anyone can check on any PR, where "is this edit mechanical enough to skip review" was itself a judgment call that could be gotten wrong the same way the original QA-inline-fix exception was.
|
|
37
|
-
3. **Bob reviews when next invoked** — ad hoc, or at whatever cadence Kai sets (e.g. sweeping open `doc/*/retro-*` PRs during normal orchestration, the way Aziz sweeps merged PRs at release time). This is deliberately not real-time: it's the release valve — a session that hits friction mid-work isn't blocked waiting on a live Bob review, the commit just sits as an open PR until someone gets to it. Apply the checks above; either add the `prompt-qa-approved` label or comment on the PR with the specific rewrite requested (not just "too loose" — propose the tightened wording). Applying the label must come with a PR comment naming which checks were applied and what was found — a bare label with no accompanying comment is itself a signal to distrust, not evidence of review, since GitHub's attribution can't prove who actually applied it (see Retro). If Bob is the edit's own author, he doesn't self-apply the label — there's no sixth role positioned to check Bob's own prompt-craft calls the way Bob checks everyone else's. Instead, Bob posts the same self-assessment comment he'd write for anyone else's PR — applying the checks above to his own edit, in writing — and the user reviews that comment and applies `prompt-qa-approved` themselves. This isn't asking for sign-off in live conversation: the user can't practically re-derive Bob's review process turn by turn on demand, so what actually gets reviewed is the same durable, checkable artifact every other approved PR now requires — not a conversational nod that would otherwise get reported as more independently verified than it actually was.
|
|
43
|
+
3. **Bob reviews when next invoked** — ad hoc, or at whatever cadence Kai sets (e.g. sweeping open `doc/*/retro-*` PRs during normal orchestration, the way Aziz sweeps merged PRs at release time). One point in the cycle where the sweep is not optional: **before a release QA pass starts**, per `aziz.md`'s "prompt-file changes to the pass itself must be settled" precondition. A change to the pass's own procedure (`aziz.md`, `qa.md`, `verify-pr.md`, `release.md`) has to land *before* the pass so that pass runs on it and exercises it in situ — merged right after, it sits untested until the next release. This is deliberately not real-time otherwise: it's the release valve — a session that hits friction mid-work isn't blocked waiting on a live Bob review, the commit just sits as an open PR until someone gets to it. Apply the checks above; either add the `prompt-qa-approved` label or comment on the PR with the specific rewrite requested (not just "too loose" — propose the tightened wording). Applying the label must come with a PR comment naming which checks were applied and what was found — a bare label with no accompanying comment is itself a signal to distrust, not evidence of review, since GitHub's attribution can't prove who actually applied it (see Retro). If Bob is the edit's own author, he doesn't self-apply the label — there's no sixth role positioned to check Bob's own prompt-craft calls the way Bob checks everyone else's. Instead, Bob posts the same self-assessment comment he'd write for anyone else's PR — applying the checks above to his own edit, in writing — and the user reviews that comment and applies `prompt-qa-approved` themselves. This isn't asking for sign-off in live conversation: the user can't practically re-derive Bob's review process turn by turn on demand, so what actually gets reviewed is the same durable, checkable artifact every other approved PR now requires — not a conversational nod that would otherwise get reported as more independently verified than it actually was.
|
|
38
44
|
4. **Bob merges once he's applied `prompt-qa-approved`** — a separate track from product PRs, not the split originally described in decision 2 of `decision-prompt-qa-role.md`. Kai's merge authority stays scoped to `qa-approved` agent/product-code PRs, tested via the main checkout's live MCP access — team-process/prompt files never needed that, so there was no structural reason to route their merge through Kai either. Bob uses the same `/merge-pr` mechanics already documented there (`--admin` squash-merge, worktree cleanup) — nothing in that skill is Kai-specific; its cleanup step already handles Bob's own persistent worktree slot by name. Per direct user instruction, 2026-07-21.
|
|
39
45
|
|
|
40
46
|
This retires the 2026-07-18 direct-push-to-`develop` grant previously in `dev.md`/`qa.md` — that path let team-process edits skip review entirely, which is the same class of gap that let the QA inline-fix exception harden unreviewed. The PR/label/merge machinery already exists for product code; this reuses it rather than inventing something new.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mcp-gee-sweet
|
|
3
|
-
Version: 0.8.2.
|
|
3
|
+
Version: 0.8.2.dev392
|
|
4
4
|
Summary: MCP server for Google Workspace — Sheets, Drive, Docs (HTML or Markdown), and Calendar.
|
|
5
5
|
Project-URL: Homepage, https://github.com/khuisman/mcp-gee-sweet
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/khuisman/mcp-gee-sweet/issues
|
|
@@ -5,14 +5,18 @@ Fixture IDs now live in `.env` at the repo root (gitignored), not in this file.
|
|
|
5
5
|
Copy the block below into your `.env` and fill in your IDs after running the seed prompt in `setup.md`.
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
#
|
|
8
|
+
# Server default create-location — the mcp-gee-sweet-shared Shared Drive ID
|
|
9
|
+
DRIVE_FOLDER_ID= # same value as SHARED_DRIVE_ID below
|
|
10
|
+
|
|
11
|
+
# QA test fixtures (provisioned inside the mcp-gee-sweet-shared Shared Drive)
|
|
9
12
|
TEST_SPREADSHEET_ID= # mcp-gee-sweet-qa-fixtures spreadsheet
|
|
10
13
|
TEST_DOC_ID= # mcp-gee-sweet-qa-fixtures-doc
|
|
11
|
-
TEST_FOLDER_ID= # the Drive folder containing
|
|
14
|
+
TEST_FOLDER_ID= # the Shared Drive folder containing the fixture files
|
|
12
15
|
TEST_LARGE_DOC_ID= # mcp-gee-sweet-qa-large-doc (TC-D48 large-content test)
|
|
13
16
|
TEST_CALENDAR_ID= # a calendar the authenticated account can access
|
|
14
17
|
TEST_EVENT_ID= # a pre-existing event in that calendar
|
|
15
18
|
TEST_PERMISSION_EMAIL= # a second account to use for permission add/remove tests (TC-D130)
|
|
19
|
+
SHARED_DRIVE_ID= # mcp-gee-sweet-shared Shared Drive (TC-D121/D122/D205); = DRIVE_FOLDER_ID
|
|
16
20
|
```
|
|
17
21
|
|
|
18
22
|
See `setup.md` for how to create the fixtures and which auth options require extra sharing steps.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# QA Run — 2026-09-04 (v0.9.0 Full Regression)
|
|
2
|
+
|
|
3
|
+
**Auth:** OAuth (6 prefixes: `ash`, `sky`, `jay`, `kit`, `kai-oauth`, `oauth`) + Service Account (2 prefixes: `kai-sa`, `sa`) — all 8 verified running release-candidate source (main-checkout `756eb89` / lane worktrees reset to `origin/develop` `2cace10`; `src/` identical between the two, only a prompt-file differs)
|
|
4
|
+
**Fixtures:** SPREADSHEET_ID=`1dBzY4Wuufx8OtHbQsYO8PQNGV-z5g0Vr_TnKzNCXZYs` · DOC_ID=`1mY8pLffvWqbpMCIfk9WUbTMNAsdz2Vp7PVnkM7m4wK4` · FOLDER_ID=`1S4H65tM0Mltkgdxxq-Vg9FgBlf7DBTam` · SHARED_DRIVE_ID/DRIVE_FOLDER_ID=`0APfXAGTeZYz3Uk9PVA` · CALENDAR_ID=`c_a479062f...@group.calendar.google.com`
|
|
5
|
+
**Start:** 2026-09-03 (pass-prep + shard spawn) · **End:** 2026-09-04 · **Duration:** ~1 day wall-clock (background shards + several correction/re-verification rounds)
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
| Category | PASS | FAIL | SKIP | N/A | Total |
|
|
10
|
+
|---|---|---|---|---|---|
|
|
11
|
+
| Infrastructure (incl. TC-I02/TC-I24 concurrency) | 11 | 0 | 19 | 0 | 30 |
|
|
12
|
+
| Sheets Read | 40 | 0 | 2 | 0 | 42 |
|
|
13
|
+
| Sheets Write | 37 | 1 | 0 | 0 | 38 |
|
|
14
|
+
| Sheets Mgmt | 102 | 0 | 2 | 0 | 104 |
|
|
15
|
+
| Sheets Charts | 12 | 0 | 0 | 0 | 12 |
|
|
16
|
+
| Drive Files | 75 | 3 | 9 | 0 | 87 |
|
|
17
|
+
| Drive Sharing | 20 | 7 | 2 | 0 | 29 |
|
|
18
|
+
| Drive Transfer | 33 | 1 | 1 | 0 | 35 |
|
|
19
|
+
| Drive Activity | 4 | 0 | 1 | 0 | 5 |
|
|
20
|
+
| Docs Content | 167 | 0 | 1 | 1 | 169 |
|
|
21
|
+
| Docs Tables | 12 | 0 | 0 | 0 | 12 |
|
|
22
|
+
| Docs Style | 27 | 0 | 0 | 0 | 27 |
|
|
23
|
+
| Docs Layout | 7 | 0 | 0 | 0 | 7 |
|
|
24
|
+
| Calendar | 76 | 0 | 1 | 0 | 77 |
|
|
25
|
+
| **Total** | **623** | **12** | **38** | **1** | **674** |
|
|
26
|
+
|
|
27
|
+
Additionally: **10 Playwright visual re-verifications** (docs style/tables + drive_transfer conversions) and **7 Playwright/OAuth Calendar re-verifications** are folded into the totals above as the authoritative Result for their TCs (superseding an earlier API-only or SA-substitute pass for the same TC — see "Process notes" below).
|
|
28
|
+
|
|
29
|
+
**750 TCs exist across the 14 files; 674 got a fresh dated Result this pass.** The ~76-TC gap is almost entirely the `docs/qa/runs/README.md` master pre-approved-SKIP list (restart/config-dependent infra cases, local-filesystem-tagged transfer cases already covered by the `tests/integration/` pytest harness, a few environmental/unit-test-only cases) — these keep their standing disposition from that list rather than a redundant fresh per-TC line; see the trimmed table in `docs/qa/runs/v0.9.0.md`.
|
|
30
|
+
|
|
31
|
+
## Failures
|
|
32
|
+
|
|
33
|
+
**TC-D18/D19/D20/D23/D24/D176 — `share_spreadsheet` broken on Shared Drives (one root cause, BUG-SS)**
|
|
34
|
+
Expected: share succeeds, entries land in `successes`.
|
|
35
|
+
Observed: every call returns `failures:[{"error":"Failed to share: File not found: <id>."}]`. Reproduced on a throwaway sheet and the real fixture.
|
|
36
|
+
Root cause (confirmed in source): `share_spreadsheet._share_one`'s `permissions().create()` call omits `supportsAllDrives=True` — the only permission op in `tools/drive/sharing.py` missing it (`update_permission`, `remove_permission`, `list_permissions`, `transfer_ownership`, `share_file` all have it). Since fixtures + the default `DRIVE_FOLDER_ID` are now a Shared Drive (#305), the tool fails on any file it's pointed at in this deployment. `share_file` works (functional workaround exists). One-line fix.
|
|
37
|
+
|
|
38
|
+
**TC-D124 — stale test-case assumption, not a tool bug**
|
|
39
|
+
`list_permissions` on the Shared-Drive fixture shows `organizer`/`fileOrganizer` roles, no `owner` (`owners: []`, correct for Shared Drive items). The TC's "expect an `owner` entry" check predates the #305 migration. Test-case fix applied (see below).
|
|
40
|
+
|
|
41
|
+
**TC-D01 — `create_spreadsheet` response has no web link**
|
|
42
|
+
Response is `{spreadsheetId, title, folder}`; the TC expects a web link. Siblings (`copy_file`, `create_folder`, `get_file_metadata`) do return one. Judgment call, not filed as a bug yet — see Bugs found.
|
|
43
|
+
|
|
44
|
+
**TC-D13 — stale test-case assumption**
|
|
45
|
+
`list_spreadsheets(default)` no longer includes the fixture spreadsheet, because the default folder now resolves to the Shared Drive *root* (`DRIVE_FOLDER_ID`) and the fixture lives in the `FOLDER_ID` *subfolder* — correct post-#305 behavior, stale TC text.
|
|
46
|
+
|
|
47
|
+
**TC-D40 — `list_files` `max_results` cache-poisoning (BUG-CACHE)**
|
|
48
|
+
`list_files(FOLDER_ID, max_results=2)` returned 5 on the first call (a prior default-`max_results` call's cache hit ignored the smaller limit); a subsequent small-`max_results` fetch then *stores* the truncated list, so later default-size calls get only the truncated result until `refresh_cache`. Reproduced twice. Root cause: the folder-listing cache key omits `max_results`. Affects `list_files`, `list_spreadsheets`, `list_folders` (shared cache). Silent, persistent wrong data — the most severe finding this pass.
|
|
49
|
+
|
|
50
|
+
**TC-D167 — stale `#519`-cap test premise, same class as TC-DOC80**
|
|
51
|
+
`export_file`'s base64-xlsx response no longer trips the (raised) `MAX_TOOL_RESPONSE_CHARS` default at this fixture's size. Not a regression; needs the same low-cap re-run method as TC-DOC80 (#678) — tracked as a follow-up, not re-run this pass (lower priority: `export_file`'s cap-check code path is exercised and passing via TC-DOC80's sibling `get_doc_content` check and unit tests).
|
|
52
|
+
|
|
53
|
+
**TC-W02 — test-prompt bug, not a tool bug**
|
|
54
|
+
Prompt used single-quote string delimiters in a Sheets formula (`=A2&' '&A3`); Google Sheets requires double quotes, producing `#ERROR!`. Re-run with `=A2&" "&A3` succeeded; `USER_ENTERED` mode independently confirmed. Test-file fix applied (see below).
|
|
55
|
+
|
|
56
|
+
## Bugs found — filed 2026-09-04
|
|
57
|
+
|
|
58
|
+
| ID | Issue | Severity | Disposition |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| BUG-SS | [#687](https://github.com/khuisman/mcp-gee-sweet/issues/687) — `share_spreadsheet` omits `supportsAllDrives=True`, broken on Shared Drives | Real, release-scope | v0.9, routed to Dev lane B — sign-off conditional on this landing |
|
|
61
|
+
| BUG-CACHE | [#688](https://github.com/khuisman/mcp-gee-sweet/issues/688) — folder-listing cache key omits `max_results`, silent truncation + cross-call poisoning | Real, release-scope (silent wrong data) | v0.9, routed to Dev lane B — sign-off conditional on this landing |
|
|
62
|
+
| BUG-LF | [#689](https://github.com/khuisman/mcp-gee-sweet/issues/689) — `list_folders(parent_folder_id=None)` hardcodes `'root' in parents`, ignores `DRIVE_FOLDER_ID` | Real, confirmed live | v0.9.1 (has an explicit-parent workaround) |
|
|
63
|
+
| BUG-DF | [#690](https://github.com/khuisman/mcp-gee-sweet/issues/690) — `download_file` trailing-slash to a non-existent dir creates a clobbering file instead of the directory | Real, minor | v0.9.1 |
|
|
64
|
+
| — | [#693](https://github.com/khuisman/mcp-gee-sweet/issues/693) — `create_spreadsheet`/`import_csv_to_sheet` response has no web link (siblings have one) | Minor/judgment | v0.9.1 enhancement |
|
|
65
|
+
| — | Service account cannot permanently-delete (only trash) a Shared-Drive item it created; `files().delete()` 404s where `files().get()`/trash both succeed | Minor, likely a Drive API permission-model fact (Content Manager role), not a code defect | Note in docs (`_SA_LIMITATIONS`); not filed as an issue |
|
|
66
|
+
| — | [#691](https://github.com/khuisman/mcp-gee-sweet/issues/691) — `find_free_slots` vs `list_all_events` per-calendar error shape inconsistent (bare string vs structured dict) | Minor | v0.9.1 |
|
|
67
|
+
| — | [#692](https://github.com/khuisman/mcp-gee-sweet/issues/692) — a bare `-` marker alone on its line isn't recognized as a list item by python-markdown regardless of indentation | Minor, markdown-syntax-level gap distinct from the tracked `sane_lists` threshold bug | v0.9.1 |
|
|
68
|
+
|
|
69
|
+
## Test-file fixes applied this pass (not product bugs)
|
|
70
|
+
|
|
71
|
+
- TC-DOC80 (#678), TC-D03/D04/D27/D58/D59/D61/D175 (#680) — done in pass-prep, see `docs/roadmap.md`/commit `966e06a`.
|
|
72
|
+
- TC-D124 (organizer vs owner on Shared Drive), TC-D13 (default-folder assumption), TC-W02 (formula quote style), TC-CAL16 (group-calendar organizer field wording) — need the same treatment; tracked for a fast-follow test-file PR alongside the bug fixes.
|
|
73
|
+
- TC-D167 needs the TC-DOC80-style low-cap rewrite (#678 follow-up).
|
|
74
|
+
|
|
75
|
+
## Process notes
|
|
76
|
+
|
|
77
|
+
- **Playwright auth gap, corrected mid-pass.** Every shard initially hit an unauthenticated Playwright browser (redirects to Google sign-in), concluded Playwright was unusable, and fell back to API-level-only verification. Once the user authenticated Playwright mid-pass, corrections were sent to live shards (one was misdirected due to an agent-ID mix-up on my end, caught and fixed) and a targeted re-verification pass redid the highest-value already-completed visual checks (10 docs/transfer TCs + 7 Sheets TCs) with real screenshots — all confirmed, no discrepancies. Filed **PR #686** to make Playwright-auth verification a real pre-flight step (not just a connection check) for future passes.
|
|
78
|
+
- **Service-account calendar fixture gap.** The SA wasn't subscribed to the real fixture calendar, so the Calendar shard ran its full suite against SA-owned substitute calendars (still valid tool-behavior coverage). A targeted OAuth re-run against the real fixture closed the gap for the 6 identity-sensitive cases plus 2 that only work under OAuth (attendee invites) — all PASS, real fixture left untouched.
|
|
79
|
+
- **Cross-shard fixture interference, resolved.** The Sheets shard's writes to the fixture spreadsheet transiently corrupted the Drive-transfer shard's CSV-export comparison mid-pass. Re-checked after Sheets restored the fixture to seed state — clean, confirms it was timing, not a product bug.
|
|
80
|
+
- **OAuth token refresh issue (infra, not QA).** A fresh script/process using the main-checkout `token.json` now hits `invalid_grant` on refresh; already-running server processes are unaffected (cached token). Recommend re-running `scripts/oauth_setup.py` before the next session needs a fresh OAuth connection. This blocked one live re-verification (TC-DOC159); disposed via a source-diff argument instead (code path unchanged since its last live PASS).
|
|
81
|
+
- **All-slots release-QA rule and the "verify Playwright first" fix were both codified as command-file PRs (#685, #686) during this pass**, per direct user instruction, rather than left as one-off in-conversation guidance.
|
|
82
|
+
|
|
83
|
+
## Tool coverage
|
|
84
|
+
|
|
85
|
+
All 127 registered tools have at least one exercising TC (verified in pass-prep, no drift since). Full coverage table not reproduced here — see `docs/tools.md` (generated, current) cross-referenced against `docs/qa/README.md`'s tool→test-file table.
|
|
86
|
+
|
|
87
|
+
## Screenshots
|
|
88
|
+
|
|
89
|
+
`docs/qa/screenshots/`, prefixed `2026-09-04-` (gitignored per #231) — delete when no longer needed.
|
|
@@ -68,6 +68,67 @@ Give each parallel shard's conductor prompt this protocol explicitly (path, acqu
|
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
71
|
+
## Running true-concurrency test cases
|
|
72
|
+
|
|
73
|
+
A single MCP client session awaits each tool result before issuing the next, so it can never hold two requests to one server process in flight at once. A handful of test cases need genuinely simultaneous requests and are otherwise perpetually skipped:
|
|
74
|
+
|
|
75
|
+
| TC | File | What it needs |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| **TC-I24** | `tests/infra.md` | Two distinct `get_sheet_data` calls (different spreadsheets) firing at the same instant — checks the shared startup `httplib2` transport isn't corrupted across worker threads (issue #183) |
|
|
78
|
+
| **TC-I02** | `tests/infra.md` | A write (`update_cells`) and a read (`get_sheet_data`) on the same spreadsheet firing at the same instant — checks SQLite WAL lets the read proceed during the write with no locking error (issue #234) |
|
|
79
|
+
|
|
80
|
+
`TC-R36`/`TC-R37` (`tests/sheets_read.md`) look similar but are **within-call** concurrency (`get_multiple_sheet_data`/`get_multiple_spreadsheet_summary` `gather()` several `.execute()` calls inside one tool call) — a single session already exercises them. They don't need this procedure; just re-run them normally during the pass and record a fresh Result. Only the **cross-session** cases (TC-I24, TC-I02) need what follows.
|
|
81
|
+
|
|
82
|
+
### Mechanism: two subagents, one server, a `mkdir` barrier
|
|
83
|
+
|
|
84
|
+
Aziz (never a lane session — this runs during the release pass, see `.claude/team-roles/aziz.md`) spawns **two `Agent`-tool subagents** — real subagents, which inherit this session's already-connected MCP servers; **not** Agent-View spawns, which don't. Both subagents point at the **same** server prefix. Prefer **`mcp__mcp-gee-sweet-kai-sa__`** — it runs the main-checkout (release-candidate) code, not a worktree copy. A lane prefix (`mcp__mcp-gee-sweet-sky__` / `-kit__`) also works if the main-checkout server isn't available, but only after that worktree is reset to the release commit; note the substitution in the run file.
|
|
85
|
+
|
|
86
|
+
Per iteration, the two subagents rendezvous at a filesystem barrier so both `.execute()` calls hit the wire within a few milliseconds of each other:
|
|
87
|
+
|
|
88
|
+
- **Barrier dir:** `/tmp/mcp-gee-sweet-qa-barrier` (created once by Aziz before spawning; distinct from the Playwright lock). Markers are files inside it.
|
|
89
|
+
- **A background release watcher** (Aziz starts one `run_in_background` shell loop before spawning the subagents) does, for each iteration `i` from 1 to N:
|
|
90
|
+
- wait until both `ready-a-<i>` and `ready-b-<i>` exist,
|
|
91
|
+
- `touch go-<i>`,
|
|
92
|
+
- wait until both `done-a-<i>` and `done-b-<i>` exist, then continue to `i+1`.
|
|
93
|
+
- **Each subagent** (`<id>` = `a` or `b`), per iteration `i`:
|
|
94
|
+
1. `touch /tmp/mcp-gee-sweet-qa-barrier/ready-<id>-<i>`
|
|
95
|
+
2. spin (`while [ ! -e .../go-<i> ]; do :; done` — a tight poll, no sleep) until `go-<i>` appears
|
|
96
|
+
3. **immediately** issue its one assigned tool call — no reasoning, no other tool call between the spin ending and the call
|
|
97
|
+
4. append the raw result (full response, or the error text) to `/tmp/mcp-gee-sweet-qa-barrier/result-<id>-<i>.json`
|
|
98
|
+
5. `touch /tmp/mcp-gee-sweet-qa-barrier/done-<id>-<i>`
|
|
99
|
+
- **Loop count:** N = 20–50. Transport/SSL corruption and WAL contention are intermittent; one clean pair proves nothing. Stop early and report if any iteration trips a check.
|
|
100
|
+
- **Teardown:** Aziz `rm -rf /tmp/mcp-gee-sweet-qa-barrier` after collecting results.
|
|
101
|
+
|
|
102
|
+
The subagent's job is to run the calls and write result files — **it must not edit any tracked repo file**. Only Aziz reads the `result-*` files back, diffs them, and writes the `**Result**` entries (see `.claude/team-roles/aziz.md`, the Compile step).
|
|
103
|
+
|
|
104
|
+
### Per-TC checks
|
|
105
|
+
|
|
106
|
+
**TC-I24** — subagent `a` calls `get_sheet_data` on `{SPREADSHEET_ID}` / `Sales!A1:C3`; subagent `b` calls `get_sheet_data` on a **second, distinct** spreadsheet / range with different known values. Across all N iterations:
|
|
107
|
+
- every `result-a-*` holds only `{SPREADSHEET_ID}`'s data, every `result-b-*` only the second spreadsheet's — no row from one appears in the other's file
|
|
108
|
+
- no result is empty, truncated, or an SSL/connection error (`record layer failure`, `Connection reset by peer`, `Remote end closed connection` — the signature of the shared-transport bug this guards against)
|
|
109
|
+
|
|
110
|
+
**TC-I02** — subagent `a` calls `update_cells` writing a per-iteration sentinel (e.g. `QA-I02-<i>-<timestamp>`) to `{SPREADSHEET_ID}` / `Empty!A1`; subagent `b` calls `get_sheet_data` on `{SPREADSHEET_ID}` / `Sales!A1:C3` (a different sheet in the same spreadsheet, so both touch the same cache row). Across all N iterations:
|
|
111
|
+
- no `result-b-*` is a `database is locked` / `SQLITE_BUSY` error, and none is empty or an SSL/connection error
|
|
112
|
+
- every `result-a-*` reports the write succeeded
|
|
113
|
+
- if the server's `LOG_FILE` is reachable (from `docs/qa/.env` or the team MCP config), grep it for `database is locked` / `OperationalError` over the run window — there should be none; if it isn't reachable, the response-level checks above still catch the failure mode (WAL contention surfaces as an error in the response, not just the log)
|
|
114
|
+
|
|
115
|
+
### Subagent prompt template
|
|
116
|
+
|
|
117
|
+
Give each of the two subagents a prompt of this shape (fill the bracketed parts; `<id>` is `a` for one, `b` for the other):
|
|
118
|
+
|
|
119
|
+
> You are one of two subagents running a true-concurrency QA iteration loop. Your worker id is **`<id>`**. Barrier dir: `/tmp/mcp-gee-sweet-qa-barrier`. Iterations: **`<N>`**.
|
|
120
|
+
>
|
|
121
|
+
> For `i` in 1..`<N>`, in order:
|
|
122
|
+
> 1. `touch /tmp/mcp-gee-sweet-qa-barrier/ready-<id>-$i`
|
|
123
|
+
> 2. Spin with a tight shell poll until `/tmp/mcp-gee-sweet-qa-barrier/go-$i` exists.
|
|
124
|
+
> 3. The instant it exists, call **exactly this tool, once**: `[full tool name + params, e.g. mcp__mcp-gee-sweet-kai-sa__get_sheet_data(spreadsheet_id="…", range="Sales!A1:C3")]`. Do nothing else first — no other tool call, no reasoning step, between the spin ending and this call.
|
|
125
|
+
> 4. Append the tool's full raw result (or, on error, the complete error text) as one JSON line to `/tmp/mcp-gee-sweet-qa-barrier/result-<id>-$i.json`.
|
|
126
|
+
> 5. `touch /tmp/mcp-gee-sweet-qa-barrier/done-<id>-$i`
|
|
127
|
+
>
|
|
128
|
+
> Call **only** `mcp__mcp-gee-sweet-kai-sa__*` tools. Do **not** edit, create, or delete any file inside the git repo — your only writes are to `/tmp/mcp-gee-sweet-qa-barrier/`. When the loop finishes, report back: for each `i`, whether the tool call returned data or an error, and the first ~200 chars of each result. Do not interpret pass/fail — just report what you observed.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
71
132
|
## Drive fixture-folder pollution
|
|
72
133
|
|
|
73
134
|
`TEST_FOLDER_ID` accumulates stray items across many creation/copy test categories that don't tear down after themselves (tracked in [#304](https://github.com/khuisman/mcp-gee-sweet/issues/304) — dedicated QA account/cleanup sweep). As of 2026-07-17 it held ~15 duplicate leftovers (`Copy of mcp-gee-sweet-qa-fixtures` ×2, `QA-Cache-Check` ×2, `QA-Copy-Explicit`, `QA-Create-Explicit`, `QA-Doc-Copy`, `QA-DocCache`, `QA-HTML-Doc` ×2, `QA-Markdown-Doc` ×2, `QA-Table-Doc` ×2, loose `qa-notes.md`/`qa-upload.txt`, two leftover folders).
|
|
@@ -97,7 +158,7 @@ Workaround: the fixture files have fixed, documented names (`setup.md`'s seed pr
|
|
|
97
158
|
```
|
|
98
159
|
You are the QA conductor for mcp-gee-sweet. Your job is to execute the full test suite against the live MCP server, record outcomes, and save a results report.
|
|
99
160
|
|
|
100
|
-
You have the mcp-gee-sweet MCP connected. Before starting, check whether Playwright MCP is also connected
|
|
161
|
+
You have the mcp-gee-sweet MCP connected. Before starting, check whether Playwright MCP is also connected AND actually authenticated to Google — these are different things: a connected Playwright MCP still runs an unauthenticated browser by default, and navigating it to a Google URL just redirects to `accounts.google.com` sign-in. Do a real check: navigate to a known Google URL (e.g. the fixture doc) and confirm the page title/URL is the real resource, not a sign-in page. If Playwright isn't connected, or the navigation redirects to sign-in, tell me: "Playwright is not connected / not authenticated — tests marked **Playwright: required** will run without visual verification. Confirm to proceed, or connect/authenticate Playwright first (see `docs/qa/playwright_oauth.md`) and restart." Wait for my confirmation before continuing. If I tell you mid-run that Playwright is now authenticated, re-verify immediately and switch to using it for all subsequent **Playwright: required** cases — don't keep treating it as unusable for the rest of the run based on the earlier check.
|
|
101
162
|
|
|
102
163
|
## Step 0 — Fixture setup
|
|
103
164
|
|
|
@@ -105,7 +166,7 @@ Before running any tests:
|
|
|
105
166
|
|
|
106
167
|
1. Record the start time (current timestamp).
|
|
107
168
|
2. Read `.env` from the repo root. If the file does not exist or the TEST_* keys are missing, stop and say: ".env not found or TEST_* keys missing — follow docs/qa/setup.md to create your fixtures first."
|
|
108
|
-
3. Extract TEST_SPREADSHEET_ID, TEST_DOC_ID, TEST_FOLDER_ID, TEST_CALENDAR_ID, TEST_EVENT_ID, TEST_LARGE_DOC_ID, TEST_PERMISSION_EMAIL.
|
|
169
|
+
3. Extract TEST_SPREADSHEET_ID, TEST_DOC_ID, TEST_FOLDER_ID, TEST_CALENDAR_ID, TEST_EVENT_ID, TEST_LARGE_DOC_ID, TEST_PERMISSION_EMAIL, SHARED_DRIVE_ID.
|
|
109
170
|
4. Verify the fixture spreadsheet with get_sheet_data: confirm sheet tabs Sales, Empty, Notes & Misc exist and Sales data has 6 rows (header + Widget/Gadget/Donut/Gizmo/Totals), columns A–D. If data is missing or in wrong order, use update_cells to restore known seed state (see docs/qa/setup.md §Known fixture state).
|
|
110
171
|
5. Verify the fixture doc with get_doc_structure: confirm title "mcp-gee-sweet-qa-fixtures-doc" and body contains heading "Test Document", a paragraph, and a bullet list (Item one / Item two). If content is wrong, use write_doc_content to restore it.
|
|
111
172
|
6. Tell me the fixture IDs, start time, and whether the fixture state looks correct, then wait for me to confirm before proceeding.
|
|
@@ -68,12 +68,13 @@ Disposition of every SKIP from the v0.8.0 Full Regression run (44 total, `docs/q
|
|
|
68
68
|
- **Pre-approved** — no action; already covered or a documented non-testable limitation
|
|
69
69
|
- **Unit-tested** — verified live against `tests/` to actually cover the case; safe to pre-approve
|
|
70
70
|
- **Environmental** — needs a fixture/account change to un-skip; low-risk by inspection in the meantime
|
|
71
|
+
- **Procedure exists** — was manual-only for lack of a way to run it; now has a documented procedure and **must be executed during the pass**, not skipped
|
|
71
72
|
- **Genuine gap** — verified *not* covered anywhere; tracked as a follow-up issue, still counts as a live-run SKIP until closed
|
|
72
73
|
|
|
73
74
|
| TC | Reason | Category | Coverage / Action |
|
|
74
75
|
|---|---|---|---|
|
|
75
76
|
| TC-I01, I03 | Cache TTL / `CACHE_DB_PATH` — requires restart | Unit-tested | ✅ `tests/test_cache.py` |
|
|
76
|
-
| TC-I02 |
|
|
77
|
+
| TC-I02, TC-I24 | Cross-session concurrency — needs two simultaneous requests to one server, which a single client session can't produce | Procedure exists | Run via `run.md` §"Running true-concurrency test cases" (two-subagent `mkdir`-barrier procedure) during the release pass — no longer a standing SKIP (#673) |
|
|
77
78
|
| TC-I04 | Cache persists across restart | Pre-approved | SQLite file persistence, trivially true by design |
|
|
78
79
|
| TC-I13 | stdio transport — requires client config change | Pre-approved | Manual / verify once per environment |
|
|
79
80
|
| TC-I15 | Hot reload with SSE | Pre-approved | Manual — known uvicorn + SSE limitation |
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# QA Run Gate — v0.9.0
|
|
2
|
+
|
|
3
|
+
**Release type:** Stable
|
|
4
|
+
**Suite required:** **Full Regression** — see scoping audit below
|
|
5
|
+
**Status:** ✅ pass complete, bugs filed and routed — sign-off conditional on #687/#688 landing before tagging. Pass ran 2026-09-03 → 2026-09-04.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Pre-flight
|
|
10
|
+
|
|
11
|
+
- [x] Aziz worktree synced to `origin/develop` @ `2cace10` (step 1); run branch `qa/v0.9.0-release-pass`
|
|
12
|
+
- [x] Release-candidate source confirmed: main-checkout servers (`oauth`/`sa`/`kai-oauth`/`kai-sa`) run `756eb89`, whose `src/` tree is byte-identical to `origin/develop` `2cace10` (only `.claude/team-roles/bob.md` differs)
|
|
13
|
+
- [x] Prompt-file precondition satisfied — Bob cleared it (2026-09-03): `docs/tools.md` sweep done (#681/#682/#683 → v0.9.1), no open pass-procedure PRs. New this pass: PR #685 (`aziz.md` all-slots rule) is in force by direct user instruction; Bob's merge is not a pass blocker (pass exercises it in situ).
|
|
14
|
+
- [x] No lane mid-ticket — 0 open PRs; `ash`/`sky`/`jay`/`kit` worktrees all on `team/<name>`, reset to `2cace10` for the pass
|
|
15
|
+
- [x] Fixtures: repo-root `.env` present with all 8 `TEST_*`/`SHARED_DRIVE_ID` keys; identical across all worktrees. `DRIVE_FOLDER_ID` = Shared Drive root on every server.
|
|
16
|
+
- [x] Fixture state verified (Sales sheet 6 rows, fixture doc structure) — per shard, at shard start; confirmed clean at pass end too
|
|
17
|
+
|
|
18
|
+
**Auth method used:** OAuth (6 prefixes) + service account (2 prefixes) — see shard table.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Scoping audit — why Full Regression
|
|
23
|
+
|
|
24
|
+
Per `docs/qa/runs/README.md` §"Scoped gating".
|
|
25
|
+
|
|
26
|
+
**1. Enumerate.** `git log v0.8.1..origin/develop` — **388 commits, 239 merged PRs**, 2026-07-04 → 2026-09-03 (~2 months).
|
|
27
|
+
|
|
28
|
+
**2/3. Behavior changes by domain.** New tools and behavior changes land in *every* domain:
|
|
29
|
+
|
|
30
|
+
| Domain | Representative changes since v0.8.1 |
|
|
31
|
+
|---|---|
|
|
32
|
+
| sheets_read | #235-era response cap already shipped; `get_multiple_*` `gather()` (#293) |
|
|
33
|
+
| sheets_write | rich-text partial hyperlinks in `update_cells` (#89/#380) |
|
|
34
|
+
| sheets_mgmt | `add_data_validation`/`get_data_validation` (#361), `update_borders` (#325), `update_sheet_properties` (#301), `resize_rows`/`resize_columns` (#321), `hide_rows`/`hide_columns` (#311), `duplicate_sheet` (#286), `_get_sheet_id` error propagation (#384/#390, #440) |
|
|
35
|
+
| sheets_charts | no new tools; teardown added to test cases (#322) |
|
|
36
|
+
| drive_files | `star_file`/`unstar_file` (#139), `restore_file`/`empty_trash` (#138), `create_shortcut` (#141), `md5Checksum` exposure (#274), `list_drives` pagination (#489); **Shared Drive fixture migration (#305)** changes default-folder semantics for `create_*` |
|
|
37
|
+
| drive_sharing | `transfer_ownership` (#140), `_SA_LIMITED_TOOLS` split (#447/#507) |
|
|
38
|
+
| drive_transfer | `convert` on `upload_local_file` (#188), `convert_markdown` on `sync_folder` (#211) + 3 edge-case rounds (#422/#433/#414), `use_checksum` (#274), `import_csv_to_sheet` (#272), `sync_folder` recursive (#328), dry_run dedup + cap offramp (#518), `upload_local_folder` routed through `_upload_local_file` (#411/#505), restamp-failure `fileId` reporting (#420/#650) |
|
|
39
|
+
| drive_activity | `list_file_activity` (Drive Activity API v2) |
|
|
40
|
+
| docs_content | **`docs/__init__.py` split into 8 submodules (#372/#371/#570/#576)** — structural; `get_doc_as_markdown` (#300/#591/#599), `create_doc_from_file`/`update_doc_from_file` (#341/#564), native md/HTML image conversion (#333/#502), heading-anchor resolution (#409/#453), blockquote support (#476/#546), `insert_softbreak_paragraph`/`insert_local_images` (#332), `find_in_doc` (#353), `create_named_range`/`create_bookmark` (#337), whitespace/paragraph-boundary parser fixes (#401/#402/#441/#443/#450/#478), inline-image size validation (#400/#562) |
|
|
41
|
+
| docs_tables | `merge_table_cells` (#310), colspan/rowspan in nested tables (#287), text-with-nested-table positioning (#276/#282) |
|
|
42
|
+
| docs_style | `style_doc_table_cells`/`apply_theme` per-edge borders (#403/#462), `create_paragraph_bullets`/`delete_paragraph_bullets` (#334/#524), `link_url=null` clear (#408/#446), nested-bullet depth emit (#336/#432) |
|
|
43
|
+
| docs_layout | no new tools |
|
|
44
|
+
| calendar | `create_calendar`/`update_calendar`/`delete_calendar` (#266), `add_calendar_to_list`/`remove_calendar_from_list` (#269), Calendar ACL tools (#158/#455), `add_calendar_acl` scope validation (#458/#616), `list_all_events` (#194/#464), `list_calendar_acl` pagination (#460/#612), `find_free_slots` multi-cal (#491) |
|
|
45
|
+
| infra | **mcp v1 → v2 migration (#175/#642)** — cross-cutting, all tools + both MCP resources; **async tool execution refactor (#293)** — cross-cutting; MCP resources `get_context()` fix (#363/#368); runtime-configurable cache TTL (#284); `MAX_TOOL_RESPONSE_CHARS` default 40000→1,000,000 (#519/#556); SA-vs-user ADC in `server://auth-status` (#506/#613) |
|
|
46
|
+
|
|
47
|
+
**4. Refactors never live-tested since v0.8.1's run:** the `docs/` submodule split, the mcp v2 migration, and the async execution refactor are all structural/cross-cutting and none has had a full live pass.
|
|
48
|
+
|
|
49
|
+
**5/7. Decision.** Every domain has behavior changes; three separate structural/cross-cutting refactors (docs split, mcp v2, async) sit under the whole tool surface; the fixture environment itself moved to a Shared Drive. This is the README's step-7 fallback outright (">roughly half the domains would need a Domain run anyway" — here it's all of them). **Full Regression**, no scoping. Matches the pre-recorded roadmap decision (`project_v09_roadmap` memory: "QA tier = Full Regression").
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Pass-prep applied before the run (this branch)
|
|
54
|
+
|
|
55
|
+
- **#678** — TC-DOC80 (`docs_content.md`) rewritten: `MAX_TOOL_RESPONSE_CHARS` default is now 1,000,000 (#519), the `TEST_LARGE_DOC_ID` fixture (~54k) can't trip it on a normal server. Case now runs against a low cap (`MAX_TOOL_RESPONSE_CHARS=40000` — purpose-started server or a direct `uv run python3 -c` invocation of the real `get_doc_content`), handled by Aziz outside the shared shard. Stale 2026-07-03 Result marked superseded.
|
|
56
|
+
- **#680** — `drive_files.md` TC-D03/D04/D27/D58/D59/D61/D175 reworked for Shared-Drive semantics (`DRIVE_FOLDER_ID` ≠ `TEST_FOLDER_ID` now):
|
|
57
|
+
- D58/D59/D03 — "default folder" / "no parent" now resolve to `DRIVE_FOLDER_ID` (Shared Drive), not personal My-Drive root; checks updated.
|
|
58
|
+
- D61 — moves between two throwaway folders instead of "to My Drive root" (avoids cross-drive-move / ownership-transfer semantics).
|
|
59
|
+
- D04/D175 — SA quota error only fires with an explicit personal-Drive destination now; default path succeeds into the Shared Drive. Checks force the personal-Drive dest; SKIP(environmental) if no such folder available.
|
|
60
|
+
- D27 — **confirmed tool gap:** `list_folders(parent_folder_id=None)` hardcodes `'root' in parents`, ignores `DRIVE_FOLDER_ID`; broken for any Shared-Drive deployment / pure-SA. Filed as [BUG-LF] (see Bugs found).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Shard plan
|
|
65
|
+
|
|
66
|
+
8 server prefixes, all verified equivalently configured (6 OAuth: `mcp-gee-sweet-{ash,sky,jay,kit,kai-oauth,oauth}`; 2 SA: `mcp-gee-sweet-{kai-sa,sa}`). One prefix per shard, run concurrently. Subagents run live calls and report structured PASS/FAIL/SKIP only — **no subagent edits a tracked file**; Aziz writes all Results.
|
|
67
|
+
|
|
68
|
+
| # | Shard | Files (order) | Exclusive fixture / isolation | Prefix |
|
|
69
|
+
|---|---|---|---|---|
|
|
70
|
+
| 1 | Sheets | sheets_read → sheets_write → sheets_mgmt → sheets_charts (serial; incl. TC-R36/R37 re-run) | `TEST_SPREADSHEET_ID` (sole writer) | `kai-oauth` |
|
|
71
|
+
| 2 | Docs-content | docs_content (minus TC-DOC80) | `TEST_DOC_ID` + own throwaway docs | `oauth` |
|
|
72
|
+
| 3 | Docs-style/tables/layout | docs_style, docs_tables, docs_layout | **own throwaway doc only** — substitute a self-created doc for `{DOC_ID}`, never `TEST_DOC_ID` | `ash` |
|
|
73
|
+
| 4 | Drive-files | drive_files | own throwaway child folder under Shared Drive | `sky` |
|
|
74
|
+
| 5 | Drive-transfer | drive_transfer | own throwaway child folder; local-fs cases SKIP | `jay` |
|
|
75
|
+
| 6 | Drive-sharing+activity | drive_sharing, drive_activity | `TEST_PERMISSION_EMAIL` | `kit` |
|
|
76
|
+
| 7 | Calendar | calendar | `TEST_CALENDAR_ID` (independent) | `kai-sa` |
|
|
77
|
+
| 8 | Infra | infra (live-testable subset) | — | `sa` |
|
|
78
|
+
| — | Concurrency | TC-I24, TC-I02 | 2 subagents + `mkdir` barrier, run last, solo | `kai-sa` |
|
|
79
|
+
| — | TC-DOC80 | #678 low-cap method | Aziz direct (`uv run python3 -c`, `MAX_TOOL_RESPONSE_CHARS=40000`) | — |
|
|
80
|
+
|
|
81
|
+
Shared across all shards: one cache DB per server process (concurrency-safe by design — that's what TC-I02 checks), one `LOG_FILE` (`/tmp/mcp-gee-sweet.log`, interleaved but functional), one Google account for the 6 OAuth prefixes (watch for 429/`rateLimitExceeded` — shards back off + retry). Playwright mutex: `/tmp/mcp-gee-sweet-playwright.lock`, per `docs/qa/run.md`.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Suite checklist
|
|
86
|
+
|
|
87
|
+
- [x] **Sheets Read** — `sheets_read.md` — 40 PASS / 0 FAIL / 2 SKIP (42)
|
|
88
|
+
- [x] **Sheets Write** — `sheets_write.md` — 37 PASS / 1 FAIL / 0 SKIP (38 run; 2 more TCs than originally listed, corrected count)
|
|
89
|
+
- [x] **Sheets Mgmt** — `sheets_mgmt.md` — 102 PASS / 0 FAIL / 2 SKIP (104)
|
|
90
|
+
- [x] **Sheets Charts** — `sheets_charts.md` — 12 PASS / 0 FAIL / 0 SKIP (12)
|
|
91
|
+
- [x] **Drive Files** — `drive_files.md` — 75 PASS / 3 FAIL / 9 SKIP (87 run; remainder covered by the pre-approved-SKIP master list)
|
|
92
|
+
- [x] **Drive Sharing** — `drive_sharing.md` — 20 PASS / 7 FAIL / 2 SKIP (29)
|
|
93
|
+
- [x] **Drive Transfer** — `drive_transfer.md` — 33 PASS / 1 FAIL / 1 SKIP (35 run; remainder is the 57 local-filesystem pre-approved SKIPs, already covered by `tests/integration/`)
|
|
94
|
+
- [x] **Drive Activity** — `drive_activity.md` — 4 PASS / 0 FAIL / 1 SKIP (5)
|
|
95
|
+
- [x] **Docs Content** — `docs_content.md` — 167 PASS / 0 FAIL / 1 SKIP / 1 N/A (169; TC-DOC80 run separately, see below)
|
|
96
|
+
- [x] **Docs Tables** — `docs_tables.md` — 12 PASS / 0 FAIL / 0 SKIP (12)
|
|
97
|
+
- [x] **Docs Style** — `docs_style.md` — 27 PASS / 0 FAIL / 0 SKIP (27)
|
|
98
|
+
- [x] **Docs Layout** — `docs_layout.md` — 7 PASS / 0 FAIL / 0 SKIP (7)
|
|
99
|
+
- [x] **Infrastructure** — `infra.md` — 11 PASS / 0 FAIL / 19 SKIP (30; includes TC-I24/TC-I02 as 2 of the 11 PASS)
|
|
100
|
+
- [x] **Calendar** — `calendar.md` — 76 PASS / 0 FAIL / 1 SKIP (77; includes 6 fixture-identity-sensitive TCs re-verified against the real fixture on OAuth after the SA-substitute shard, per Run history)
|
|
101
|
+
- [x] **Concurrency** — TC-I24 (47/50 valid data points, zero cross-contamination), TC-I02 (50/50 clean, zero locking errors) — both **PASS**
|
|
102
|
+
|
|
103
|
+
**Grand total: 623 PASS / 12 FAIL / 38 SKIP / 1 N/A across 674 TCs** (out of 750 in the 14 files — the ~76-TC gap is the pre-approved-SKIP master list below, kept at its standing disposition rather than a redundant fresh line). Plus 17 Playwright/OAuth re-verifications folded into the totals as the authoritative Result for their TCs (see Run history).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Pre-approved SKIPs
|
|
108
|
+
|
|
109
|
+
Copied from `docs/qa/runs/README.md` master list, trimmed to v0.9.0 scope. TC-I02/TC-I24 are **no longer standing SKIPs** (#673) — run via the barrier procedure.
|
|
110
|
+
|
|
111
|
+
| TC | Reason | Coverage / action |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| TC-I01, I03, I04 | Cache TTL / DB path / persistence — require restart | ✅ `tests/test_cache.py`; persistence trivially true |
|
|
114
|
+
| TC-I05–I12 | Tool filtering / auth variants — require restart | ✅ `tests/test_server.py`; auth in #98 |
|
|
115
|
+
| TC-I13, I15 | stdio transport / SSE hot reload — env/manual | Verify once per environment |
|
|
116
|
+
| TC-D35 | `search_spreadsheets` forced API error | Genuine gap — #490 (unit test added, PR #572; confirm) |
|
|
117
|
+
| TC-D95 | `upload_local_file` skip_if_exists=False duplicate | #495 (PR #634 — confirm) |
|
|
118
|
+
| TC-D98–D107, D109, D110 | `upload_local_folder` / `download_file` / `download_folder` params — local-filesystem | Unit coverage added #485/#486/#487; live path is local-fs, SKIP here |
|
|
119
|
+
| TC-D119 | `sync_folder` invalid `direction` | #488 (PR #563 — confirm returns error dict) |
|
|
120
|
+
| TC-D123 | `list_drives` pagination | #489 (PR #569); also permanently env-skipped per #305 (`TEST_FOLDER_2_ID` retired) |
|
|
121
|
+
| TC-D155 | `list_shared_with_me` quote escaping | #494 (PR #577 — confirm) |
|
|
122
|
+
| TC-DOC51 | Nested tables in markdown | Documented limitation |
|
|
123
|
+
| TC-CAL04 | `list_calendars` empty subscription | Environmental |
|
|
124
|
+
| TC-CAL32 | `find_free_slots` multi-calendar merge | #491 (PR #575 — confirm) |
|
|
125
|
+
|
|
126
|
+
(Per-shard SKIPs beyond this list get recorded with reasons at compile.)
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Results
|
|
131
|
+
|
|
132
|
+
| Run date | Auth | Results file | PASS | FAIL | SKIP | N/A |
|
|
133
|
+
|---|---|---|---|---|---|---|
|
|
134
|
+
| 2026-09-03/04 | OAuth (6 prefixes) + service account (2 prefixes) | [docs/qa/results/2026-09-04.md](../results/2026-09-04.md) | 623 | 12 | 38 | 1 |
|
|
135
|
+
|
|
136
|
+
## Run history / incidents
|
|
137
|
+
|
|
138
|
+
- **Playwright browser wasn't authenticated to Google at pass start.** Every one of the 8 parallel shards independently hit the sign-in redirect within its first few `**Playwright: required**` TCs, concluded Playwright was unusable, and fell back to API-level-only verification for its entire remaining run. The user authenticated Playwright mid-pass; corrections were sent to the two still-running shards (Sheets, Docs-content retries) — one was misdirected due to an agent-ID mix-up on Aziz's own end (caught and corrected). A dedicated re-verification pass then redid the ~17 highest-value already-completed visual checks (10 docs/drive_transfer TCs, 7 Sheets TCs) with real screenshots — all PASS, zero discrepancies from the API-only evidence. Filed **PR #686** to make Playwright-auth verification (a real navigate, not just a connection check) a mandatory pre-flight step for future passes, done once centrally before spawning shards.
|
|
139
|
+
- **Service account wasn't subscribed to the fixture calendar.** The Calendar shard's reads against `{CALENDAR_ID}`/`{EVENT_ID}` all 404'd on the SA prefix; it ran its full 77-TC suite against two SA-owned scratch calendars instead (valid tool-behavior coverage, but not against the real fixture). A targeted OAuth re-run against the real fixture closed the gap for 6 identity-sensitive TCs (CAL05/16/60/62/67) plus 2 that only work under OAuth at all (CAL17/22 — attendee invites, which a service account cannot send) — all PASS, real fixture confirmed untouched (`updated` timestamp identical pre/post).
|
|
140
|
+
- **Cross-shard fixture interference (transient, resolved).** The Sheets shard's writes to `{SPREADSHEET_ID}` were caught mid-mutation by the Drive-transfer shard's CSV-export comparison (TC-D86 vs TC-D104 diverged: extra column, an `#ERROR!` cell, an extra row). Re-checked after the Sheets shard restored the fixture to seed state — both exports now agree byte-for-byte. Not a product bug; a sharding-design lesson (two shards touching the same fixture, one read-mostly, without wave-sequencing).
|
|
141
|
+
- **Main-checkout OAuth `token.json` refresh token is failing (`invalid_grant`) for fresh processes.** Already-running MCP server processes are unaffected (they hold an already-refreshed in-memory token — confirmed live-working throughout this pass), but any *new* script/session using this file will hit it and fall into an interactive-consent hang. This blocked one live re-verification (TC-DOC159 — raw `documents().get()` read of blockquote indent/border), disposed instead via a source-diff argument (the exact code path hasn't changed since its last live PASS). Recommend re-running `scripts/oauth_setup.py` before the next session needs a fresh OAuth connection — flagged to the user, not a QA finding.
|
|
142
|
+
- **Two subagent-prompt mistakes, both self-inflicted and non-blocking:** the TC-I24/TC-I02 concurrency subagents were given a slightly wrong tool-call syntax (`range="Sheet!A1:C3"` instead of separate `sheet=`/`range=` params) for their first 1-2 iterations each; all subagents self-corrected immediately and the remaining iterations are the ones adjudicated. Neither is a transport/locking signature — genuine client-side parameter errors.
|
|
143
|
+
- **Google Drive API had two transient server-side blips** (an `export_file` `HttpError 500 Internal Error`, and one `delete_file(permanent=True)` `404` on a file `get_file_metadata` could see and trash could act on — isolated to the service-account prefix specifically; the same delete succeeded immediately via OAuth on the identical file, suggesting a Shared-Drive Content-Manager-role permission-model quirk rather than a code defect). Neither reproduced on retry via the correct auth path; not filed as product bugs.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Bugs found
|
|
148
|
+
|
|
149
|
+
| ID | Title | Severity | Disposition |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| BUG-SS | `share_spreadsheet` omits `supportsAllDrives=True` on its `permissions().create()` call — every sibling permission op in the same file has it. Fails with "File not found" for any Shared-Drive file (the current fixture environment, post-#305). `share_file` still works (functional workaround). | Real, release-scope | File — v0.9.0, route to Dev lane B |
|
|
152
|
+
| BUG-CACHE | Folder-listing cache key omits `max_results` — a smaller-limit call can (a) get an unfiltered cache hit from an earlier larger call, ignoring the limit, and (b) *store* its own truncated result, so later larger-limit calls get the truncated list until `refresh_cache`. Reproduced twice. Affects `list_files`, `list_spreadsheets`, `list_folders` (shared cache). | Real, release-scope — silent persistent wrong data, the most severe finding this pass | File — v0.9.0, route to Dev lane B |
|
|
153
|
+
| BUG-LF | `list_folders(parent_folder_id=None)` hardcodes `'root' in parents`, ignores `DRIVE_FOLDER_ID` — broken scope on any Shared-Drive deployment and for a pure service account (no personal root). Confirmed live (TC-D27). Has an explicit-parent workaround. | Real, confirmed live | File — v0.9.1 |
|
|
154
|
+
| BUG-DF | `download_file` with a trailing-slash `local_path` to a non-existent directory creates a single file at that path (not the directory) and silently clobbers it on every subsequent download to the same path. Correct once the directory already exists. | Real, minor | File — v0.9.1 |
|
|
155
|
+
| (enhancement) | `create_spreadsheet`/`import_csv_to_sheet` response has no web link, unlike `copy_file`/`create_folder`/`get_file_metadata` | Minor/judgment call | User to decide: add `web_link` for consistency, or fix TC-D01's expectation instead |
|
|
156
|
+
| (doc note) | Service account's Shared-Drive "Content manager" role can trash but apparently not permanently-delete (`files().delete()`) an item it created — surfaced as a 404, not 403. Same call succeeds immediately via OAuth on the identical file. Looks like a Drive API permission-model fact, not a code defect. | Minor, informational | Note in `_SA_LIMITATIONS`/docs, not filing as a bug |
|
|
157
|
+
| (minor) | `find_free_slots` per-calendar error shape (`{"error": "notFound"}`, bare) is less detailed than `list_all_events`'s (`{calendar_id, calendar_summary, error: <full repr>}`) for the same failure mode | Minor | File — v0.9.1 |
|
|
158
|
+
| (minor) | A bare `-` marker alone on its line isn't recognized as a list item by python-markdown regardless of indentation width — distinct from the tracked `sane_lists` threshold bug these fixtures otherwise target | Minor, markdown-syntax-level gap | File — v0.9.1, or a doc note in `markdown-support.md` |
|
|
159
|
+
|
|
160
|
+
**Filed** (2026-09-04, per direct user go-ahead):
|
|
161
|
+
|
|
162
|
+
| ID | Issue | Labels |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| BUG-SS | [#687](https://github.com/khuisman/mcp-gee-sweet/issues/687) | `defect`, `qa`, `v0.9`, `ready-for-development`, `lane-b` |
|
|
165
|
+
| BUG-CACHE | [#688](https://github.com/khuisman/mcp-gee-sweet/issues/688) | `defect`, `qa`, `v0.9`, `ready-for-development`, `lane-b` |
|
|
166
|
+
| BUG-LF | [#689](https://github.com/khuisman/mcp-gee-sweet/issues/689) | `defect`, `qa`, `v0.9.1` |
|
|
167
|
+
| BUG-DF | [#690](https://github.com/khuisman/mcp-gee-sweet/issues/690) | `defect`, `qa`, `v0.9.1` |
|
|
168
|
+
| find_free_slots error-shape | [#691](https://github.com/khuisman/mcp-gee-sweet/issues/691) | `defect`, `qa`, `v0.9.1` |
|
|
169
|
+
| markdown bare `-` marker gap | [#692](https://github.com/khuisman/mcp-gee-sweet/issues/692) | `defect`, `qa`, `v0.9.1` |
|
|
170
|
+
| `create_spreadsheet`/`import_csv_to_sheet` web_link | [#693](https://github.com/khuisman/mcp-gee-sweet/issues/693) | `enhancement`, `qa`, `v0.9.1` |
|
|
171
|
+
|
|
172
|
+
BUG-SS (#687) and BUG-CACHE (#688) routed straight to `ready-for-development`/`lane-b` (both, simultaneously — a deliberate exception to the usual one-at-a-time front-of-queue labeling discipline, per direct user instruction: these are two known, already-scoped v0.9.0-blocking findings from this pass, not an untriaged backlog). The service-account Shared-Drive permanent-delete finding is a docs-only note (`_SA_LIMITATIONS`), not filed as an issue.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Sign-off
|
|
177
|
+
|
|
178
|
+
- [x] All 14 domain suites + concurrency complete, Results written inline (674 TCs)
|
|
179
|
+
- [x] TC-DOC80 (#678) re-run under low-cap method — PASS
|
|
180
|
+
- [x] All FAILs disposed — 4 are stale test-case assumptions (fixed in this branch: TC-D124, TC-D13, TC-W02, TC-CAL16), 1 (TC-D167) tracked as a follow-up of the same class as TC-DOC80, 6 (the `share_spreadsheet` TCs) and 1 (TC-D40) trace to BUG-SS/BUG-CACHE respectively — filed and routed above. No FAIL is left undiagnosed.
|
|
181
|
+
- [x] `docs/qa/results/2026-09-04.md` written and linked
|
|
182
|
+
- [x] Bugs filed — #687-#693 (BUG-SS, BUG-CACHE, BUG-LF, BUG-DF + 3 minor)
|
|
183
|
+
- [x] QA-gate PR opened — see below
|
|
184
|
+
|
|
185
|
+
**BUG-SS (#687) and BUG-CACHE (#688) are routed to Dev lane B for a v0.9.0 fix before the release tags** — sign-off is conditional on those landing; v0.9.0 should not ship with them open. BUG-LF, BUG-DF, and the 3 minor findings are lower-severity/have workarounds and are v0.9.1 follow-ups.
|
|
186
|
+
|
|
187
|
+
**Signed off by:** Aziz (Release QA Lead), pending user confirmation of the final go-ahead to tag once #687/#688 land **Date:** 2026-09-04
|