Skip to content

Proposal: host-rendered multi-Session presentation and facet-local requirements #18

Description

@xlennart

Summary

While adapting KarlOfLaw/dsh-side-chat as a portable dsh-std consumer, I found one browser UI protocol gap and two manifest-model gaps:

  1. there is no host-rendered surface for presenting more than one named Session;
  2. executable browser code is represented indirectly as a LocalModule extension instead of a first-class facet with its own lifecycle;
  3. Community v0.15 root requires.contracts[] cannot retain a protocol-owned spec, so a consumer cannot statically require an operation subset or exact surface properties.

The current plugin deliberately does not publish a root dsh-plugin.json: the existing coordinates would produce an incomplete compatibility claim. I have an executable consumer-side state model and acceptance fixtures and would like to contribute them after the protocol direction is agreed.

Concrete consumer requirement

Side Chat presents a second durable Session beside the current Session while preserving the host's native conversation renderer, input routing, attachments, approvals, questions, model selection, and session-scoped contributions.

This cannot be implemented as a generic plugin-rendered panel without duplicating product UI and interaction behavior. The portable boundary should let a component request presentation membership and focus while the host remains the renderer and interaction owner.

Proposed UI surface

Candidate coordinate:

browser.ui.dsh/v1alpha1 SessionPresentation

Candidate mode:

host-rendered

The minimum observable state would be:

interface SessionPresentationState {
  readonly visible: readonly SessionReference[]
  readonly focused?: SessionReference
  readonly capacity: number
  readonly overCapacity: boolean
}

The minimum controller would support typed open, focus, and close outcomes plus an effect-owned requestCapacity lease.

Required semantics:

  • visible MUST be unique and ordered; changing focus MUST NOT reorder membership.
  • Every rendered pane MUST bind to its explicit Session reference, not a global current/focused Session.
  • Send, upload, model selection, question, approval, and cancellation operations MUST capture that Session identity before the first asynchronous boundary.
  • At capacity greater than one, session-scoped contributions MUST be instantiated once per visible Session under the corresponding provider.
  • Capacity reduction MUST be admission-only: it MUST NOT evict an already visible Session.
  • Closing a presentation MUST only remove presentation membership. It MUST NOT cancel, archive, or delete the durable Session.
  • An open request while full MUST return a typed refusal or an explicitly requested replacement outcome; it MUST NOT silently replace another pane.
  • Activation/unload MUST own and release registrations and capacity leases.

A contribution could remain inert JSON, for example:

ui.register({
  descriptor: {
    id: 'dsh-side-chat',
    surface: {
      apiVersion: 'browser.ui.dsh/v1alpha1',
      kind: 'SessionPresentation',
    },
    placement: 'session.secondary',
    content: {
      role: 'peer-conversation',
      minimumCapacity: 2,
      namedSessionBinding: true,
      sessionScopedMultiplicity: 'per-visible-session',
      asyncInteractionIdentity: 'capture-at-initiation',
    },
  },
})

The adapter would validate this descriptor and supply the actual native controller. No React component or product-runtime object would cross the protocol boundary.

Manifest gap exposed by this consumer

Community v0.15 root requires.contracts currently accepts the protocol coordinate and optional/fallback flags, but not a protocol-specific requirement spec. A consumer can therefore name SessionCatalog without expressing that it needs get and create, or name ContributionHost without requiring the exact host-rendered surface above.

For the next breaking Community manifest revision, I propose considering named first-class facets:

{
  "facets": [
    {
      "name": "browser",
      "runtime": "browser",
      "activation": {
        "apiVersion": "browser.ui.dsh/v1alpha1",
        "kind": "LocalModule",
        "module": "dist/std/client.mjs"
      },
      "requires": {
        "contracts": [
          {
            "apiVersion": "ui.dsh/v1alpha1",
            "kind": "ContributionHost",
            "spec": {
              "surfaces": [
                {
                  "apiVersion": "browser.ui.dsh/v1alpha1",
                  "kind": "SessionPresentation",
                  "mode": "host-rendered",
                  "spec": { "minimumCapacity": 2 }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

The manifest layer SHOULD validate that a requirement spec is JSON data and preserve it unchanged. The selected protocol validator SHOULD own its interpretation. An adapter MUST reject an unsatisfied required spec before importing the facet module.

Making host and browser modules peer facets would also give each executable unit independent negotiation, activation diagnostics, cleanup, and optional-runtime behavior. A headless host could decline the browser facet without invalidating an otherwise portable host facet.

The exact manifest version number and field spelling are open; 2.0 here means “next breaking Community manifest”, not a version of SessionPresentation or of the consumer plugin.

Relationship to existing Session work

This proposal does not make presentation responsible for creating or controlling Sessions.

Side Chat also needs an empty related-session operation that preserves parent, workspace, and Agent/Preset configuration, plus session-scoped submit/cancel/resume operations. Those requirements overlap the portable Session runtime discussion in #11 and should remain in Session/Agent/Workspace protocols rather than becoming product fields in SessionPresentation.

Initial conformance cases

I can contribute product-neutral fixtures covering:

  1. unique and stable visible membership;
  2. focus changes without reordering;
  3. typed, non-destructive open-while-full behavior;
  4. right-then-left focus selection when closing the focused pane;
  5. max-wins capacity leases;
  6. admission-only capacity shrink without eviction;
  7. named Session identity across asynchronous interaction initiation;
  8. per-visible-Session contribution multiplicity;
  9. refusal to activate when the exact host-rendered surface or required operations are unavailable;
  10. scope-owned registration and cleanup.

Questions

  • Does SessionPresentation fit as a new optional surface under browser.ui.dsh/v1alpha1 ContributionHost, or should native Session presentation use a separate capability?
  • Should capacity be part of the negotiated surface agreement, the runtime controller, or both?
  • For the next breaking manifest revision, would first-class runtime facets and protocol-owned requirement specs fit the current internal ComponentManifest direction?
  • Would maintainers prefer the UI protocol proposal and manifest-format proposal as two documents/PRs after this issue establishes direction?

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions