Skip to content

fix(backend-ad4m): consent and the model check follow ad4m #1167's user-session refusals - #281

Open
HexaField wants to merge 4 commits into
refactor/ad4m-onfrom
fix/user-session-consent
Open

HexaField wants to merge 4 commits into
refactor/ad4m-onfrom
fix/user-session-consent

Conversation

@HexaField

Copy link
Copy Markdown
Contributor

Important

Paired with: coasys/ad4m#1167

What

  • WE offers consent requests (approve an app's capabilities, trust a peer) only where it administers the node. A guest or a user on a multi-user node gets no consent prompts.
  • The default model's status reads unchecked, not error, when the executor refuses the model check (ai.discoverModels answers 403). It reads the RPC status, not the wording of the message.

Stacked on #227 (the SDK's on() API), which this needs to build against an ad4m with coasys/ad4m#1193.

Why

coasys/ad4m#1167 keeps user sessions on a multi-user node off calls that act on the node itself. Two of WE's surfaces still reached those calls:

Surface Call Before After
Consent prompt, Trust / Decline runtime.addTrustedAgents, runtime.deleteTrustedAgents Offered to every session. The executor raises "agent is untrusted" to all sessions (coasys/ad4m#1164), so a user saw the prompt, and both buttons failed with 403. Offered only with administersNode
Consent prompt, Approve app agent.permitCapability Needs AGENT PERMIT, which only the operator holds. Offered only with administersNode
Default model status ai.discoverModels #1167's refusal ("… acts on the node itself, so a user session may not call it") matched none of capabilit|forbidden|unauthori, so a user saw their working model marked broken. The same pattern also turned a provider's own "Unauthorized" into "unchecked". Unchecked on RpcError status 403; any other failure is an error

Everything else #1167 refuses was already gated in WE: backup export and import, languages, trusted agents, peers and AI model changes need administersNode; a user session always reports itself initialised and unlocked, so WE never offers it generate or unlock; the dev link-language publish runs only in Electron, where WE is the operator.

How

createAd4mRuntimeAdmin(client, { administersNode, capabilities })
  ├─ agentScoped     unsupported, onUnsupported              every session
  ├─ aiRead          aiModels, presets, status, tasks        AI READ granted
  ├─ aiWrite         add / update / remove / default         administersNode && AI CREATE
  └─ administersNode ? { ...nodeScoped, ...consent }         ← consent moved here
                         consent: onConsentRequest, approve, deny

The shell already skips consent when the port has no onConsentRequest (RuntimeStore.tsx), so no shell change is needed.

File Change
packages/backend-system/ad4m/src/runtimeAdminAdapter.ts Consent members move from agentScoped into a consent group, spread only with administersNode
packages/backend-system/ad4m/src/languageModelPort.ts err instanceof RpcError && err.status === 403 → unchecked
tests/runtimeAdminAdapter.test.ts Operator gets consent; a guest gets none of onConsentRequest, approve, deny
tests/languageModelPort.test.ts A 403 refusal reads unchecked; an endpoint's "Unauthorized" (500) reads error

Docs kept in sync

  • The docs this change touches are updated, or none applied

None applied: no doc describes which sessions get consent prompts; the adapter's own comments carry the rule.

Test plan

  • backend-ad4m tests for both files, against the SDK built from fix(api): keep user sessions off node operations; sign as the user ad4m#1167 (28/28)
  • Lint, CSS lint, format, build, typecheck and the full test suite, with @coasys/ad4m linked to the #1167 build
  • Manual, on a multi-user executor built from #1167: a user session in WE web gets no trust prompt and sees its default model as unchecked; the operator in WE Electron still gets and answers consent prompts

Changelog

none

— Hex, Josh's assistant ⬡

…ssion refusals

coasys/ad4m#1167 refuses calls that act on the node to a user session on a
multi-user node. Two WE surfaces still reached them:

- Consent prompts (approve an app, trust a peer) answer with
  agent.permitCapability and runtime.add/deleteTrustedAgents. They move from
  the agent-scoped group to a consent group offered only with
  administersNode, beside the other node-scoped controls.
- The default model's status treated a refused ai.discoverModels as an
  error, because #1167's message matched none of the keywords. It now reads
  RpcError status 403 as unchecked, and leaves an endpoint's own
  Unauthorized as an error.
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

✅ This PR works against coasys/ad4m#1167

Tested at f718c980a, merged with refactor/ad4m-on, against ad4m d3a559649.

The red required checks are only the ad4m pin. They clear once coasys/ad4m#1167 is
published and pnpm bump:ad4m moves the pin.

  • ✅ ad4m SDK
  • ✅ Build
  • ✅ Typecheck
  • ✅ Tests
  • ✅ Schemas and audits
  • ✅ Browser tests

The run · updated on every push

@github-actions github-actions Bot added the paired with ad4m Paired with an unpublished ad4m change: required checks stay red until the pin moves label Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

paired with ad4m Paired with an unpublished ad4m change: required checks stay red until the pin moves

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant