mcp-gee-sweet 0.7.0.dev76__tar.gz → 0.7.0.dev80__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.
Files changed (141) hide show
  1. mcp_gee_sweet-0.7.0.dev80/.claude/commands/orchestrator.md +20 -0
  2. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.claude/commands/prep-for-pr.md +2 -2
  3. mcp_gee_sweet-0.7.0.dev80/.claude/commands/verify-pr.md +33 -0
  4. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/PKG-INFO +1 -1
  5. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/docs.md +18 -0
  6. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/roadmap.md +2 -0
  7. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/emitter.py +16 -9
  8. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_docs_tables.py +40 -0
  9. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.claude/commands/cleanup-worktrees.md +0 -0
  10. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.claude/commands/merge-pr.md +0 -0
  11. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.claude/commands/start-worktree.md +0 -0
  12. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.dockerignore +0 -0
  13. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  14. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  15. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  16. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/dependabot.yml +0 -0
  17. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/workflows/ci.yml +0 -0
  18. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/workflows/docs.yml +0 -0
  19. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/workflows/publish-dev.yml +0 -0
  20. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.github/workflows/release.yml +0 -0
  21. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.gitignore +0 -0
  22. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.pre-commit-config.yaml +0 -0
  23. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/.python-version +0 -0
  24. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/CHANGELOG.md +0 -0
  25. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/CLAUDE.md +0 -0
  26. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/CODE_OF_CONDUCT.md +0 -0
  27. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/CONTRIBUTING.md +0 -0
  28. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/Dockerfile +0 -0
  29. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/LICENSE +0 -0
  30. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/Makefile +0 -0
  31. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/README.md +0 -0
  32. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/SECURITY.md +0 -0
  33. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docker-compose.yml +0 -0
  34. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/auth.md +0 -0
  35. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/client-setup.md +0 -0
  36. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/configuration.md +0 -0
  37. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-chart-theming.md +0 -0
  38. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-composite-tools.md +0 -0
  39. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-docs-formatting.md +0 -0
  40. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-fork.md +0 -0
  41. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-grid-data-size-cap.md +0 -0
  42. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-publishing.md +0 -0
  43. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-response-size-cap-generalization.md +0 -0
  44. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/decision-testing.md +0 -0
  45. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/decisions/index.md +0 -0
  46. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/design/docs-ast-pipeline.md +0 -0
  47. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/design/effectiveformat-spike.md +0 -0
  48. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/design/index.md +0 -0
  49. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/design/markdown-support.md +0 -0
  50. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/design/phase3-theme-system.md +0 -0
  51. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/design.md +0 -0
  52. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/index.md +0 -0
  53. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/known-limitations.md +0 -0
  54. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/notes-read.md +0 -0
  55. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/README.md +0 -0
  56. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/fixtures/tc-d195-create-doc.md +0 -0
  57. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/fixtures/tc-d196-create-doc.html +0 -0
  58. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/fixtures/tc-d213-dollar-escape.md +0 -0
  59. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/fixtures/tc-d226-heading-table.md +0 -0
  60. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/fixtures.template.md +0 -0
  61. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/operations.yaml +0 -0
  62. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/playwright_oauth.md +0 -0
  63. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/.gitkeep +0 -0
  64. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-02.md +0 -0
  65. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-14.md +0 -0
  66. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-17.md +0 -0
  67. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-18.md +0 -0
  68. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-21-drive-discovery.md +0 -0
  69. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-21-sheets-delete-clear.md +0 -0
  70. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-06-28.md +0 -0
  71. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-07-04-docs.md +0 -0
  72. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-07-04-drive-smoke.md +0 -0
  73. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-07-04-infra.md +0 -0
  74. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-07-04-sheets_read.md +0 -0
  75. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/results/2026-07-04.md +0 -0
  76. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/retro-v0.8.0.md +0 -0
  77. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/run.md +0 -0
  78. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/runs/README.md +0 -0
  79. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/runs/v0.8.0.md +0 -0
  80. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/runs/v0.8.1.md +0 -0
  81. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/setup.md +0 -0
  82. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/calendar.md +0 -0
  83. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/drive.md +0 -0
  84. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/infra.md +0 -0
  85. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/sheets_charts.md +0 -0
  86. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/sheets_mgmt.md +0 -0
  87. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/sheets_read.md +0 -0
  88. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa/tests/sheets_write.md +0 -0
  89. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/qa-checklist.md +0 -0
  90. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/docs/tools.md +0 -0
  91. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/mkdocs.yml +0 -0
  92. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/pyproject.toml +0 -0
  93. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/pyrightconfig.json +0 -0
  94. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/scripts/gen_tool_docs.py +0 -0
  95. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/scripts/oauth_setup.py +0 -0
  96. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/.env.template +0 -0
  97. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/__init__.py +0 -0
  98. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/auth.py +0 -0
  99. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/cache.py +0 -0
  100. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/server.py +0 -0
  101. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/__init__.py +0 -0
  102. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/cache.py +0 -0
  103. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/calendar.py +0 -0
  104. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/__init__.py +0 -0
  105. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/ast.py +0 -0
  106. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/content.py +0 -0
  107. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/html_parser.py +0 -0
  108. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/layout.py +0 -0
  109. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/style.py +0 -0
  110. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/docs/tables.py +0 -0
  111. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/drive/__init__.py +0 -0
  112. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/drive/activity.py +0 -0
  113. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/drive/files.py +0 -0
  114. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/drive/sharing.py +0 -0
  115. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/drive/transfer.py +0 -0
  116. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/response_limits.py +0 -0
  117. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
  118. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/sheets/data.py +0 -0
  119. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/sheets/helpers.py +0 -0
  120. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/src/mcp_gee_sweet/tools/sheets/structure.py +0 -0
  121. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/__init__.py +0 -0
  122. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/drive/__init__.py +0 -0
  123. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/drive/test_activity.py +0 -0
  124. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/drive/test_files.py +0 -0
  125. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/drive/test_sharing.py +0 -0
  126. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/drive/test_transfer.py +0 -0
  127. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/sheets/__init__.py +0 -0
  128. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/sheets/test_data.py +0 -0
  129. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/sheets/test_helpers.py +0 -0
  130. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/sheets/test_structure.py +0 -0
  131. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_auth.py +0 -0
  132. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_cache.py +0 -0
  133. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_calendar.py +0 -0
  134. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_docs_content.py +0 -0
  135. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_docs_core.py +0 -0
  136. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_docs_layout.py +0 -0
  137. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_docs_style.py +0 -0
  138. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_gen_tool_docs.py +0 -0
  139. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_response_limits.py +0 -0
  140. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/tests/test_server.py +0 -0
  141. {mcp_gee_sweet-0.7.0.dev76 → mcp_gee_sweet-0.7.0.dev80}/uv.lock +0 -0
@@ -0,0 +1,20 @@
1
+ Establish this session as the **orchestrator** — the one session responsible for ticket triage, roadmap grooming, live testing, and reviewing/merging PRs, as opposed to a worker session doing ticket implementation in a worktree.
2
+
3
+ Why this role split exists: any locally-configured MCP server that runs this project via `uv run --directory <path>` (check your global MCP config for one pointing at this repo), plus the `mcp-gee-sweet` docker-compose service (bind-mounts `./src`), always serve whatever is checked out at that fixed path — the main checkout, not whichever worktree a session's shell happens to be in. A worktree's code is invisible to every live MCP tool call until it's checked out in the main checkout or merged to the default branch. So only one place can ever do meaningful live testing — the main checkout — and only one session should treat it as home base at a time.
4
+
5
+ 1. Confirm this session is running from the main checkout, not a `.claude/worktrees/*` path. If it's in a worktree, tell the user the orchestrator role requires the main checkout and ask whether to `ExitWorktree` (`keep`) first.
6
+ 2. Check `git branch --show-current` and `git status --short` on the main checkout:
7
+ - On `develop` and clean: ready.
8
+ - On a feature branch, or dirty: flag it. Ticket implementation shouldn't live in the main checkout under this model — it blocks freely checking out other branches to live-test them. Ask the user whether to move that work into its own worktree (`start-worktree`) or continue as-is for now.
9
+ 3. Report current state so the user can steer:
10
+ - `git worktree list` — active worker worktrees
11
+ - `gh pr list --state open` — PRs awaiting live-test/review/merge (run from inside the repo so `gh` infers it from the git remote — don't hardcode a repo slug, forks won't match)
12
+ - `gh issue list --label ready-for-development --state open` — queued ticket(s)
13
+ 4. State the orchestrator's responsibilities plainly:
14
+ - Ticket triage and labeling (`ready-for-development`, version labels)
15
+ - Roadmap grooming (`docs/roadmap.md` + whichever roadmap-planning memory is currently active — check the memory index rather than assuming a specific version-numbered file)
16
+ - Live/manual tool testing — only possible here
17
+ - Reviewing worker PRs: `verify-pr` (code review + scoped live QA against real Google APIs) before `merge-pr`
18
+ - Worktree cleanup after merge (`cleanup-worktrees`)
19
+
20
+ Do NOT pick up ticket implementation directly in this session — hand it to a worker session via `start-worktree` (or `next-issue`, which does this automatically).
@@ -8,8 +8,8 @@ Review the current branch against this checklist and report the status of each i
8
8
  - [ ] **Unit tests passing** — has `uv run python -m pytest tests/` been run and passed?
9
9
  - [ ] **Regression coverage** — were tests that touch the modified files (not just new tests) also run?
10
10
  - [ ] **QA test cases written** — are there AI-driven test cases in `docs/qa/tests/` for the new/changed tools?
11
- - [ ] **QA tests run** — have those test cases been executed live against the fixture doc?
12
- - [ ] **QA results recorded**does each test case have a `**Result (date) ✅/❌**` entry with actual observed output?
11
+
12
+ **Live QA execution is out of scope for this checklist.** If this session is a worker in a `.claude/worktrees/*` checkout, running live QA tools here would exercise the main checkout's code, not this branch's changes the result would look real but prove nothing. Do not run live tests and do not write `**Result**` entries from a worktree. That happens in the orchestrator's `/verify-pr` pass after the PR is open, in the main checkout, where the branch's actual code is reachable by the live MCP tools. Leave the `**Result**` line off new/changed test cases entirely — don't stub it as "pending," just omit it so `/verify-pr` adds the first real one.
13
13
 
14
14
  ## 2. QA test case tags
15
15
 
@@ -0,0 +1,33 @@
1
+ Verify an open worker PR before merging: code review plus live QA testing against real Google APIs. This only works from the orchestrator session in the main checkout — see `/orchestrator` for why (live MCP tools always serve the main checkout's code, never a worktree's).
2
+
3
+ CI (the "Lint and test" check `/merge-pr` already gates on) covers unit tests. It cannot cover code review judgment or live calls against real Google APIs, since those need credentials and fixtures CI doesn't have. That's what this skill does instead — it's the step between a worker's PR going up and `/merge-pr`.
4
+
5
+ 1. **Preconditions.** Confirm this session is in the main checkout, not a worktree (same check as `/orchestrator` step 1). If the main checkout has uncommitted changes, stop and ask the user how to proceed — don't stash or discard anything.
6
+
7
+ 2. **Identify the PR.** Take a PR number as an argument if given, otherwise use `gh pr list --state open` and ask the user which one if there's more than one. Get its details: `gh pr view <number> --json number,title,url,headRefName,baseRefName,statusCheckRollup`.
8
+
9
+ 3. **Check out the branch.** `gh pr checkout <number>`. This fetches and switches the main checkout to the PR's branch directly (no worktree needed — the orchestrator owns the main checkout).
10
+
11
+ 4. **Reconnect the MCP server.** The server hot-reloads on file change, but this Claude session's MCP connection stays on the old process. Tell the user to run:
12
+ ```
13
+ /mcp reconnect
14
+ ```
15
+ on its own line, standalone (not embedded in other text). Wait for confirmation before continuing — live tests run against stale code otherwise.
16
+
17
+ 5. **Code review.** Run `/code-review` at `high` effort against the diff (`<baseRefName>...<headRefName>`, typically `develop...HEAD`). Report findings before moving on to live testing — if it surfaces a correctness bug, ask the user whether to still proceed with live QA or send the PR back to the worker first.
18
+
19
+ 6. **Scope the live QA run.** Don't run the full suite. Find what this PR actually touches:
20
+ - `git diff origin/<baseRefName>...HEAD --name-only -- docs/qa/tests/` — new or modified test case files.
21
+ - Within those, identify test cases that are new or whose `Prompt`/`Setup`/`Checks` changed (not ones only touched by unrelated reflow). These are mandatory.
22
+ - Cross-check against `git diff origin/<baseRefName>...HEAD --name-only -- src/mcp_gee_sweet/tools/` — for each changed tool, confirm there's at least one QA test case covering it in scope; if a changed tool has no corresponding test case at all, flag that as a gap rather than silently skipping it.
23
+ - Existing passing test cases for the same tool (regression) are optional spot-checks, not mandatory re-runs — full regression is `docs/qa/run.md`'s job, run periodically, not per-PR.
24
+
25
+ 7. **Run the scoped test cases live.** Follow each test case's `Prompt`/`Setup` against the fixtures in `docs/qa/.env` (see `docs/qa/setup.md` if fixtures aren't configured), using the now-reconnected MCP tools. For `**Playwright: required**` cases, use the connected Playwright MCP if available; if not connected, tell the user and ask whether to proceed without visual verification or connect it first.
26
+
27
+ 8. **Record results honestly.** For each test case actually executed, add `**Result (<date>) ✅ PASS**` or `**Result (<date>) ❌ FAIL — <what happened>**` directly below its `Checks` block. Never write a Result for a case you didn't actually invoke — if something blocks a case (fixture missing, tool errors before completing), write `**Result (<date>)** pending — <reason>` and say so plainly rather than guessing the outcome.
28
+
29
+ 9. **Commit and push the results.** If any Result entries were added, commit just those QA doc changes onto the PR branch (`qa: record live verification for PR #<number>`) and push, so the evidence lands in history before merge. Ask before pushing, per this repo's normal commit/push confirmation rule.
30
+
31
+ 10. **Report.** Summarize: code review findings (if any), which test cases passed/failed/pending, any coverage gaps found in step 6, and whether the branch looks ready to merge. If everything passed, say the next step is `/merge-pr`. If something failed, say the PR needs to go back to its worker session — don't attempt the fix yourself here; this session's job is verification, not implementation.
32
+
33
+ Leave the branch checked out either way — `/merge-pr` operates on the current branch's PR, and if it needs rework, the worker's own worktree still has the branch open there too.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-gee-sweet
3
- Version: 0.7.0.dev76
3
+ Version: 0.7.0.dev80
4
4
  Summary: MCP server for Google Workspace — Sheets, Drive, Docs, and Calendar. 60+ tools for AI clients.
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
@@ -1020,6 +1020,24 @@ These test the HTML→AST→Docs API pipeline introduced in Phase 2 (#87). All u
1020
1020
 
1021
1021
  ---
1022
1022
 
1023
+ ### TC-DOC89: Degenerate table (row with no cells) followed by a real table doesn't desync content (issue #277)
1024
+
1025
+ **Background:** `ast_to_requests` skips emitting an `insertTable` request for a table with zero rows or zero columns (e.g. a `<tr>` with no `<td>`s), but was still counting that table in the list it hands to `fill_tables()`. Since `fill_tables()` pairs AST tables against live-doc tables positionally, a skipped table shifted every later table's fill/merge/style requests onto the wrong doc table — silently, with no error. Fixed by excluding degenerate tables from that list at the source.
1026
+
1027
+ **Prompt**
1028
+ > "Write this HTML to doc {DOC_ID}: `<table><tr></tr></table><table><tr><td>A</td><td>B</td></tr></table>`"
1029
+
1030
+ **Checks**
1031
+ - Call succeeds with no API error
1032
+ - `get_doc_structure` shows exactly **one** table in the doc (the empty-row table produces no table element at all)
1033
+ - That table is `columns: 2` with cell [0,0] text "A" and cell [0,1] text "B" — not empty, not misapplied, not offset onto the wrong table
1034
+
1035
+ **Cleanup:** write fixture content back
1036
+
1037
+ **Result (2026-07-09) ✅ PASS**
1038
+
1039
+ ---
1040
+
1023
1041
  ### TC-DOC52: `get_doc_theme` scans body paragraph styles
1024
1042
  **Note:** `get_doc_theme` reads explicit per-paragraph and per-run styles from the document body. It returns data for AI-generated docs (where styles are set explicitly on runs); for standard docs whose styles are fully inherited from named style defaults it returns an empty dict.
1025
1043
 
@@ -96,6 +96,7 @@ No new tools. Stabilize on what Tier 1 shipped before starting Tier 2 feature wo
96
96
 
97
97
  **Defects** _(found after v0.8.1 shipped; too late for that release, don't warrant a standalone patch)_
98
98
  - [ ] Bare URLs in markdown content aren't autolinked — Python-Markdown's built-in autolink only fires on `<https://...>` or `[text](url)`, not a bare URL ([#248](https://github.com/khuisman/mcp-gee-sweet/issues/248))
99
+ - [ ] `zip(doc_tables, ast_tables)` in `emitter.py` silently cross-pairs tables when one is skipped (zero-row/zero-col table), misapplying fill/merge/style requests to the wrong table — surfaced during #276's review ([#277](https://github.com/khuisman/mcp-gee-sweet/issues/277))
99
100
 
100
101
  **Sheets**
101
102
  - [ ] `update_borders` — border style, width, color on a range ([#122](https://github.com/khuisman/mcp-gee-sweet/issues/122)) _(freema/mcp-gsheets)_
@@ -130,6 +131,7 @@ No new tools. Stabilize on what Tier 1 shipped before starting Tier 2 feature wo
130
131
  - [ ] `create_shortcut` — create a Drive shortcut to a file ([#141](https://github.com/khuisman/mcp-gee-sweet/issues/141))
131
132
  - [ ] `sync_folder` — option to convert markdown files to Google Docs on upload ([#211](https://github.com/khuisman/mcp-gee-sweet/issues/211))
132
133
  - [ ] `upload_local_file` with Drive format conversion (CSV→Sheets, MD→Docs) ([#188](https://github.com/khuisman/mcp-gee-sweet/issues/188))
134
+ - [ ] Expose `md5Checksum` in `list_files`/`get_file_metadata` for real content-diffing, and let `sync_folder` diff by checksum instead of/in addition to `modifiedTime` — mtime is unreliable across in-place overwrites, `upload_local_file`'s "now" stamp, and content-preserving regenerations; related to #239 ([#274](https://github.com/khuisman/mcp-gee-sweet/issues/274))
133
135
  - [x] Drive Activity API — file change history ([#72](https://github.com/khuisman/mcp-gee-sweet/issues/72))
134
136
 
135
137
  **Infrastructure**
@@ -28,6 +28,14 @@ def ast_to_requests(nodes: list[DocNode], start_index: int = 1) -> tuple[list[di
28
28
 
29
29
  for node in nodes:
30
30
  if isinstance(node, Table):
31
+ num_rows = len(node.rows)
32
+ num_cols = max((sum(c.colspan for c in row.cells) for row in node.rows), default=0)
33
+ if num_rows == 0 or num_cols == 0:
34
+ # No insertTable request is emitted below for a degenerate table, so it must
35
+ # not be added to `tables` either — fill_tables() zips this list positionally
36
+ # against the tables actually present in the live doc, and a table with no
37
+ # insertTable request never shows up there.
38
+ continue
31
39
  tables.append(node)
32
40
  table_positions.append(start_index + len(full_text))
33
41
  else:
@@ -105,16 +113,15 @@ def ast_to_requests(nodes: list[DocNode], start_index: int = 1) -> tuple[list[di
105
113
  table = tables[i]
106
114
  num_rows = len(table.rows)
107
115
  num_cols = max((sum(c.colspan for c in row.cells) for row in table.rows), default=0)
108
- if num_rows > 0 and num_cols > 0:
109
- requests.append(
110
- {
111
- "insertTable": {
112
- "rows": num_rows,
113
- "columns": num_cols,
114
- "location": {"index": table_positions[i]},
115
- }
116
+ requests.append(
117
+ {
118
+ "insertTable": {
119
+ "rows": num_rows,
120
+ "columns": num_cols,
121
+ "location": {"index": table_positions[i]},
116
122
  }
117
- )
123
+ }
124
+ )
118
125
 
119
126
  return requests, tables
120
127
 
@@ -12,10 +12,12 @@ from mcp_gee_sweet.tools.docs.ast import (
12
12
  from mcp_gee_sweet.tools.docs.content import _html_to_doc_requests
13
13
  from mcp_gee_sweet.tools.docs.emitter import (
14
14
  _ast_cell_to_doc_cell,
15
+ _build_fill_requests,
15
16
  _cell_para_start_for_cursor,
16
17
  _fill_nested_cell_content,
17
18
  _find_nth_table_in_cell,
18
19
  _text_offset_since_last_table,
20
+ ast_to_requests,
19
21
  )
20
22
  from mcp_gee_sweet.tools.docs.html_parser import html_to_ast
21
23
 
@@ -719,3 +721,41 @@ class TestFillNestedCellContent:
719
721
  degenerate = Table(rows=[Row(cells=[])])
720
722
  doc = self._run(Cell(children=[degenerate, Run("After")]))
721
723
  assert doc.describe_cell(0, 0, 0) == ["Para:After"]
724
+
725
+
726
+ # ---------------------------------------------------------------------------
727
+ # #277 — a skipped degenerate table must not desync doc_tables/ast_tables
728
+ # ---------------------------------------------------------------------------
729
+
730
+
731
+ class TestSkippedTableDoesNotDesyncTablePairing:
732
+ def test_empty_row_table_excluded_from_ast_to_requests_tables(self):
733
+ # A top-level <table><tr></tr></table> has a row but zero cells, so num_cols == 0
734
+ # and no insertTable request is emitted for it. It must not appear in the returned
735
+ # `tables` list either, or the table after it desyncs from doc_tables in fill_tables().
736
+ empty_table = _table(_row())
737
+ normal_table = _table(_row(_cell("hello")))
738
+ requests, tables = ast_to_requests([empty_table, normal_table])
739
+
740
+ table_inserts = [r for r in requests if "insertTable" in r]
741
+ assert len(table_inserts) == 1
742
+ assert tables == [normal_table]
743
+
744
+ def test_fill_requests_land_on_correct_table_after_a_skip(self):
745
+ # Simulates fill_tables(): doc_tables comes from the live doc, which only ever
746
+ # contains tables that actually got an insertTable request — i.e. never the
747
+ # skipped empty-row table. ast_tables must be the same (already-filtered) list
748
+ # returned by ast_to_requests, so the zip() stays 1:1.
749
+ empty_table = _table(_row())
750
+ normal_table = _table(_row(_cell("hello")))
751
+ _, tables = ast_to_requests([empty_table, normal_table])
752
+
753
+ doc_table = {
754
+ "tableRows": [{"tableCells": [{"startIndex": 9, "content": [{"startIndex": 10}]}]}]
755
+ }
756
+ fill_requests = _build_fill_requests([doc_table], tables)
757
+
758
+ insert_texts = [r["insertText"] for r in fill_requests if "insertText" in r]
759
+ assert len(insert_texts) == 1
760
+ assert insert_texts[0]["text"] == "hello"
761
+ assert insert_texts[0]["location"]["index"] == 10