From 3925ba5ec3f3ca166d6c045f8a346321e256dbf3 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 19:06:50 -0700 Subject: [PATCH 1/4] docs(plans): matrix rows and a staging-walk fill-in for Atlassian writes and Sentry (TASK-270) Adds rows for Atlassian writes (#2328) and Sentry (#2329) to the readiness matrix, and a fill-in for their planned staging walk: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. Each cell names what the walk checks and reads unverified. C4 is refused by design until TASK-213. A staging green keeps its own mark until the same check passes on commonly.me. The walk records which of #2328, #2329, #2397, #2378 and #2178 its build carries. The Hosted MCP row's cannot-write bar is conformed to the 2026-10-19 amendment of the scope doc. Co-Authored-By: Claude Opus 5.5 Co-authored-by: wren Agent-Model: claude/claude-opus-5-5/max --- docs/plans/integration-readiness-matrix.md | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/plans/integration-readiness-matrix.md b/docs/plans/integration-readiness-matrix.md index 2da71be669..346e8e2548 100644 --- a/docs/plans/integration-readiness-matrix.md +++ b/docs/plans/integration-readiness-matrix.md @@ -53,9 +53,11 @@ The matrix below is the definition of "ready". A row is ready when every cell is | GroupMe | yes | **red**: TASK-101 | | X | yes (admin OAuth callback + feed) | unverified | | GitHub (app) | yes | Walked 2026-09-25 and re-walked 2026-09-26 on `5561a1dd` (both below). Live on our own repository since 09-18. **red** in C1 until per-person GitHub: a team cannot connect its own repository. C2 at 390 is green since #1874, shown on `5561a1dd`. C3 (a hosted agent gets the broker, #1880) shipped and has not been walked. C8 was green on `9a32fca5`. A new grant from the connection's owner, `grant_3c4d6ad5` (2026-09-29, on Sam's approval), has the same scope as the lapsed 09-18 one: pod "C4 run 2026-09-18"; `list_issues`, `create_issue` and `close_issue`; write-with-confirm; audience Sam, `c3stranger0912` and `c4-smoke`. It runs to 2026-10-06, so C3, C4 and C8 are walkable again. None has been walked on the current build | -| Hosted MCP (generic type, TASK-172) | yes | **Built and live, with one follow-up open.** Steps 1–6 of `hosted-mcp-connection-scope.md` §10, and step 8's prerequisites (the client record, expand phase, and the pre-registered client; #2063), are live. **Open:** the reconnect withdrawal #2069 added to step 3 (withdraw the old account's token at the vendor before dropping our copy) is not built yet, and `hostedMcpConnect.ts:406–420` does not do it. The bar every entry must meet (Wren 76043): a credential that cannot write. Notion, Sentry and Stripe wait for a vendor read scope. Entries are offered one by one; the rows below walk them | +| Hosted MCP (generic type, TASK-172) | yes | **Built and live, with one follow-up open.** Steps 1–6 of `hosted-mcp-connection-scope.md` §10, and step 8's prerequisites (the client record, expand phase, and the pre-registered client; #2063), are live. **Open:** the reconnect withdrawal #2069 added to step 3 (withdraw the old account's token at the vendor before dropping our copy) is not built yet, and `hostedMcpConnect.ts:406–420` does not do it. Since 2026-10-19 an entry's credential may write: a tool that writes is pinned `write`, and each call parks for the connection's owner with its exact arguments (`hosted-mcp-connection-scope.md` §3 and §5). That lifted Wren 76043's bar, that every entry's credential be unable to write. Entries are offered one by one; the rows below walk them | | Linear (hosted MCP) | yes | **Fresh-account walk 2026-10-15 on `cfe91c21`, green** (connector-ops 77850 and 77962; the build is Deploy Dev's last run before the walk): a new commonly.me account and a new Linear workspace, neither connected before. **C1 green**: connected through the Connectors page. Linear's consent read "Read, Identity", the authorize request asked for `read openid`, and the token response granted `read openid` (`config.grantedScope`). **C3 green in an eligible pod**: a read grant of the 36 pinned tools, made through the grant panel, which offers only Read, in the account's own My Workspace. That pod is private and invite-only, with no bridge and Scout as its only agent, so it passes §12's pod rule in `hosted-mcp-connection-scope.md` (#2211). Scout listed the workspace's one team through the grant, the trail records the call ok, and Scout quoted #2206's untrusted-content marker ahead of the data. #2211 deployed after the walk, and the same call was ok again after it, at 16:22:37Z. The earlier C3 and C4 walks ran in the C4 run pod, which fails that rule: since `ff909fb3` the deployed rule returns `pod_joinable` for both of its grants. Partly walked live 2026-10-01 (Sam's account, Chrome). Before the fresh-account walk, C1 was open: Sam's own operator-led connect succeeded on `cf9b6abf`, through CIMD with scope `read openid`, and the row records its client and the Linear subject. That didn't prove a stranger connects unaided, and no stranger had tried. **C2 green at 1440, the rest unwalked**: in the fresh-account walk the grant panel offered only Read. Earlier, on `cf9b6abf` the grant rendered as GitHub, because the catalogue projected 0 Linear tools. #2068 (`207c68d5`) fixed it, and on the deployed `e370fe9b` (its descendant) the row reads Linear, with its mark and the read eye, at 1200. 390, a failure reaching Activity, and revoke reachability are unwalked. Earlier, C3 was green in the C4 run pod: Scout listed the team and three issues through `grant_c6af31b8`; the trail showed the calls ok, with Sam as credential owner. **C4 refused by design** from #2211 (the C4 column), and c4-smoke is now offered no Linear tool. Before that it was green (2026-10-09): c4-smoke, a public local claude seat confined by Seatbelt, called `linear.list_teams` through its broker on `grant_e3a1507b` at 06:12:57Z, and the trail shows it ok. Its daemon started at 06:11:59Z, after global cli 0.1.84 (npm latest) was installed at 06:11:41Z, so it runs the current build. An earlier run on 2026-09-27 didn't count, because that daemon predated the cli it should have been running. The same spawn showed that TASK-228's headers helper works under the public Seatbelt profile. A by-name scan of the spawn's claude process found `COMMONLY_TOKEN_FILE` set and `COMMONLY_AGENT_TOKEN` absent. The rest of #2067's consumer proof is unmeasured: the child processes' environments, and a credential rotation followed by a 401 retry succeeding. **C8 open**: in a pod with no grant, Scout is offered no `linear.*` tools. That's confinement by projection. An attempted out-of-pod call, refused and recorded in the trail, hasn't been made. **C9 open**, now only for whether a revoke takes effect at Linear. Linear's revoke is page-only. The fresh-account walk reached the page: `https://linear.app/settings/account/security`, whose Authorized applications list shows the connection as "MCP · Read · Revoke". #2230 points the entry's page there. Before #2230 the entry named `https://linear.app/settings/security`, which is Linear's workspace admin page. Before that walk, every linear.app settings URL redirected to the old workspace's unfinished welcome flow, so the page had not been reached. C5, C6, C7 and C10 are unwalked | | Google Calendar (hosted MCP) | yes | **Built, live, not offered.** #2066 (`e370fe9b`) pins the 5 read tools from Google's unauthenticated `tools/list`, with a pre-registered client and `openid` for the account subject. "Not offered" is a **config fact, not a code fact**. The client values arrived on 2026-10-09 (#2111), and the tile was offered until 2026-10-14. OAuth worked, but every tool call failed Google's Developer Preview gate, which is **per Cloud project** (Google named the project in its error on the 2026-10-09 gate test). Since 2026-10-14 `hostedMcp.googleCalendar.enabled` is `false` in values-dev (Wren's ruling), so the instance holds no client values, the catalogue reports `available: false`, and the page shows "not enabled on this instance" with no Connect. Flip the flag once the project is enrolled and an enrolled `list_calendars` call succeeds. Waiting on Sam: a Workspace seat on the domain and Developer Preview enrollment for the connectors project. The OAuth client already exists in a project of its own (Wren: a revoke withdraws every scope a person granted the project) | +| Atlassian (hosted MCP), writes in #2328 | reads yes; writes in draft #2328 | **Reads live; writes in draft, walk on staging planned.** The entry on main pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call and is merged; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments. The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect. Its merge waits on TASK-247 (#2378). **C4 refused by design** (the C4 column). The staging walk's fill-in is below | +| Sentry (hosted MCP), #2329 | in draft #2329 | **Draft entry, not on main; walk on staging planned.** #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. Its merge waits on TASK-247 (#2378). **C4 refused by design** (the C4 column). The staging walk's fill-in is below | | next app | no | Sam's decision; see below | ## Staging connector walk — 2026-10-23 on `876870378` @@ -155,6 +157,46 @@ The test gate on "Scout (Default)" was switched back off after the walk. On Sam' **Membership, hardened across every connector write path (2026-09-27).** A connector now writes only where its owner is a listed pod member, the same rule `createMessage` uses (`isListedPodMember`): relay, inbound, the gate PATCH, install, bind confirm and the gate reconciler (#1940, TASK-161). A pod's creator cannot leave it (#1945, TASK-166), so `createdBy` no longer stands in for membership; the Discord/Slack owner routes follow (#1946, TASK-168); `agent-admin` pods are not a gate target (#1954, TASK-171); the PG chat path reads Mongo membership rather than its own mirror (#1942, TASK-162); and a seat whose own declaration cannot confine a broker is refused at the broker call — every dispatch except the native runtime's in-process one, which is exempt because a hosted turn has no shell, web or file tool to confine (#1971, TASK-175, ruled by Wren). This bears on C9 (authority is bounded) for every channel row above. +## Staging walk: Atlassian writes and Sentry (planned 2026-10-23) + +A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the two draft entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. Each result reads `unverified` until the walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. + +**A staging green is not a commonly.me green.** Ready means green on commonly.me against the deployed build, so a cell that passes here is recorded as green on staging. Like "green to the external boundary", it keeps that mark when it is copied into the rows above, and it turns green when the same check passes on commonly.me (Method rule 5). + +**Record the build.** Note the staging commit and which of these it carries. A cell whose check needs a missing one is `unverified` on that build, not red: + +- #2328 and #2329, the entries walked; +- #2397, which opens an MCP session for each list and call (merged); without it every Atlassian call fails (TASK-263); +- #2378 (TASK-247), so a parked call runs only under the pin it parked under; +- #2178 (TASK-210), so the seat learns how a parked call ended. On main nothing reaches the seat after a park, because the approval wake leaves parked calls out (`approvalActionService.ts:836`). + +**C6 for a hosted write.** This type has no inbound path, so no card is answered from the vendor. Here C6 reads as the parked call's card: the connection's owner answers it in Commonly, and the seat receives the ending as `approval.resolved`. + +**The walk's grants need an eligible pod.** Every source counts as outsider-writable today, and the mint applies §12's pod rule in `hosted-mcp-connection-scope.md` to every grant (`routes/grants.ts:389`, #2211). So each grant is a pod grant, in a pod that is private, invite-only and unbridged, with every agent in it running inside the backend. For an entry with a write tool, the grant panel offers `read` and "read and write, ask first" (`write-with-confirm`), never unattended `write` (`V2ConnectorTools.tsx:369`). + +**Atlassian writes (#2328).** + +| cell | what the walk checks | result | +|---|---|---| +| C1 | The site's admin first allows the instance's API origin under MCP server domains, as the entry's connect notice asks. A fresh connect then shows Atlassian's consent for the Jira and Confluence write scopes, and the row's `config.grantedScope` holds them. A row connected before #2328 holds no write scope; record whether the page tells its owner to reconnect, and whether a reconnect gains write | unverified | +| C3 | In an eligible pod, a hosted agent calls a writer through a `write-with-confirm` pod grant, such as `create_jira_issue`. The call parks, and the card shows the connection's owner its exact arguments. Once approved it runs once, the trail records it ok, and the issue is there when read in Jira | unverified | +| C6 | The owner approves one parked write and declines another. The seat receives each ending once as `approval.resolved`, and the trail records each ending under its card's `approvalId`. An expiry takes 24 hours; record it if the walk spans one | unverified | +| C8 | The grant's tools are offered in its pod and not in a second pod the same agent is in. A call against the grant from outside its pod or audience is refused with its code and recorded in the trail | unverified | +| C9 | Bounded: only the five writers are offered, never the vendor's `createConfluenceContent`; a `read` grant refuses a writer; the mint refuses plain `write` with `write_requires_confirm`; the comment tool is marked irreversible. Revocable: a write approved after its grant is revoked or has expired is refused with its code, and the seat learns that code. After a revoke on the Connectors page, record whether the connection has left Atlassian's connected apps page, the entry's revoke page. Rotation: if the walk outlasts the access token, a later call succeeds through a refresh | unverified | +| C4 | Refused by design until TASK-213 | refused by design | + +**Sentry (#2329).** + +| cell | what the walk checks | result | +|---|---|---| +| C0 | A stranger sees the Sentry row on the Connectors page at 1200 and 390, and the catalogue API lists `sentry` with its tools (Method rule 4) | unverified | +| C1 | A stranger connects without an operator, through the CIMD client. At Sentry's consent, select the Triage Issues skill, as #2329 asks. The authorization then appears on Sentry's Authorized Applications page, and the row's `config.grantedScope` records what Sentry granted | unverified | +| C2 | The page shows the row connected. A failed call lands as an Activity row that names the failure. Revoke is reachable at 390 | unverified | +| C3 | In an eligible pod, a hosted agent completes a read through a pod grant, such as `find_projects`. The trail records it ok, and the answer matches what Sentry's own pages show | unverified | +| C6 | Through a `write-with-confirm` grant, `update_issue` parks, and the card shows the owner its exact arguments. The owner approves one call and declines another. Only the approved one changes the issue in Sentry, and the seat receives each ending once as `approval.resolved` | unverified | +| C9 | Bounded: the 12 pinned tools are the only ones offered, without the dispatcher, its catalogue or Seer, and `get_sentry_resource` is offered without a `url` argument. Revocable: a write approved after its grant is revoked or has expired is refused with its code. After a revoke on the Connectors page, record whether the authorization has left Sentry's Authorized Applications page | unverified | +| C4 | Refused by design until TASK-213 | refused by design | + ## Cross-cutting reds | red | state | From 02fb942cdf6c508545884d5af29e56bc1996a9b5 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 20:13:12 -0700 Subject: [PATCH 2/4] docs(plans): conform the TASK-270 fill-in to main 4bc63222 #2328, #2329, #2378 and #2178 merged on 2026-10-23, so the two rows no longer read as drafts waiting on TASK-247, and the build record names main 4bc63222 as a commit that carries everything the walk needs. C6 now names the endings #2178 delivers to the seat (ran, failed, refused, declined, expired) and the approved call's receipt in the pod. C9's revoke check follows the code: a revoke leaves parked cards open, and an approval afterwards is refused at run with grant_revoked. An unanswered card expires at the earlier of 24 hours and its grant's end, and the panel's shortest grant is 7 days. The grant-panel cite moves to V2ConnectorTools.tsx:382. Co-Authored-By: Claude Opus 5.5 Co-authored-by: wren Agent-Model: claude/claude-opus-5-5/max --- docs/plans/integration-readiness-matrix.md | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/plans/integration-readiness-matrix.md b/docs/plans/integration-readiness-matrix.md index 346e8e2548..fc251dc1a0 100644 --- a/docs/plans/integration-readiness-matrix.md +++ b/docs/plans/integration-readiness-matrix.md @@ -56,8 +56,8 @@ The matrix below is the definition of "ready". A row is ready when every cell is | Hosted MCP (generic type, TASK-172) | yes | **Built and live, with one follow-up open.** Steps 1–6 of `hosted-mcp-connection-scope.md` §10, and step 8's prerequisites (the client record, expand phase, and the pre-registered client; #2063), are live. **Open:** the reconnect withdrawal #2069 added to step 3 (withdraw the old account's token at the vendor before dropping our copy) is not built yet, and `hostedMcpConnect.ts:406–420` does not do it. Since 2026-10-19 an entry's credential may write: a tool that writes is pinned `write`, and each call parks for the connection's owner with its exact arguments (`hosted-mcp-connection-scope.md` §3 and §5). That lifted Wren 76043's bar, that every entry's credential be unable to write. Entries are offered one by one; the rows below walk them | | Linear (hosted MCP) | yes | **Fresh-account walk 2026-10-15 on `cfe91c21`, green** (connector-ops 77850 and 77962; the build is Deploy Dev's last run before the walk): a new commonly.me account and a new Linear workspace, neither connected before. **C1 green**: connected through the Connectors page. Linear's consent read "Read, Identity", the authorize request asked for `read openid`, and the token response granted `read openid` (`config.grantedScope`). **C3 green in an eligible pod**: a read grant of the 36 pinned tools, made through the grant panel, which offers only Read, in the account's own My Workspace. That pod is private and invite-only, with no bridge and Scout as its only agent, so it passes §12's pod rule in `hosted-mcp-connection-scope.md` (#2211). Scout listed the workspace's one team through the grant, the trail records the call ok, and Scout quoted #2206's untrusted-content marker ahead of the data. #2211 deployed after the walk, and the same call was ok again after it, at 16:22:37Z. The earlier C3 and C4 walks ran in the C4 run pod, which fails that rule: since `ff909fb3` the deployed rule returns `pod_joinable` for both of its grants. Partly walked live 2026-10-01 (Sam's account, Chrome). Before the fresh-account walk, C1 was open: Sam's own operator-led connect succeeded on `cf9b6abf`, through CIMD with scope `read openid`, and the row records its client and the Linear subject. That didn't prove a stranger connects unaided, and no stranger had tried. **C2 green at 1440, the rest unwalked**: in the fresh-account walk the grant panel offered only Read. Earlier, on `cf9b6abf` the grant rendered as GitHub, because the catalogue projected 0 Linear tools. #2068 (`207c68d5`) fixed it, and on the deployed `e370fe9b` (its descendant) the row reads Linear, with its mark and the read eye, at 1200. 390, a failure reaching Activity, and revoke reachability are unwalked. Earlier, C3 was green in the C4 run pod: Scout listed the team and three issues through `grant_c6af31b8`; the trail showed the calls ok, with Sam as credential owner. **C4 refused by design** from #2211 (the C4 column), and c4-smoke is now offered no Linear tool. Before that it was green (2026-10-09): c4-smoke, a public local claude seat confined by Seatbelt, called `linear.list_teams` through its broker on `grant_e3a1507b` at 06:12:57Z, and the trail shows it ok. Its daemon started at 06:11:59Z, after global cli 0.1.84 (npm latest) was installed at 06:11:41Z, so it runs the current build. An earlier run on 2026-09-27 didn't count, because that daemon predated the cli it should have been running. The same spawn showed that TASK-228's headers helper works under the public Seatbelt profile. A by-name scan of the spawn's claude process found `COMMONLY_TOKEN_FILE` set and `COMMONLY_AGENT_TOKEN` absent. The rest of #2067's consumer proof is unmeasured: the child processes' environments, and a credential rotation followed by a 401 retry succeeding. **C8 open**: in a pod with no grant, Scout is offered no `linear.*` tools. That's confinement by projection. An attempted out-of-pod call, refused and recorded in the trail, hasn't been made. **C9 open**, now only for whether a revoke takes effect at Linear. Linear's revoke is page-only. The fresh-account walk reached the page: `https://linear.app/settings/account/security`, whose Authorized applications list shows the connection as "MCP · Read · Revoke". #2230 points the entry's page there. Before #2230 the entry named `https://linear.app/settings/security`, which is Linear's workspace admin page. Before that walk, every linear.app settings URL redirected to the old workspace's unfinished welcome flow, so the page had not been reached. C5, C6, C7 and C10 are unwalked | | Google Calendar (hosted MCP) | yes | **Built, live, not offered.** #2066 (`e370fe9b`) pins the 5 read tools from Google's unauthenticated `tools/list`, with a pre-registered client and `openid` for the account subject. "Not offered" is a **config fact, not a code fact**. The client values arrived on 2026-10-09 (#2111), and the tile was offered until 2026-10-14. OAuth worked, but every tool call failed Google's Developer Preview gate, which is **per Cloud project** (Google named the project in its error on the 2026-10-09 gate test). Since 2026-10-14 `hostedMcp.googleCalendar.enabled` is `false` in values-dev (Wren's ruling), so the instance holds no client values, the catalogue reports `available: false`, and the page shows "not enabled on this instance" with no Connect. Flip the flag once the project is enrolled and an enrolled `list_calendars` call succeeds. Waiting on Sam: a Workspace seat on the domain and Developer Preview enrollment for the connectors project. The OAuth client already exists in a project of its own (Wren: a revoke withdraws every scope a person granted the project) | -| Atlassian (hosted MCP), writes in #2328 | reads yes; writes in draft #2328 | **Reads live; writes in draft, walk on staging planned.** The entry on main pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call and is merged; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments. The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect. Its merge waits on TASK-247 (#2378). **C4 refused by design** (the C4 column). The staging walk's fill-in is below | -| Sentry (hosted MCP), #2329 | in draft #2329 | **Draft entry, not on main; walk on staging planned.** #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. Its merge waits on TASK-247 (#2378). **C4 refused by design** (the C4 column). The staging walk's fill-in is below | +| Atlassian (hosted MCP), writes in #2328 | yes (writes since #2328) | **Reads live; writes merged 2026-10-23, live once a deploy carries them; walk on staging planned.** The entry pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments, and runs only under the definition it parked under (#2378). The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect. **C4 refused by design** (the C4 column). The staging walk's fill-in is below | +| Sentry (hosted MCP), #2329 | yes (#2329) | **Merged 2026-10-23, offered once a deploy carries it; walk on staging planned.** #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. **C4 refused by design** (the C4 column). The staging walk's fill-in is below | | next app | no | Sam's decision; see below | ## Staging connector walk — 2026-10-23 on `876870378` @@ -159,20 +159,20 @@ The test gate on "Scout (Default)" was switched back off after the walk. On Sam' ## Staging walk: Atlassian writes and Sentry (planned 2026-10-23) -A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the two draft entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. Each result reads `unverified` until the walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. +A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the two entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. Each result reads `unverified` until the walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. **A staging green is not a commonly.me green.** Ready means green on commonly.me against the deployed build, so a cell that passes here is recorded as green on staging. Like "green to the external boundary", it keeps that mark when it is copied into the rows above, and it turns green when the same check passes on commonly.me (Method rule 5). -**Record the build.** Note the staging commit and which of these it carries. A cell whose check needs a missing one is `unverified` on that build, not red: +**Record the build.** Note the staging commit. Everything the walk depends on is on `main` by `4bc63222`, so a build from that commit or later carries all of it. A cell whose check needs a change the build lacks is `unverified` on that build, not red: - #2328 and #2329, the entries walked; -- #2397, which opens an MCP session for each list and call (merged); without it every Atlassian call fails (TASK-263); -- #2378 (TASK-247), so a parked call runs only under the pin it parked under; -- #2178 (TASK-210), so the seat learns how a parked call ended. On main nothing reaches the seat after a park, because the approval wake leaves parked calls out (`approvalActionService.ts:836`). +- #2397, which opens an MCP session for each list and call; without it every Atlassian call fails (TASK-263); +- #2378 (TASK-247), so a parked call runs only under the definition it parked under. A mismatch is refused with `definition_digest_mismatch`, which the walk cannot provoke against a vendor it does not control; +- #2178 (TASK-210), so the seat learns how a parked call ended. -**C6 for a hosted write.** This type has no inbound path, so no card is answered from the vendor. Here C6 reads as the parked call's card: the connection's owner answers it in Commonly, and the seat receives the ending as `approval.resolved`. +**C6 for a hosted write.** This type has no inbound path, so no card is answered from the vendor. Here C6 reads as the parked call's card: the connection's owner answers it in Commonly, and the seat receives the ending as `approval.resolved`: `ran`, `failed`, `refused`, `declined` or `expired`, with its code when it has one. An approved call also posts a receipt in the pod that names the approver, the agent, the tool and the ending. -**The walk's grants need an eligible pod.** Every source counts as outsider-writable today, and the mint applies §12's pod rule in `hosted-mcp-connection-scope.md` to every grant (`routes/grants.ts:389`, #2211). So each grant is a pod grant, in a pod that is private, invite-only and unbridged, with every agent in it running inside the backend. For an entry with a write tool, the grant panel offers `read` and "read and write, ask first" (`write-with-confirm`), never unattended `write` (`V2ConnectorTools.tsx:369`). +**The walk's grants need an eligible pod.** Every source counts as outsider-writable today, and the mint applies §12's pod rule in `hosted-mcp-connection-scope.md` to every grant (`routes/grants.ts:389`, #2211). So each grant is a pod grant, in a pod that is private, invite-only and unbridged, with every agent in it running inside the backend. For an entry with a write tool, the grant panel offers `read` and "read and write, ask first" (`write-with-confirm`), never unattended `write` (`V2ConnectorTools.tsx:382`). **Atlassian writes (#2328).** @@ -180,9 +180,9 @@ A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the |---|---|---| | C1 | The site's admin first allows the instance's API origin under MCP server domains, as the entry's connect notice asks. A fresh connect then shows Atlassian's consent for the Jira and Confluence write scopes, and the row's `config.grantedScope` holds them. A row connected before #2328 holds no write scope; record whether the page tells its owner to reconnect, and whether a reconnect gains write | unverified | | C3 | In an eligible pod, a hosted agent calls a writer through a `write-with-confirm` pod grant, such as `create_jira_issue`. The call parks, and the card shows the connection's owner its exact arguments. Once approved it runs once, the trail records it ok, and the issue is there when read in Jira | unverified | -| C6 | The owner approves one parked write and declines another. The seat receives each ending once as `approval.resolved`, and the trail records each ending under its card's `approvalId`. An expiry takes 24 hours; record it if the walk spans one | unverified | +| C6 | The owner approves one parked write and declines another. The approved one ends `ran` and its receipt appears in the pod; the declined one ends `declined` (`approval_declined`) without running. The seat receives each ending once as `approval.resolved`, and the trail records each under its card's `approvalId`. A card nobody answers expires after 24 hours, or sooner if its grant ends first (the panel's shortest grant is 7 days), and the sweep then ends it `expired` (`approval_expired`) within five minutes; record it if the walk spans one | unverified | | C8 | The grant's tools are offered in its pod and not in a second pod the same agent is in. A call against the grant from outside its pod or audience is refused with its code and recorded in the trail | unverified | -| C9 | Bounded: only the five writers are offered, never the vendor's `createConfluenceContent`; a `read` grant refuses a writer; the mint refuses plain `write` with `write_requires_confirm`; the comment tool is marked irreversible. Revocable: a write approved after its grant is revoked or has expired is refused with its code, and the seat learns that code. After a revoke on the Connectors page, record whether the connection has left Atlassian's connected apps page, the entry's revoke page. Rotation: if the walk outlasts the access token, a later call succeeds through a refresh | unverified | +| C9 | Bounded: only the five writers are offered, never the vendor's `createConfluenceContent`; a `read` grant refuses a writer; the mint refuses plain `write` with `write_requires_confirm`; the comment tool is marked irreversible. Revocable: revoking a grant leaves its parked cards open; approve one afterwards, and it is refused when it runs, ending `refused` (`grant_revoked`) for the seat and in the pod's receipt. Record whether the card still offers Approve after the revoke. After a revoke on the Connectors page, record whether the connection has left Atlassian's connected apps page, the entry's revoke page. Rotation: if the walk outlasts the access token, a later call succeeds through a refresh | unverified | | C4 | Refused by design until TASK-213 | refused by design | **Sentry (#2329).** @@ -193,8 +193,8 @@ A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the | C1 | A stranger connects without an operator, through the CIMD client. At Sentry's consent, select the Triage Issues skill, as #2329 asks. The authorization then appears on Sentry's Authorized Applications page, and the row's `config.grantedScope` records what Sentry granted | unverified | | C2 | The page shows the row connected. A failed call lands as an Activity row that names the failure. Revoke is reachable at 390 | unverified | | C3 | In an eligible pod, a hosted agent completes a read through a pod grant, such as `find_projects`. The trail records it ok, and the answer matches what Sentry's own pages show | unverified | -| C6 | Through a `write-with-confirm` grant, `update_issue` parks, and the card shows the owner its exact arguments. The owner approves one call and declines another. Only the approved one changes the issue in Sentry, and the seat receives each ending once as `approval.resolved` | unverified | -| C9 | Bounded: the 12 pinned tools are the only ones offered, without the dispatcher, its catalogue or Seer, and `get_sentry_resource` is offered without a `url` argument. Revocable: a write approved after its grant is revoked or has expired is refused with its code. After a revoke on the Connectors page, record whether the authorization has left Sentry's Authorized Applications page | unverified | +| C6 | Through a `write-with-confirm` grant, `update_issue` parks, and the card shows the owner its exact arguments. The owner approves one call and declines another. Only the approved one changes the issue in Sentry: it ends `ran` with a receipt in the pod, and the other ends `declined` (`approval_declined`). The seat receives each ending once as `approval.resolved` | unverified | +| C9 | Bounded: the 12 pinned tools are the only ones offered, without the dispatcher, its catalogue or Seer, and `get_sentry_resource` is offered without a `url` argument. Revocable: an `update_issue` call parked before its grant is revoked, then approved, ends `refused` (`grant_revoked`) without changing the issue. After a revoke on the Connectors page, record whether the authorization has left Sentry's Authorized Applications page | unverified | | C4 | Refused by design until TASK-213 | refused by design | ## Cross-cutting reds From a235d7ced7bc5c791824e6039fa900759dc6a929 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 24 Oct 2026 07:03:29 -0700 Subject: [PATCH 3/4] docs(plans): fill TASK-270's rows from the 10-23 staging walk Both entries are deployed and hidden on commonly.me since #2530. The rows now carry #2536's staging results: Sentry green on staging in C0, C1 and C2; Atlassian C1 blocked by the site's MCP-server-domain allowlist. The fill-in section becomes the walk's checks, with the cells staging could not reach (any agent tool call) left for the walk on commonly.me. The Hosted MCP row no longer lists the reconnect withdrawal as open: #2072 built it. Co-Authored-By: Claude Opus 5.5 Co-authored-by: wren Agent-Model: claude/claude-opus-5-5/max --- docs/plans/integration-readiness-matrix.md | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/plans/integration-readiness-matrix.md b/docs/plans/integration-readiness-matrix.md index fc251dc1a0..fcd25f1276 100644 --- a/docs/plans/integration-readiness-matrix.md +++ b/docs/plans/integration-readiness-matrix.md @@ -53,11 +53,11 @@ The matrix below is the definition of "ready". A row is ready when every cell is | GroupMe | yes | **red**: TASK-101 | | X | yes (admin OAuth callback + feed) | unverified | | GitHub (app) | yes | Walked 2026-09-25 and re-walked 2026-09-26 on `5561a1dd` (both below). Live on our own repository since 09-18. **red** in C1 until per-person GitHub: a team cannot connect its own repository. C2 at 390 is green since #1874, shown on `5561a1dd`. C3 (a hosted agent gets the broker, #1880) shipped and has not been walked. C8 was green on `9a32fca5`. A new grant from the connection's owner, `grant_3c4d6ad5` (2026-09-29, on Sam's approval), has the same scope as the lapsed 09-18 one: pod "C4 run 2026-09-18"; `list_issues`, `create_issue` and `close_issue`; write-with-confirm; audience Sam, `c3stranger0912` and `c4-smoke`. It runs to 2026-10-06, so C3, C4 and C8 are walkable again. None has been walked on the current build | -| Hosted MCP (generic type, TASK-172) | yes | **Built and live, with one follow-up open.** Steps 1–6 of `hosted-mcp-connection-scope.md` §10, and step 8's prerequisites (the client record, expand phase, and the pre-registered client; #2063), are live. **Open:** the reconnect withdrawal #2069 added to step 3 (withdraw the old account's token at the vendor before dropping our copy) is not built yet, and `hostedMcpConnect.ts:406–420` does not do it. Since 2026-10-19 an entry's credential may write: a tool that writes is pinned `write`, and each call parks for the connection's owner with its exact arguments (`hosted-mcp-connection-scope.md` §3 and §5). That lifted Wren 76043's bar, that every entry's credential be unable to write. Entries are offered one by one; the rows below walk them | +| Hosted MCP (generic type, TASK-172) | yes | **Built and live.** Steps 1–6 of `hosted-mcp-connection-scope.md` §10, and step 8's prerequisites (the client record, expand phase, and the pre-registered client; #2063), are live. The reconnect withdrawal #2069 added to step 3 is built (#2072). A reconnect that brings a different account withdraws the old token at the vendor before our copy is overwritten. When that cannot be done, or the two accounts cannot be compared, the Connectors page points the person to the vendor's revoke page instead (`hostedMcpConnect.ts:554–598`). Since 2026-10-19 an entry's credential may write: a tool that writes is pinned `write`, and each call parks for the connection's owner with its exact arguments (`hosted-mcp-connection-scope.md` §3 and §5). That lifted Wren 76043's bar, that every entry's credential be unable to write. Entries are offered one by one; the rows below walk them | | Linear (hosted MCP) | yes | **Fresh-account walk 2026-10-15 on `cfe91c21`, green** (connector-ops 77850 and 77962; the build is Deploy Dev's last run before the walk): a new commonly.me account and a new Linear workspace, neither connected before. **C1 green**: connected through the Connectors page. Linear's consent read "Read, Identity", the authorize request asked for `read openid`, and the token response granted `read openid` (`config.grantedScope`). **C3 green in an eligible pod**: a read grant of the 36 pinned tools, made through the grant panel, which offers only Read, in the account's own My Workspace. That pod is private and invite-only, with no bridge and Scout as its only agent, so it passes §12's pod rule in `hosted-mcp-connection-scope.md` (#2211). Scout listed the workspace's one team through the grant, the trail records the call ok, and Scout quoted #2206's untrusted-content marker ahead of the data. #2211 deployed after the walk, and the same call was ok again after it, at 16:22:37Z. The earlier C3 and C4 walks ran in the C4 run pod, which fails that rule: since `ff909fb3` the deployed rule returns `pod_joinable` for both of its grants. Partly walked live 2026-10-01 (Sam's account, Chrome). Before the fresh-account walk, C1 was open: Sam's own operator-led connect succeeded on `cf9b6abf`, through CIMD with scope `read openid`, and the row records its client and the Linear subject. That didn't prove a stranger connects unaided, and no stranger had tried. **C2 green at 1440, the rest unwalked**: in the fresh-account walk the grant panel offered only Read. Earlier, on `cf9b6abf` the grant rendered as GitHub, because the catalogue projected 0 Linear tools. #2068 (`207c68d5`) fixed it, and on the deployed `e370fe9b` (its descendant) the row reads Linear, with its mark and the read eye, at 1200. 390, a failure reaching Activity, and revoke reachability are unwalked. Earlier, C3 was green in the C4 run pod: Scout listed the team and three issues through `grant_c6af31b8`; the trail showed the calls ok, with Sam as credential owner. **C4 refused by design** from #2211 (the C4 column), and c4-smoke is now offered no Linear tool. Before that it was green (2026-10-09): c4-smoke, a public local claude seat confined by Seatbelt, called `linear.list_teams` through its broker on `grant_e3a1507b` at 06:12:57Z, and the trail shows it ok. Its daemon started at 06:11:59Z, after global cli 0.1.84 (npm latest) was installed at 06:11:41Z, so it runs the current build. An earlier run on 2026-09-27 didn't count, because that daemon predated the cli it should have been running. The same spawn showed that TASK-228's headers helper works under the public Seatbelt profile. A by-name scan of the spawn's claude process found `COMMONLY_TOKEN_FILE` set and `COMMONLY_AGENT_TOKEN` absent. The rest of #2067's consumer proof is unmeasured: the child processes' environments, and a credential rotation followed by a 401 retry succeeding. **C8 open**: in a pod with no grant, Scout is offered no `linear.*` tools. That's confinement by projection. An attempted out-of-pod call, refused and recorded in the trail, hasn't been made. **C9 open**, now only for whether a revoke takes effect at Linear. Linear's revoke is page-only. The fresh-account walk reached the page: `https://linear.app/settings/account/security`, whose Authorized applications list shows the connection as "MCP · Read · Revoke". #2230 points the entry's page there. Before #2230 the entry named `https://linear.app/settings/security`, which is Linear's workspace admin page. Before that walk, every linear.app settings URL redirected to the old workspace's unfinished welcome flow, so the page had not been reached. C5, C6, C7 and C10 are unwalked | | Google Calendar (hosted MCP) | yes | **Built, live, not offered.** #2066 (`e370fe9b`) pins the 5 read tools from Google's unauthenticated `tools/list`, with a pre-registered client and `openid` for the account subject. "Not offered" is a **config fact, not a code fact**. The client values arrived on 2026-10-09 (#2111), and the tile was offered until 2026-10-14. OAuth worked, but every tool call failed Google's Developer Preview gate, which is **per Cloud project** (Google named the project in its error on the 2026-10-09 gate test). Since 2026-10-14 `hostedMcp.googleCalendar.enabled` is `false` in values-dev (Wren's ruling), so the instance holds no client values, the catalogue reports `available: false`, and the page shows "not enabled on this instance" with no Connect. Flip the flag once the project is enrolled and an enrolled `list_calendars` call succeeds. Waiting on Sam: a Workspace seat on the domain and Developer Preview enrollment for the connectors project. The OAuth client already exists in a project of its own (Wren: a revoke withdraws every scope a person granted the project) | -| Atlassian (hosted MCP), writes in #2328 | yes (writes since #2328) | **Reads live; writes merged 2026-10-23, live once a deploy carries them; walk on staging planned.** The entry pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments, and runs only under the definition it parked under (#2378). The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect. **C4 refused by design** (the C4 column). The staging walk's fill-in is below | -| Sentry (hosted MCP), #2329 | yes (#2329) | **Merged 2026-10-23, offered once a deploy carries it; walk on staging planned.** #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. **C4 refused by design** (the C4 column). The staging walk's fill-in is below | +| Atlassian (hosted MCP), writes in #2328 | yes (writes since #2328) | **Deployed, hidden on commonly.me since #2530.** The live build (`19de6035d`, 2026-10-24) carries every change below. `hostedMcp.hiddenEntries` in values-dev leaves the entry out of the catalogue and refuses a new connect with `unknown_entry` (`hostedMcpConnect.ts:251`). **C1 blocked on staging** (2026-10-23, `876870378`, #2536): the site's MCP-server-domain allowlist does not include the staging origin, and only a site admin can add it. The entry pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments, and runs only under the definition it parked under (#2378). The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect. **C4 refused by design** (the C4 column). The walk's checks are below | +| Sentry (hosted MCP), #2329 | yes (#2329) | **Deployed, hidden on commonly.me since #2530**, the same way as Atlassian. **Green on staging in C0, C1 and C2** (2026-10-23, `876870378`, #2536). Staging has no agent runtime, so C3, C6 and C9 were not walked. #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. **C4 refused by design** (the C4 column). The walk's checks are below | | next app | no | Sam's decision; see below | ## Staging connector walk — 2026-10-23 on `876870378` @@ -157,13 +157,13 @@ The test gate on "Scout (Default)" was switched back off after the walk. On Sam' **Membership, hardened across every connector write path (2026-09-27).** A connector now writes only where its owner is a listed pod member, the same rule `createMessage` uses (`isListedPodMember`): relay, inbound, the gate PATCH, install, bind confirm and the gate reconciler (#1940, TASK-161). A pod's creator cannot leave it (#1945, TASK-166), so `createdBy` no longer stands in for membership; the Discord/Slack owner routes follow (#1946, TASK-168); `agent-admin` pods are not a gate target (#1954, TASK-171); the PG chat path reads Mongo membership rather than its own mirror (#1942, TASK-162); and a seat whose own declaration cannot confine a broker is refused at the broker call — every dispatch except the native runtime's in-process one, which is exempt because a hosted turn has no shell, web or file tool to confine (#1971, TASK-175, ruled by Wren). This bears on C9 (authority is bounded) for every channel row above. -## Staging walk: Atlassian writes and Sentry (planned 2026-10-23) +## Walk checks: Atlassian writes and Sentry -A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the two entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. Each result reads `unverified` until the walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. +What a walk checks for the two entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. The staging walk of 2026-10-23 (above, #2536) filled the cells staging can reach. Staging has no agent runtime, so a cell that needs an agent to call a tool waits for a walk on commonly.me. #2536 keeps both entries hidden there until that walk passes; the values-dev comment that hides them (#2530) still says a staging walk. A hidden entry refuses a new connect, so the walk needs the hide lifted while it runs. Each result reads `unverified` until a walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. #2536 does not record which widths it walked. **A staging green is not a commonly.me green.** Ready means green on commonly.me against the deployed build, so a cell that passes here is recorded as green on staging. Like "green to the external boundary", it keeps that mark when it is copied into the rows above, and it turns green when the same check passes on commonly.me (Method rule 5). -**Record the build.** Note the staging commit. Everything the walk depends on is on `main` by `4bc63222`, so a build from that commit or later carries all of it. A cell whose check needs a change the build lacks is `unverified` on that build, not red: +**Record the build.** Everything the walk depends on is on `main` by `4bc63222`, so a build from that commit or later carries all of it. The staging walk's `876870378` does, and so does commonly.me's `19de6035d` (2026-10-24). A cell whose check needs a change the build lacks is `unverified` on that build, not red: - #2328 and #2329, the entries walked; - #2397, which opens an MCP session for each list and call; without it every Atlassian call fails (TASK-263); @@ -172,13 +172,13 @@ A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the **C6 for a hosted write.** This type has no inbound path, so no card is answered from the vendor. Here C6 reads as the parked call's card: the connection's owner answers it in Commonly, and the seat receives the ending as `approval.resolved`: `ran`, `failed`, `refused`, `declined` or `expired`, with its code when it has one. An approved call also posts a receipt in the pod that names the approver, the agent, the tool and the ending. -**The walk's grants need an eligible pod.** Every source counts as outsider-writable today, and the mint applies §12's pod rule in `hosted-mcp-connection-scope.md` to every grant (`routes/grants.ts:389`, #2211). So each grant is a pod grant, in a pod that is private, invite-only and unbridged, with every agent in it running inside the backend. For an entry with a write tool, the grant panel offers `read` and "read and write, ask first" (`write-with-confirm`), never unattended `write` (`V2ConnectorTools.tsx:382`). +**The walk's grants need an eligible pod.** Every source counts as outsider-writable today, and the mint applies §12's pod rule in `hosted-mcp-connection-scope.md` to every grant (`routes/grants.ts:389`, #2211). So each grant is a pod grant, in a pod that is private, invite-only and unbridged, with every agent in it running inside the backend. For an entry with a write tool, the grant panel offers `read` and "read and write, ask first" (`write-with-confirm`), never unattended `write` (`V2ConnectorTools.tsx:381–386`). **Atlassian writes (#2328).** | cell | what the walk checks | result | |---|---|---| -| C1 | The site's admin first allows the instance's API origin under MCP server domains, as the entry's connect notice asks. A fresh connect then shows Atlassian's consent for the Jira and Confluence write scopes, and the row's `config.grantedScope` holds them. A row connected before #2328 holds no write scope; record whether the page tells its owner to reconnect, and whether a reconnect gains write | unverified | +| C1 | The site's admin first allows the instance's API origin under MCP server domains, as the entry's connect notice asks. A fresh connect then shows Atlassian's consent for the Jira and Confluence write scopes, and the row's `config.grantedScope` holds them. A row connected before #2328 holds no write scope; record whether the page tells its owner to reconnect, and whether a reconnect gains write | **blocked on staging** (2026-10-23, `876870378`, #2536): the allowlist does not include the staging origin. Unverified on commonly.me | | C3 | In an eligible pod, a hosted agent calls a writer through a `write-with-confirm` pod grant, such as `create_jira_issue`. The call parks, and the card shows the connection's owner its exact arguments. Once approved it runs once, the trail records it ok, and the issue is there when read in Jira | unverified | | C6 | The owner approves one parked write and declines another. The approved one ends `ran` and its receipt appears in the pod; the declined one ends `declined` (`approval_declined`) without running. The seat receives each ending once as `approval.resolved`, and the trail records each under its card's `approvalId`. A card nobody answers expires after 24 hours, or sooner if its grant ends first (the panel's shortest grant is 7 days), and the sweep then ends it `expired` (`approval_expired`) within five minutes; record it if the walk spans one | unverified | | C8 | The grant's tools are offered in its pod and not in a second pod the same agent is in. A call against the grant from outside its pod or audience is refused with its code and recorded in the trail | unverified | @@ -189,12 +189,12 @@ A fill-in for a walk on staging (`docs/runbooks/staging-environment.md`) of the | cell | what the walk checks | result | |---|---|---| -| C0 | A stranger sees the Sentry row on the Connectors page at 1200 and 390, and the catalogue API lists `sentry` with its tools (Method rule 4) | unverified | -| C1 | A stranger connects without an operator, through the CIMD client. At Sentry's consent, select the Triage Issues skill, as #2329 asks. The authorization then appears on Sentry's Authorized Applications page, and the row's `config.grantedScope` records what Sentry granted | unverified | -| C2 | The page shows the row connected. A failed call lands as an Activity row that names the failure. Revoke is reachable at 390 | unverified | +| C0 | A stranger sees the Sentry row on the Connectors page at 1200 and 390, and the catalogue API lists `sentry` with its tools (Method rule 4) | **green on staging** (2026-10-23, `876870378`, #2536) | +| C1 | A stranger connects without an operator, through the CIMD client. At Sentry's consent, select the Triage Issues skill, as #2329 asks. The authorization then appears on Sentry's Authorized Applications page, and the row's `config.grantedScope` records what Sentry granted | **green on staging** (#2536): consent with only the Inspect and Triage groups, and the row written. Sentry lists the authorization as `mcp.sentry.dev`. `config.grantedScope` was not recorded | +| C2 | The page shows the row connected. A failed call lands as an Activity row that names the failure. Revoke is reachable at 390 | **green on staging** per #2536: a read grant of the 11 reads, made in the walk pod and revoked. Not recorded: the Activity row for a failed call, which needs an agent's call | | C3 | In an eligible pod, a hosted agent completes a read through a pod grant, such as `find_projects`. The trail records it ok, and the answer matches what Sentry's own pages show | unverified | | C6 | Through a `write-with-confirm` grant, `update_issue` parks, and the card shows the owner its exact arguments. The owner approves one call and declines another. Only the approved one changes the issue in Sentry: it ends `ran` with a receipt in the pod, and the other ends `declined` (`approval_declined`). The seat receives each ending once as `approval.resolved` | unverified | -| C9 | Bounded: the 12 pinned tools are the only ones offered, without the dispatcher, its catalogue or Seer, and `get_sentry_resource` is offered without a `url` argument. Revocable: an `update_issue` call parked before its grant is revoked, then approved, ends `refused` (`grant_revoked`) without changing the issue. After a revoke on the Connectors page, record whether the authorization has left Sentry's Authorized Applications page | unverified | +| C9 | Bounded: the 12 pinned tools are the only ones offered, without the dispatcher, its catalogue or Seer, and `get_sentry_resource` is offered without a `url` argument. Revocable: an `update_issue` call parked before its grant is revoked, then approved, ends `refused` (`grant_revoked`) without changing the issue. A disconnect on the Connectors page calls Sentry's revocation endpoint before deleting the row. Record what Sentry's Authorized Applications page shows afterwards: it lists the client as `mcp.sentry.dev`, and removing it there cuts every Sentry-MCP session on the account (#2536) | unverified. On staging the disconnect's revocation call returned 200 (#2536) | | C4 | Refused by design until TASK-213 | refused by design | ## Cross-cutting reds From 316d089639a83c1b024cd93d7fd56a8727a86e93 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 24 Oct 2026 07:20:17 -0700 Subject: [PATCH 4/4] docs(plans): each staging green names what #2536 did not record, and the hide refuses a reconnect (TASK-270) CodeRabbit (review 5638542062) found three cells that overclaimed: - Sentry C1 was marked green while `config.grantedScope`, part of its check, was not recorded. It now reads green on staging except the scope. - Sentry C2 was marked green while the failed-call Activity row was not recorded. It now reads green on staging except the Activity row, and names revoke at 390 as unrecorded too. - The Atlassian row said a hidden entry refuses a new connect. startConnect refuses a hidden entry before any lookup of an existing connection (`hostedMcpConnect.ts:251`), so a reconnect is refused as well, and a row connected before #2328 cannot gain write scopes while the hide stands. C0 gets the same treatment for its widths, which the section already said #2536 did not record, and the Sentry row's summary follows the cells. Co-Authored-By: Claude Opus 5.5 Co-authored-by: wren Agent-Model: claude/claude-opus-5-5/max --- docs/plans/integration-readiness-matrix.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/plans/integration-readiness-matrix.md b/docs/plans/integration-readiness-matrix.md index fcd25f1276..f3424abe64 100644 --- a/docs/plans/integration-readiness-matrix.md +++ b/docs/plans/integration-readiness-matrix.md @@ -56,8 +56,8 @@ The matrix below is the definition of "ready". A row is ready when every cell is | Hosted MCP (generic type, TASK-172) | yes | **Built and live.** Steps 1–6 of `hosted-mcp-connection-scope.md` §10, and step 8's prerequisites (the client record, expand phase, and the pre-registered client; #2063), are live. The reconnect withdrawal #2069 added to step 3 is built (#2072). A reconnect that brings a different account withdraws the old token at the vendor before our copy is overwritten. When that cannot be done, or the two accounts cannot be compared, the Connectors page points the person to the vendor's revoke page instead (`hostedMcpConnect.ts:554–598`). Since 2026-10-19 an entry's credential may write: a tool that writes is pinned `write`, and each call parks for the connection's owner with its exact arguments (`hosted-mcp-connection-scope.md` §3 and §5). That lifted Wren 76043's bar, that every entry's credential be unable to write. Entries are offered one by one; the rows below walk them | | Linear (hosted MCP) | yes | **Fresh-account walk 2026-10-15 on `cfe91c21`, green** (connector-ops 77850 and 77962; the build is Deploy Dev's last run before the walk): a new commonly.me account and a new Linear workspace, neither connected before. **C1 green**: connected through the Connectors page. Linear's consent read "Read, Identity", the authorize request asked for `read openid`, and the token response granted `read openid` (`config.grantedScope`). **C3 green in an eligible pod**: a read grant of the 36 pinned tools, made through the grant panel, which offers only Read, in the account's own My Workspace. That pod is private and invite-only, with no bridge and Scout as its only agent, so it passes §12's pod rule in `hosted-mcp-connection-scope.md` (#2211). Scout listed the workspace's one team through the grant, the trail records the call ok, and Scout quoted #2206's untrusted-content marker ahead of the data. #2211 deployed after the walk, and the same call was ok again after it, at 16:22:37Z. The earlier C3 and C4 walks ran in the C4 run pod, which fails that rule: since `ff909fb3` the deployed rule returns `pod_joinable` for both of its grants. Partly walked live 2026-10-01 (Sam's account, Chrome). Before the fresh-account walk, C1 was open: Sam's own operator-led connect succeeded on `cf9b6abf`, through CIMD with scope `read openid`, and the row records its client and the Linear subject. That didn't prove a stranger connects unaided, and no stranger had tried. **C2 green at 1440, the rest unwalked**: in the fresh-account walk the grant panel offered only Read. Earlier, on `cf9b6abf` the grant rendered as GitHub, because the catalogue projected 0 Linear tools. #2068 (`207c68d5`) fixed it, and on the deployed `e370fe9b` (its descendant) the row reads Linear, with its mark and the read eye, at 1200. 390, a failure reaching Activity, and revoke reachability are unwalked. Earlier, C3 was green in the C4 run pod: Scout listed the team and three issues through `grant_c6af31b8`; the trail showed the calls ok, with Sam as credential owner. **C4 refused by design** from #2211 (the C4 column), and c4-smoke is now offered no Linear tool. Before that it was green (2026-10-09): c4-smoke, a public local claude seat confined by Seatbelt, called `linear.list_teams` through its broker on `grant_e3a1507b` at 06:12:57Z, and the trail shows it ok. Its daemon started at 06:11:59Z, after global cli 0.1.84 (npm latest) was installed at 06:11:41Z, so it runs the current build. An earlier run on 2026-09-27 didn't count, because that daemon predated the cli it should have been running. The same spawn showed that TASK-228's headers helper works under the public Seatbelt profile. A by-name scan of the spawn's claude process found `COMMONLY_TOKEN_FILE` set and `COMMONLY_AGENT_TOKEN` absent. The rest of #2067's consumer proof is unmeasured: the child processes' environments, and a credential rotation followed by a 401 retry succeeding. **C8 open**: in a pod with no grant, Scout is offered no `linear.*` tools. That's confinement by projection. An attempted out-of-pod call, refused and recorded in the trail, hasn't been made. **C9 open**, now only for whether a revoke takes effect at Linear. Linear's revoke is page-only. The fresh-account walk reached the page: `https://linear.app/settings/account/security`, whose Authorized applications list shows the connection as "MCP · Read · Revoke". #2230 points the entry's page there. Before #2230 the entry named `https://linear.app/settings/security`, which is Linear's workspace admin page. Before that walk, every linear.app settings URL redirected to the old workspace's unfinished welcome flow, so the page had not been reached. C5, C6, C7 and C10 are unwalked | | Google Calendar (hosted MCP) | yes | **Built, live, not offered.** #2066 (`e370fe9b`) pins the 5 read tools from Google's unauthenticated `tools/list`, with a pre-registered client and `openid` for the account subject. "Not offered" is a **config fact, not a code fact**. The client values arrived on 2026-10-09 (#2111), and the tile was offered until 2026-10-14. OAuth worked, but every tool call failed Google's Developer Preview gate, which is **per Cloud project** (Google named the project in its error on the 2026-10-09 gate test). Since 2026-10-14 `hostedMcp.googleCalendar.enabled` is `false` in values-dev (Wren's ruling), so the instance holds no client values, the catalogue reports `available: false`, and the page shows "not enabled on this instance" with no Connect. Flip the flag once the project is enrolled and an enrolled `list_calendars` call succeeds. Waiting on Sam: a Workspace seat on the domain and Developer Preview enrollment for the connectors project. The OAuth client already exists in a project of its own (Wren: a revoke withdraws every scope a person granted the project) | -| Atlassian (hosted MCP), writes in #2328 | yes (writes since #2328) | **Deployed, hidden on commonly.me since #2530.** The live build (`19de6035d`, 2026-10-24) carries every change below. `hostedMcp.hiddenEntries` in values-dev leaves the entry out of the catalogue and refuses a new connect with `unknown_entry` (`hostedMcpConnect.ts:251`). **C1 blocked on staging** (2026-10-23, `876870378`, #2536): the site's MCP-server-domain allowlist does not include the staging origin, and only a site admin can add it. The entry pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments, and runs only under the definition it parked under (#2378). The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect. **C4 refused by design** (the C4 column). The walk's checks are below | -| Sentry (hosted MCP), #2329 | yes (#2329) | **Deployed, hidden on commonly.me since #2530**, the same way as Atlassian. **Green on staging in C0, C1 and C2** (2026-10-23, `876870378`, #2536). Staging has no agent runtime, so C3, C6 and C9 were not walked. #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. **C4 refused by design** (the C4 column). The walk's checks are below | +| Atlassian (hosted MCP), writes in #2328 | yes (writes since #2328) | **Deployed, hidden on commonly.me since #2530.** The live build (`19de6035d`, 2026-10-24) carries every change below. `hostedMcp.hiddenEntries` in values-dev leaves the entry out of the catalogue and refuses every connect with `unknown_entry`, a reconnect included (`hostedMcpConnect.ts:251`). **C1 blocked on staging** (2026-10-23, `876870378`, #2536): the site's MCP-server-domain allowlist does not include the staging origin, and only a site admin can add it. The entry pins six Jira and Confluence reads. In a 2026-10-22 walk C3 was red: every call failed with "tools/list could not be verified", which TASK-263 attributed to our client never opening an MCP session. #2397 opens one for each list and call; the C3 re-check after its deploy belongs to TASK-263. #2328 adds five named writers: `update_confluence_content`, `create_jira_issue`, `edit_jira_issue`, `transition_jira_issue` and `add_or_edit_jira_issue_comment`, the last marked irreversible. Each is pinned `write`, so every write parks for the connection's owner with its exact arguments, and runs only under the definition it parked under (#2378). The entry now requests write scopes, so a row connected before #2328 holds a token that cannot write, and its owner must reconnect, which the hide refuses until it is lifted. **C4 refused by design** (the C4 column). The walk's checks are below | +| Sentry (hosted MCP), #2329 | yes (#2329) | **Deployed, hidden on commonly.me since #2530**, the same way as Atlassian. **C0, C1 and C2 green on staging, each with a part #2536 did not record** (2026-10-23, `876870378`). Staging has no agent runtime, so C3, C6 and C9 were not walked. #2329 pins 11 named reads and `update_issue`, an irreversible write that parks for the connection's owner with its exact arguments. `get_sentry_resource` is pinned without the vendor's `url` argument, and the vendor's dispatcher, its catalogue and Seer are left out, as ruled in the PR thread. The client is CIMD, and the entry requests five scopes, four of them write. **C4 refused by design** (the C4 column). The walk's checks are below | | next app | no | Sam's decision; see below | ## Staging connector walk — 2026-10-23 on `876870378` @@ -159,7 +159,7 @@ The test gate on "Scout (Default)" was switched back off after the walk. On Sam' ## Walk checks: Atlassian writes and Sentry -What a walk checks for the two entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. The staging walk of 2026-10-23 (above, #2536) filled the cells staging can reach. Staging has no agent runtime, so a cell that needs an agent to call a tool waits for a walk on commonly.me. #2536 keeps both entries hidden there until that walk passes; the values-dev comment that hides them (#2530) still says a staging walk. A hidden entry refuses a new connect, so the walk needs the hide lifted while it runs. Each result reads `unverified` until a walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. #2536 does not record which widths it walked. +What a walk checks for the two entries above: C1, C3, C6, C8 and C9 for Atlassian writes, and C0 to C3, C6 and C9 for Sentry. C4 is refused by design for both until TASK-213, so it is not walked. The staging walk of 2026-10-23 (above, #2536) filled the cells staging can reach. Staging has no agent runtime, so a cell that needs an agent to call a tool waits for a walk on commonly.me. #2536 keeps both entries hidden there until that walk passes; the values-dev comment that hides them (#2530) still says a staging walk. A hidden entry refuses every connect, a reconnect included, so the walk needs the hide lifted while it runs. Each result reads `unverified` until a walk replaces it with what it saw and a link to the evidence. Method rules 1 and 2 hold: a stranger account's own session, and every UI cell at 1200 and 390. #2536 does not record which widths it walked. **A staging green is not a commonly.me green.** Ready means green on commonly.me against the deployed build, so a cell that passes here is recorded as green on staging. Like "green to the external boundary", it keeps that mark when it is copied into the rows above, and it turns green when the same check passes on commonly.me (Method rule 5). @@ -189,9 +189,9 @@ What a walk checks for the two entries above: C1, C3, C6, C8 and C9 for Atlassia | cell | what the walk checks | result | |---|---|---| -| C0 | A stranger sees the Sentry row on the Connectors page at 1200 and 390, and the catalogue API lists `sentry` with its tools (Method rule 4) | **green on staging** (2026-10-23, `876870378`, #2536) | -| C1 | A stranger connects without an operator, through the CIMD client. At Sentry's consent, select the Triage Issues skill, as #2329 asks. The authorization then appears on Sentry's Authorized Applications page, and the row's `config.grantedScope` records what Sentry granted | **green on staging** (#2536): consent with only the Inspect and Triage groups, and the row written. Sentry lists the authorization as `mcp.sentry.dev`. `config.grantedScope` was not recorded | -| C2 | The page shows the row connected. A failed call lands as an Activity row that names the failure. Revoke is reachable at 390 | **green on staging** per #2536: a read grant of the 11 reads, made in the walk pod and revoked. Not recorded: the Activity row for a failed call, which needs an agent's call | +| C0 | A stranger sees the Sentry row on the Connectors page at 1200 and 390, and the catalogue API lists `sentry` with its tools (Method rule 4) | **green on staging except the widths** (2026-10-23, `876870378`, #2536): #2536 does not record whether it walked 1200 and 390 | +| C1 | A stranger connects without an operator, through the CIMD client. At Sentry's consent, select the Triage Issues skill, as #2329 asks. The authorization then appears on Sentry's Authorized Applications page, and the row's `config.grantedScope` records what Sentry granted | **green on staging except the scope** (#2536): consent with only the Inspect and Triage groups, and the row written. Sentry lists the authorization as `mcp.sentry.dev`. Unverified: `config.grantedScope`, which #2536 did not record | +| C2 | The page shows the row connected. A failed call lands as an Activity row that names the failure. Revoke is reachable at 390 | **green on staging except the Activity row** (#2536): a read grant of the 11 reads, made in the walk pod and revoked. Unverified: the Activity row for a failed call, which needs an agent's call, and revoke at 390 | | C3 | In an eligible pod, a hosted agent completes a read through a pod grant, such as `find_projects`. The trail records it ok, and the answer matches what Sentry's own pages show | unverified | | C6 | Through a `write-with-confirm` grant, `update_issue` parks, and the card shows the owner its exact arguments. The owner approves one call and declines another. Only the approved one changes the issue in Sentry: it ends `ran` with a receipt in the pod, and the other ends `declined` (`approval_declined`). The seat receives each ending once as `approval.resolved` | unverified | | C9 | Bounded: the 12 pinned tools are the only ones offered, without the dispatcher, its catalogue or Seer, and `get_sentry_resource` is offered without a `url` argument. Revocable: an `update_issue` call parked before its grant is revoked, then approved, ends `refused` (`grant_revoked`) without changing the issue. A disconnect on the Connectors page calls Sentry's revocation endpoint before deleting the row. Record what Sentry's Authorized Applications page shows afterwards: it lists the client as `mcp.sentry.dev`, and removing it there cuts every Sentry-MCP session on the account (#2536) | unverified. On staging the disconnect's revocation call returned 200 (#2536) |