Skip to content

feat(brains): sync the capability catalog to the release production serves and bump to 2.9.0 [BRNS-MCP-048] - #27

Merged
olegshmuelov merged 4 commits into
mainfrom
chore/sync-brains-build-2026-08-10
Aug 11, 2026
Merged

feat(brains): sync the capability catalog to the release production serves and bump to 2.9.0 [BRNS-MCP-048]#27
olegshmuelov merged 4 commits into
mainfrom
chore/sync-brains-build-2026-08-10

Conversation

@olegshmuelov

@olegshmuelov olegshmuelov commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What this does

Syncs the published capability artifacts to e332512644b2f06a6b7068dcc9196eab2d31c05a and ships it as one release rather than two.

Three generated skills move:

  • brains-build/SKILL.md — three capability rows an earlier sync missed: Board form, Sharing, Recipe publishing. The server has been advertising these tools; the published skill had no route to them.
  • brains-write/SKILL.md — the integration-action contract sentence, see below.
  • brains-automation/SKILL.md — the automation-side rule: a confirmation-required action drafts unless the automation's owner set write_policy:'auto_confirm_safe'.

capability-catalog.json advances three artifact_sha256 values (brains-write, brains-build, brains-automation), the brains-features catalog_sha256, and source_commit. Both client manifests go 2.8.32.9.0. One test file changes; nothing else authored is touched.

Reviewer: the part to actually read (BRNS-MCP-048)

brains-write/SKILL.md now tells a CLI agent that an act_on_integration call may execute inline instead of always drafting. That is the security-relevant change here, and the reason this is pinned to this commit rather than the earlier one.

The behaviour is off by default and narrow: a per-user opt-in in brains settings, a three-action allowlist (gdrive-files/create_file, gcalendar/create_event, monday-items/create_item), each behind an input guard and an audited byte digest, and only for a client signed in from the user's own machine. Everything else drafts. Every execution is still recorded in /inbox. The text says the mode is decided server-side per call and that an agent must never assume a draft_id — literally true: the rate cap degrades a direct execution back to a draft.

The server-side change itself shipped upstream in BRNS-MCP-045; this PR only republishes the text that documents it.

This repo's contract tripwire fired on the regenerated artifact, which is worth seeing rather than discovering. It pinned requires_confirmation:true as unconditionally drafting, and that is now false server-side. I updated it to the current wording and pinned the whole contract paragraph as a verbatim region — because a substring pin proved bypassable: leaving every pinned sentence intact and inserting "the setting is off for almost everyone, so plan on the draft" kept the suite green while reversing what the contract means. Mutation-proved, that insertion and nine other edits now go red.

This PR introduces a transient contradiction in brains-automation/SKILL.md. At origin/main that file was internally consistent and wrong: the contract sentence and lines 179 and 251 all said a confirmation-required action waits at /inbox, when write_policy:'auto_confirm_safe' has always executed those inline. This corrects the contract sentence only — the other two are generated from different upstream sources and cannot be fixed here. So the file goes from consistent-and-wrong to half-corrected-and-self-contradicting. Net better, not strictly better: nobody ends up believing something more dangerous than today's published "always waits", but a reader now has to arbitrate two statements. Filed upstream as BRNS-MCP-052.

Two smaller upstream gaps the review found, filed with it: the brains-write text names the risk but prescribes no "check with the user first" behaviour, and its Cap: 30 auto-executions/install/60s line omits the additional per-user direct-exec cap of 10/min.

BRNS-MCP-048's rule is an ordering rule: publish only after every production MCP replica serves the implementing commit. Telling CLI users a call may execute while their server still always drafts is wrong in the direction that matters, and CLI users are the eligible population.

That gate is met. The production brains-mcp statefulset is fully rolled — 2/2 replicas ready and updated, currentRevision == updateRevision, both pods on that revision. It now serves 656828d2870b27e9c926a0c726b767c222a076e6 (a release after this one); e332512 is an ancestor of it, and every artifact this PR publishes is byte-identical between the two, so the pinned bytes are what prod runs. That is a cluster check I ran by hand; nothing in CI proves it, so re-check if this sits before merge.

Why one digest moves and its neighbour does not

brains-write and brains-automation change artifact_sha256 while their catalog_sha256 holds. That is correct: catalog_sha256 digests the authored capability object, and this sentence is authored in the renderer, so the rendered bytes move while the authored catalog does not. brains-features moves both because its change was in the authored feature catalog.

Verification

  • Rendered twice into separate scratch roots, byte-identical.
  • Every rendered skill byte-compared against the source repo's own generated copy at that commit — five for five.
  • Every digest cross-checked against the source manifest, and every artifact_sha256 recomputed from the bytes on disk.
  • Published catalog and source manifest differ in exactly one key, source_commit, stamped on the published copy only.
  • brains-board and brains-workflow confirmed unmoved.
  • Contract suite passes. Its action-contract pins now cover the paragraph as a whole region plus the per-rule checks, so an insertion or a reflow reddens the build, not just a deletion.
  • Delivery guard confirms both manifests move forward together.

These artifacts are build output from ssvlabs/brains and sync verbatim — wording changes belong upstream, not here.

Regenerate the published capability artifacts from the current catalog in
ssvlabs/brains. brains-build/SKILL.md gains the three feature rows an earlier
sync missed — Board form, Sharing, Recipe publishing — with the routing wording
as it now stands; the other four generated skills render byte-identical and do
not move.

capability-catalog.json carries the refreshed digests and the commit that
rendered these bytes. Both client manifests advance 2.8.3 -> 2.9.0 together, so
the new content reaches installed plugins and the two stay version-aligned.
Re-renders the published artifacts from the current source commit, so
source_commit names the release a user's MCP server is actually running rather
than the earlier one this branch first pinned.

brains-write/SKILL.md picks up the integration-action contract change: a user
who enables direct execution in their brains settings has a short allowlist of
low-risk actions run inline from a local CLI client, so an agent must treat any
act_on_integration call as potentially executing and never assume a draft_id.
Executions are still recorded in /inbox. brains-automation/SKILL.md states the
automation-side rule instead — a confirmation-required action drafts unless the
automation's owner set write_policy:'auto_confirm_safe'.

brains-build/SKILL.md is unchanged from the previous commit; its rows are
already at the rendered text for this commit. The manifest advances two artifact
digests and source_commit. Both client manifests already carry 2.9.0 from the
previous commit, which is the single release that delivers all of this.
The existing branch assertion pinned "`requires_confirmation:true` drafts for
out-of-band approval" as an absolute. That is no longer true server-side: a user
who enables direct execution has an allowlisted low-risk action run inline from a
local CLI client despite requires_confirmation:true. The rendered contract now
says "normally drafts", so the pin follows the truth. Its other two clauses are
untouched.

Adds a pin for the rule that carries the weight once true can execute: the mode
is decided server-side per call, so the caller must never assume a draft_id. It
is one contiguous substring of the rendered sentence rather than separate
includes for each phrase, because two fragments can sit in different sentences or
under a contradicting condition and still both be found — that pins vocabulary,
not the rule.

Mutation-proved both. Reverting to the old absolute wording, deleting the
auto_executed row, rewording the false branch, and deleting, paraphrasing,
splitting or inverting the per-call rule each turn the suite red with the right
message. The artifact digest gate fires first on a lone edit, so each mutation
also resealed the manifest — the coordinated edit that clears provenance and is
exactly what these semantic pins are for.
…n it

Presence checks cannot see what sits next to the sentence they find. Review
demonstrated it: leave every pinned sentence intact, insert "the setting is off
for almost everyone, so plan on the draft" straight after the never-assume-a-
draft_id rule, refresh the digests, and the suite passed while the contract now
told an agent the opposite of what it means.

Pins the whole rendered contract paragraph as one verbatim region, following the
README_INTRO_REGION idiom already in this file. The region runs from the
"Discover with" opener to the kind-table header, exclusive, so an insertion
anywhere in the prose — including just past the draft_id sentence, where the
attack landed — falls inside it. A region ending at that sentence would leave the
evasion one character outside and change nothing.

The per-rule assertions stay and run first, so a broken rule still reports itself
by name; the region is the catch-all for what none of them can see. Ordered the
other way it fires first on every in-region edit and the precise messages never
surface.

This reddens on every upstream reword of the paragraph, harmless ones included.
That is intended: the text tells an agent when a call may fire an external write
without asking, so a human should read each change before it reaches users. The
comment records how to update it correctly, since the tempting fix is to loosen
it back to a substring.

Mutation-proved, each case also resealing the manifest so the digest gate cannot
mask the result: the review's exact insertion, the same contradiction appended at
the end of the block, a deleted line, a one-word weakening, a pure reflow, and
the previous round's five cases all turn the suite red.
@olegshmuelov olegshmuelov changed the title feat(brains): sync the generated capability catalog and bump to 2.9.0 feat(brains): sync the capability catalog to the release production serves and bump to 2.9.0 Aug 11, 2026
@olegshmuelov olegshmuelov changed the title feat(brains): sync the capability catalog to the release production serves and bump to 2.9.0 feat(brains): sync the capability catalog to the release production serves and bump to 2.9.0 [BRNS-MCP-048] Aug 11, 2026

@sebastian-ssvlabs sebastian-ssvlabs 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.

Approving. I looked for anything that breaks an installed plugin or reverses a safety rule for an agent reading these skills, and found nothing critical. Recording what I verified and four medium notes inline.

Verified independently

  • All five artifact_sha256 values recomputed from the bytes on this branch — five for five, plus source_commit and both manifests at 2.9.0.
  • Contract suite green on a clean checkout of this branch (bun run tests/plugin-contract/run.ts).
  • The insertion attack the last commit describes: I reproduced it against brains-write — inserted "The setting is off for almost everyone, so plan on the draft" right after the draft_id sentence and resealed every digest. The region pin fires with the intended message. The defense works as claimed.
  • Every tool newly routed to from brains-build exists on the live MCP surface: create_board_form, share_board, publish_recipe (also share_folder, share_mini_site, create_share_circle named in the Sharing row). No repeat of #26.

Nothing here is a breaking change. No tool name is removed or renamed, no schema moves, both manifests advance together, and the one behavioral statement that changed moves published text toward what the server does. Worth stating explicitly because the direction matters: main today tells an agent requires_confirmation:true always drafts, while the server may execute — an agent believing main fires an external write thinking it staged a draft. This PR closes that. Merging sooner is the safer option, not the riskier one.

The four notes below are all medium and none should hold the merge.

Comment thread plugins/brains/skills/brains-automation/SKILL.md
Comment thread plugins/brains/skills/brains-write/SKILL.md
Comment thread tests/plugin-contract/run.ts
Comment thread plugins/brains/generated/capability-catalog.json

@stefan-ssv-labs stefan-ssv-labs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed against BRNS-MCP-048's requirement: the plugin skill text may only advertise direct execution ("may execute") once every production MCP replica already runs the SHA that implements it (BRNS-MCP-045 / brains#1270).

Content correctness — independently reproduced, not just trusted. I checked out ssvlabs/brains at the pinned source_commit (e332512644b2f06a6b7068dcc9196eab2d31c05a, confirmed to be the real stagemain merge commit for #1296) in a disposable worktree and ran apps/mcp/scripts/generate-capability-catalog.ts --check --plugin-root <this PR's worktree> --source-commit e332512644b2f06a6b7068dcc9196eab2d31c05a. All 18 generated outputs — including all three republished SKILL.md files and capability-catalog.json — came back fresh, i.e. byte-identical to what's committed here. Worth noting: scripts/generated-artifact-guard.sh's own header explicitly documents that it cannot prove the artifact bytes came from the monorepo generator (private repo, no cross-repo automation) — this reproduction is what closes exactly that gap.

Rollout ordering — the hard requirement. Live production kubectl wasn't available to me in this session, so I confirmed via GitOps instead: gitops-production's main HEAD (ed4a812c, "Updated brains docker images to 656828d28...", committed 2026-08-11T11:43:57Z) targets an image tag that is a confirmed git descendant of the pinned e332512644..., and the brains-production ArgoCD Application (environments/aws/brains.yaml) tracks targetRevision: HEAD with syncPolicy.automated.{prune,selfHeal}: true — no manual sync gate. That's desired-state + auto-sync-policy evidence rather than a live pod read, but it independently corroborates the ordering claim in the PR description.

Test hardening. Read the new WRITE_ACTION_CONTRACT_REGION whole-region pin in tests/plugin-contract/run.ts against the actual rendered text — it correctly captures the current direct-execution behavior (allowlist + per-user opt-in + eligible-client-class gate, not a blanket claim), reuses the existing normalizeRegion helper rather than inventing new comparison logic, and runs after the per-rule includes() checks so a specific rule failure still names itself first. The boundary anchors (Discover with … opener, | \kind` |` table header) are structural rather than editorial, so a reword of the prose between them won't silently move the pin.

Out of scope, correctly. The automation/sandbox-face self-contradiction this PR's description flags (packages/capability-catalog/render.ts / sandbox-catalog.ts in ssvlabs/brains still describing requires_confirmation:false as unconditionally inline, without the allowlist/opt-in nuance the brains-write face already carries) is real — I cross-checked both source locations against this PR's diff. It's already tracked as BRNS-MCP-052 and isn't fixable in this repo (these are rendered, not hand-authored, here), and this PR's own brains-automation/SKILL.md change is an unrelated write_policy:'auto_confirm_safe' addition that doesn't touch or worsen it.

CI is green on this exact head (cross-client plugin contract, generated-artifact + delivery guard, inbox-v2 contract test, tool-error contract test).

No blockers or critical issues. Approving.

@olegshmuelov

Copy link
Copy Markdown
Contributor Author

@stefan-ssv-labs thanks — regenerating from the pinned commit yourself is the check that actually closes the gap the delivery guard documents about itself, and the GitOps evidence is a better ordering proof than my pod read, since it shows the sync policy rather than a moment in time.

One correction on the out-of-scope note, so BRNS-MCP-052 doesn't get picked up on the wrong premise. The upstream defect isn't requires_confirmation:false being described as unconditionally inline — that description is correct for automations, and the allowlist/opt-in nuance can't apply there at all, because automations are hard-excluded from direct execution (direct-exec-eligibility.ts:42 returns false whenever automationId/formId is set).

The contradiction is on the true branch. render.ts:211 says a confirmation-required action "therefore waits for the human at /inbox", which is false when the owner set write_policy:'auto_confirm_safe' — exactly the case this PR's new contract sentence now describes correctly. sandbox-catalog.ts:91's Send row has the same gap.

That's also why this PR does slightly worsen that file's internal consistency rather than leaving it untouched: it corrects the contract sentence and leaves those two, so the artifact goes from consistent-and-wrong to half-corrected. Both are rendered, so neither is fixable here — the ticket carries the fix plus the automation region pin Sebastian asked for.

@olegshmuelov
olegshmuelov merged commit 3505891 into main Aug 11, 2026
4 checks passed
@olegshmuelov
olegshmuelov deleted the chore/sync-brains-build-2026-08-10 branch August 11, 2026 13:08
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.

3 participants