Skip to content

fix(confluence): gate the page selector to operations that use it - #6769

Open
mzxchandra wants to merge 2 commits into
stagingfrom
fix/confluence-selector-gating
Open

fix(confluence): gate the page selector to operations that use it#6769
mzxchandra wants to merge 2 commits into
stagingfrom
fix/confluence-selector-gating

Conversation

@mzxchandra

Copy link
Copy Markdown
Contributor

The bug

The v2 Confluence block gated its page target (pageId / manualPageId) with a 23-entry
not: true denylist, while the same two subblocks declared required as an 18-entry
allowlist. The two lists were not complements, so Select Page rendered on operations that
consume no page id at all
. The most visible case is Create Page, where the page id is an
output of the operation, not an input: users were shown a required-looking page picker for the
page they were about to create.

The fix

Both condition and required now share one positive PAGE_ID_OPERATIONS allowlist.

The list was derived rather than hand-written: every one of the 44 v2 operations was mapped through
the block's own tools.config.tool switch to its tool file, and the tool's params checked for a
pageId entry. Exactly 18 tools declare a required pageId, and those 18 are the allowlist -
identical to the required list that was already there.

Newly hidden (5): create, create_blogpost, update_comment, delete_comment,
delete_attachment. None of their tools declare pageId; the two create operations produce a page
id, and the comment/attachment mutations address their own commentId / attachmentId. No other
subblock depends on the page field for these operations, and Create Page keeps its dedicated
parentId field, which is the input people actually wanted there.

Legacy block

ConfluenceBlock (hideFromToolbar, sunset.replacedBy: 'confluence_v2') had no condition at
all
, so it rendered the page target on all 15 of its operations. It now has its own
LEGACY_PAGE_ID_OPERATIONS, seeded from its existing 8-op required list and verified the same way
against the tools. It is deliberately a separate constant rather than a reference to
PAGE_ID_OPERATIONS: the two blocks expose different operation sets, and a sunset block must not
silently track changes to its replacement. Its labels and sentences are otherwise untouched.

Also in this diff

  • dependsOn symmetry. manualPageId was missing the dependsOn: ['credential', 'domain'] its
    pageId twin has, so the manual field stayed editable while its credential was still unbound.
    Added. This is UI gating only - dependsOn does not affect serialization or required validation.
  • Dead canvas clauses. With the page target hidden on delete_comment and delete_attachment,
    their canvas sentences' trailing from page clause referenced a field that can never render.
    The repo's check:canvas-sentences audit catches this; the clause is removed on both blocks. The
    rendered sentence is unchanged, since the clause had nothing to interpolate.
  • Label. v2 Read Page becomes Get Page, matching the Get * convention used by the rest of
    the block's single-item reads, plus its canvas sentence and the generated integrations.json
    entry. The legacy block keeps Read Page.

Deliberate non-change

list_tasks accepts an optional pageId filter and the block forwards it, but the selector has
always been hidden, so the filter has never been reachable. Un-hiding it now would make any existing
list_tasks block that carries a stale stored pageId silently start filtering its results. Left
hidden; worth a separate issue.

Compatibility

Operation ids and tool ids are unchanged (read still maps to confluence_retrieve). Only the
display label, the visibility conditions, and one dependsOn array moved. Stored workflows are
unaffected: a saved pageId on a now-hidden operation was already being dropped by the tool, and
nothing about serialization or required validation changed for the 18 operations that use it.

Tests

apps/sim/blocks/blocks/confluence.test.ts - 181 tests covering both blocks. They derive their
expectations from the tool contracts rather than hand-copied operation lists, so adding an operation
whose tool takes a pageId fails here until the block's condition is widened to match. A guard test
fails if any operation resolves to a tool the file does not import.

The tools are imported directly rather than through @/tools/registry: vitest.setup.ts mocks
the registry to {}, so routing through it would make every contract assertion pass vacuously.

Mutation-checked: stashing the block change turns 9 of them red, and re-adding a dead sentence
clause turns the new canvas-sentence guard red on both blocks.

Verification

Live end-to-end against a real Confluence site (sim-testing.atlassian.net):

  • All 44 operations swept in both basic and advanced mode and diffed identical - 18 show the
    page field in each, 26 do not.
  • create page confirmed to render space / title / content / parentId and no page selector.
  • get page executed successfully, returning real page content.
  • A runtime <block.output> reference typed into the manual page field survived save and reload
    without the selector clobbering it.

Repo gates: check:canvas-sentences, docs:check, integration-catalog:check,
tool-metadata:check, check:api-validation, type-check, and biome all pass. 1711 tests green
across blocks/, connectors/, lib/integrations/, lib/oauth/, and lib/workflows/blocks/.

Known pre-existing bug, not addressed here

Confluence v2 fails on any operation that has a rendered-but-empty optional field:

error: "Confluence: Invalid input: expected string, received null"

The block's params spreads ...rest unnormalized, so an untouched subblock's stored null reaches
a tool param typed string. It hits create (via parentId) and all 20 list operations (via
limit), plus search / update / upload_attachment. Confirmed pre-existing: reproduced on unmodified
staging with this change stashed. It is why create could not be executed end to end here, and it
is tracked separately - not a regression from this PR.

A separate pre-existing issue also surfaced while validating: search_in_space can never succeed,
because its tool and route both require spaceKey while the block's space picker supplies spaceId.
Also out of scope here.

The v2 block gated `pageId`/`manualPageId` with a 23-entry `not: true`
denylist while its `required` was an allowlist. The two were not
complements, so Select Page rendered on operations that consume no page
id - most visibly Create Page, where the page id is an output.

Replace the denylist with a positive `PAGE_ID_OPERATIONS` allowlist,
shared by both `condition` and `required`. The list is the 18 v2
operations whose tool declares a required `pageId`, derived by mapping
all 44 operations through `tools.config.tool` to their tool file.

The legacy block had no `condition` at all. Give it its own
`LEGACY_PAGE_ID_OPERATIONS` (its existing 8-op `required` list), kept
separate so a sunset block does not track its replacement.

Also drop the now-dead "from page" sentence clause on `delete_comment`
and `delete_attachment`, add the `dependsOn` that `manualPageId` was
missing, and rename the v2 `Read Page` label to `Get Page`.
@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 16, 2026 5:09pm

Request Review

@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes workflow block UI gating and labels for Confluence integrations; behavior is contract-tested and stored operation ids are unchanged, but users will see different fields on several operations.

Overview
Fixes the v2 Confluence block showing Select Page on operations that never consume a page id (notably Create Page), caused by a long not: true denylist on condition that did not match the required allowlist.

condition and required now share one positive PAGE_ID_OPERATIONS list (18 ops), aligned with each operation’s tool requiring pageId. Five ops (create, create_blogpost, comment/attachment deletes/updates) no longer show the page picker; create still uses parentId.

The legacy block gets its own LEGACY_PAGE_ID_OPERATIONS gating (it previously had no condition). manualPageId gains dependsOn: ['credential', 'domain'] like its twin. Canvas sentences drop dead “from page” clauses on comment/attachment deletes. v2 Read Page label becomes Get Page (legacy stays Read Page); integrations.json matches.

Adds confluence.test.ts so page-selector visibility stays tied to tool pageId contracts for both blocks.

Reviewed by Cursor Bugbot for commit 77f8f5b. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR aligns Confluence page-selector visibility and required-state gating with the operations whose tools require a page ID.

  • Introduces separate allowlists for the v2 and legacy Confluence blocks.
  • Adds biconditional contract tests covering both visible and hidden selector states.
  • Synchronizes the manual selector’s dependencies and removes unreachable canvas clauses.
  • Renames the v2 single-page retrieval label from “Read Page” to “Get Page” across block and integration metadata.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported regression-test gap is closed by assertions covering both directions of the selector/tool contract.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/confluence.test.ts Adds comprehensive operation-to-tool contract tests; the revised biconditional assertion resolves the previously reported one-direction coverage gap.
apps/sim/blocks/blocks/confluence.ts Uses explicit page-consuming operation allowlists for selector visibility and required state while keeping basic and advanced fields symmetric.
apps/sim/lib/integrations/integrations.json Synchronizes generated integration metadata with the v2 “Get Page” display label.

Reviews (2): Last reviewed commit: "test(confluence): assert page-selector v..." | Re-trigger Greptile

Comment thread apps/sim/blocks/blocks/confluence.test.ts Outdated
The contract test returned early when a tool did not require `pageId`, so
it only proved that page-consuming operations render the selector. An
operation wrongly added to `PAGE_ID_OPERATIONS` still passed unless it
also appeared in the separate five-entry hidden list.

Assert the biconditional instead: for every operation, the page target
renders exactly when its tool requires `pageId`. Injecting `search` into
the allowlist now fails the suite.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 77f8f5b. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant