Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 255 additions & 0 deletions docs/governance/design-Intent-classification-and-routing.md

Large diffs are not rendered by default.

100 changes: 100 additions & 0 deletions docs/governance/design-ux-progressive-selection-UI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Progressive Selection UI — Architecture & Design

## Status
This is the universal, project-agnostic design standard for the **web/mobile page-level UI**
scaffold that hosts a Progressive Selection Chat surface (see
`docs/governance/design-ux-progressive-selection-chat.md`, which this document assumes and does
not repeat). This document covers layout, component boundaries, and responsive behavior — not the
chat protocol itself. Product-specific detail belongs in that solution's own product
documentation.

## Problem Statement

A single chat page must serve two audiences at once: someone picking up a prior conversation
(session history) and someone actively working a guided hierarchy descent (message list +
selection chips + suggested prompts + composer). The layout must work identically in narrow
(mobile) and wide (desktop) viewports without diverging behavior, and must never require a page
navigation to move between hierarchy levels — the entire journey happens inside one page.

## Core Principles

1. **One page hosts the entire journey.** Selecting a kit, an instance, a parallel artifact branch,
and a leaf record all happen without route changes. The page is a shell around: session
picker, message history, action/selection chips, suggested prompts, and composer. Routing to a
dedicated per-entity page is reserved for the CRUD/admin experience, not the chat journey.
2. **Breakpoint-driven layout, not device-detection.** Layout responds to a measured grid
breakpoint (e.g., narrow vs. standard), not user-agent sniffing. Both layouts render the same
five regions in the same top-to-bottom order; only proportions/placement (stacked strip vs.
side list) differ.
3. **Five stable regions, always present in this order:**
- **Session control** — start a new session; access session history.
- **Header / orientation** — a constant reminder of the page's purpose ("What can I help you
with?").
- **Message history** — scrollable, bounded height, auto-scrolls to newest message on new
content.
- **Action strip** — the current selection chips (see selection-token contract in the chat
governance doc), directly above the composer.
- **Composer + suggested prompts** — the input control immediately followed by the
context-derived suggested-prompt buttons, so the two "ways to advance the journey" (type vs.
tap a suggestion) are visually adjacent.
4. **Session switching resets journey context.** Choosing a different session or starting a new
one must clear all accumulated selection state (active kit/instance/branch/leaf) and pending
action chips — a session boundary is also a context boundary.
5. **The message list re-derives chips on every refresh, not just once.** After any message is
sent or a session is (re)loaded, the UI re-scans the latest assistant reply for selection
tokens and rebuilds the action strip and suggested prompts from that scan — chips are a
projection of the latest reply, never independently persisted UI state.
6. **Scroll-to-latest is an explicit, page-owned behavior.** The page, not the message list
component, owns the "should scroll to bottom" flag and triggers it after render whenever new
content arrives (new message, new session, session switch).
7. **Chips and suggestions are ephemeral per turn.** Selection chips are cleared immediately when
acted upon (before the resulting message round-trip resolves) to prevent double-submission and
to avoid presenting stale, already-resolved options while a new reply is in flight.
8. **No client-side business logic duplication.** The page composes existing tool/service replies;
it must not re-derive domain state (e.g., recompute execution status) that a tool call already
returned. UI logic is limited to: session bookkeeping, breakpoint layout, token parsing for
chips, and suggested-prompt selection based on locally-tracked context ids.

## Component Boundaries

- **Page (shell)**: owns session state, active-context ids (kit/instance/branch/leaf), pending
action chips, breakpoint flag, scroll-flag, and orchestrates calls to the chat service.
- **Session list/strip**: pure presentation of available sessions; emits a selection event only.
- **Message list**: pure presentation of the conversation; owns only the regex-based extraction of
selection tokens for its own rendering needs (e.g., stripping tokens from displayed text), not
for building the action strip (that responsibility stays with the page so it can coordinate with
submitted-context state).
- **Action strip**: stateless renderer of the chips the page hands it; emits a click event with the
full selection payload (kind/id/value/label) and takes no action itself.
- **Suggested-prompts strip**: stateless renderer of prompt strings computed by the page; emits the
clicked string verbatim as the next submitted message.
- **Composer (input or card variant)**: the only component that talks directly to the chat
service to create a session or submit a message; both mobile and desktop layouts wrap the same
submission API so the page can drive either variant without branching its own logic beyond
choosing which ref to call.

## Responsive Layout Rules

- Narrow layout: session control and session strip stack full-width above the header; message
history, action strip, and composer/suggestions stack full-width below.
- Standard/wide layout: session control and session list occupy a persistent side column; message
history occupies a wide center column; action strip and composer/suggestions occupy a matching
wide column beneath the message history, vertically aligned with it.
- Both layouts must present the same maximum message-history height with independent scrolling
(never let the whole page scroll to reveal older messages — only the history region scrolls).

## Anti-Patterns to Avoid

- Navigating to a different route to represent progression through the hierarchy — this breaks the
"single continuous conversation" mental model the chat pattern depends on.
- Persisting selection chips independently of the latest assistant reply (leads to stale/duplicate
chips after a session switch or new reply).
- Device-specific business logic branches beyond the composer variant used.
- Letting the message-history component own submission or context-tracking responsibilities that
belong to the page shell.

## Applicability

This layout scaffold applies to any product page, in any solution built from this template,
hosting a chat-driven guided journey. Reuse this five-region, breakpoint-driven structure rather
than inventing a new page layout per product.
134 changes: 134 additions & 0 deletions docs/governance/design-ux-progressive-selection-chat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Progressive Selection Chat — Architecture & Design

## Status
This is the universal, project-agnostic design standard for the **AI agent chat experience**
pattern used to walk a user down a hierarchical resource tree (definition → instance →
sub-resource → leaf) purely through conversational turns. It applies to any Microsoft Agent
Framework (MAF) / Microsoft.Extensions.AI (MEAI) based chat surface, in any solution built from
this template. Product-specific detail (the concrete hierarchy levels, tool names, and phrasing
for a given solution) belongs in that solution's own product documentation — read the applicable
product-specific journey document alongside this one, not instead of it.

This document assumes familiarity with
`docs/governance/design-Intent-classification-and-routing.md`. That document governs how a
free-form message resolves to a tool call; this document governs what a tool call **returns** and
how the chat surface turns that return value into the next step of a guided journey.

## Problem Statement

Many products in this ecosystem expose data as a **hierarchy**: a top-level catalog of
definitions, each with many runtime instances, each instance producing multiple parallel
sub-resources, each sub-resource containing many leaf records. A user rarely wants to type a GUID.
They want to be walked, level by level, from "what exists" down to "the specific leaf record I
care about," using natural language and lightweight taps/clicks, without losing conversational
context between levels.

This is the **Progressive Selection Chat** pattern: an agent chat surface that (1) always shows the
user what can be selected at the current level, (2) lets a single click/tap or short phrase advance
to the next level, (3) silently carries forward selected-context so the user never has to repeat an
identifier, and (4) exposes level-appropriate suggested prompts that change as context narrows.

## Core Principles

1. **The hierarchy is the journey, not the entity list.** Do not design chat tools around "CRUD
for entity X." Design them around "what is the next question a user asks after selecting the
previous level." A tool's response should always answer that next question or offer the means
to ask it.
2. **Selection is a first-class response artifact, not prose.** When a tool response enumerates
selectable children, it must emit a machine-parseable **selection token** for each one, in
addition to human-readable markdown. The UI parses these tokens into clickable chips
independent of exact wording, so selection works even when the model paraphrases the
surrounding text.
3. **Context accumulates and narrows scope automatically.** Selecting an item at level N sets an
"active context" server-side (e.g., active pipeline, active execution, active timeline) that
subsequent tool calls read implicitly. The user is never asked to repeat an id they already
selected. Explicit ids remain a supported override for direct/deep-linked requests.
4. **Suggested prompts are context-derived, not static.** The set of suggested next prompts shown
beneath the composer must be computed from current selection state (nothing selected → top of
hierarchy prompts; kit selected → instance-level prompts; instance selected → sub-resource
prompts; sub-resource selected → leaf-level prompts). This keeps the surface useful without
requiring the user to recall tool names.
5. **Every response ends with a "next suggested action."** A tool's markdown reply should
explicitly state what a user would logically do next ("show chronicles or timelines for the
selected execution"), reinforcing the guided-descent shape of the journey even for users typing
free-form text instead of clicking chips.
6. **Parallel siblings are presented together, not hidden behind a single path.** Where a level has
more than one class of child that a user would reasonably want to view side-by-side (e.g., a
narrative summary artifact and a raw event-stream artifact produced from the same run), the
response/journey should surface both as parallel, independently selectable branches rather than
forcing a single linear order.
7. **The chat surface is single-turn stateless from the model's perspective; state lives in
context, not conversation replay.** Long-running or asynchronous actions (e.g., "run this")
must not promise future proactive notification — the assistant has no channel to push updates.
Replies must say plainly that the user should send a new message to check status.
8. **Selection is idempotent and re-selectable.** Clicking a chip for an already-active selection,
or starting a new chat session, must cleanly reset/replace context rather than accumulate stale
state.

## Selection Token Contract

A tool response that offers selectable children emits one token per child using a stable,
delimiter-based grammar that is trivial to parse with a single regular expression and is resilient
to the model rephrasing surrounding prose:

```
[selection|<kind>|<id>|<value>|<label>]
```

- `kind` — the level/type of the thing being selected (e.g., `pipeline`, `execution`, `timeline`).
- `id` — the stable identifier used to re-query this item (GUID, code, canonical key).
- `value` — an optional secondary value (CURI, canonical key) carried for downstream tool calls.
- `label` — the human-readable chip label.

Rules for this contract:
- Tokens are additive to markdown, never a replacement for it — the markdown table/list remains
the source of truth for what a human reads; tokens are only for UI chip extraction.
- The UI-side parser must be permissive of the model surrounding the token with arbitrary prose,
and must degrade gracefully (no chips rendered, plain text still shown) if a token is malformed
or absent.
- A generic per-`kind` prompt-builder (e.g., "Select pipeline `{id}`") must exist so new `kind`
values can be introduced without UI code changes, with an explicit fallback for unrecognized
kinds.

## Suggested Prompts Contract

Suggested prompts are a pure function of accumulated selection context, evaluated client-side or
server-side every time context changes:

- No selection → prompts that enumerate the top of the hierarchy and orient a first-time user.
- Level 1 selected (kit/definition) → prompts that reveal level 2 (instances) and the
definition's own descriptive sub-views (its declared shape/plan/config).
- Level 2 selected (instance/run) → prompts that reveal both parallel level 3 branches together.
- Level 3 selected (a specific parallel branch) → prompts that reveal level 4 (leaf records) scoped
to that branch.

This list must be short (3–4 items), action-oriented, and phrased as the literal sentence the tool
router expects, so a click reliably resolves to the same tool call a typed phrase would.

## Action Chip Contract

Selection chips and suggested-prompt buttons are visually distinct but behave identically: both
ultimately submit a phrase into the same message pipeline used for typed input. Do not create a
separate code path for "chip click" vs. "typed message" beyond constructing the phrase — this
guarantees intent routing, context updates, and reply rendering stay consistent regardless of
input method. Once a chip is acted on, it must be cleared from the strip so stale, already-resolved
selections are not offered again after the assistant's next reply.

## Anti-Patterns to Avoid

- Requiring the user to know or type a GUID/id to move between levels when a prior response already
offered a chip for it.
- Tool responses that describe children in prose only, without emitting selection tokens.
- Suggested prompts that remain static regardless of context — this defeats the purpose of guided
descent and reintroduces a "remember the tool name" burden on the user.
- Promising asynchronous follow-up ("I'll let you know when it's done") from a stateless,
single-turn chat surface.
- Collapsing parallel sibling branches into a forced single linear path when the underlying data
model treats them as independent, co-equal views of the same instance.

## Applicability

This pattern applies to any product built from this template that exposes a definition → instance
→ parallel-artifact → leaf-record hierarchy through an MAF/MEAI chat surface. Implementers should
reuse the selection-token grammar, the context-accumulation model, and the suggested-prompt-by-level
contract rather than inventing a bespoke variant per product.
96 changes: 96 additions & 0 deletions docs/governance/pipeline-governance-principles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Pipeline Governance Principles (Static, Product-Wide)

## Purpose

Define a durable, reusable governance lock for pipeline systems with four mandatory principles:

1. Observability
2. Auditability
3. Defensibility
4. Repeatability

## Principle Definitions

- **Observability**: every execution path must be traceable with evidence references.
- **Auditability**: ownership/tenant and tool use must be attributable.
- **Defensibility**: applied policy and justification context must be preserved.
- **Repeatability**: the same inputs and configuration must be replayable and verifiable.

## Durable Lock Model

`GovernanceProfile` is the shared contract used across products:

- `PolicyProfileVersion`
- `ObservabilityRequired`
- `AuditabilityRequired`
- `DefensibilityRequired`
- `RepeatabilityRequired`
- deterministic `GovernanceLockHash` (SHA-256 of the profile)

The lock hash is used to detect drift/tampering and to verify cross-entity governance alignment.

## Governed Evaluation Output Schema (Required)

In addition to entity-level governance locks, evaluate-stage outputs must use a deterministic governed schema:

- `overall_score` (0-100)
- `overall_level`
- `overall_confidence` (0-1)
- `defensibility_summary`
- `criteria[]` with required fields:
- `name`
- `score` (0-100)
- `level`
- `justification`
- `evidence`
- `rubric_reference`
- `confidence` (0-1)
- `uncertainty_flag`
- `defensibility`
- `strengths[]`
- `weaknesses[]`
- `recommendations[]`
- `audit_trace`:
- `model_version`
- `rubric_version`
- `timestamp_utc`
- `evaluation_id`

This schema is represented by `GovernedEvaluationOutputSchema` and validated at runtime before record-stage persistence.

## Hard-Persisted Fields

The following persisted entities must contain governance lock fields:

- `PipelineEntity`
- `GovernancePolicyProfileVersion`
- `GovernanceObservabilityRequired`
- `GovernanceAuditabilityRequired`
- `GovernanceDefensibilityRequired`
- `GovernanceRepeatabilityRequired`
- `GovernanceLockHash`
- `PlaybookEntity`
- `GovernancePolicyProfileVersion`
- `GovernanceObservabilityRequired`
- `GovernanceAuditabilityRequired`
- `GovernanceDefensibilityRequired`
- `GovernanceRepeatabilityRequired`
- `GovernanceLockHash`

## Non-Bypass Rules

- Pipeline and playbook creation/update must apply governance from authoritative pipeline kit registration.
- Governance flags must remain fully required for all four principles.
- Read and execute paths must validate governance hash integrity.
- Pipeline execution must reject playbooks whose governance profile/hash does not match pipeline governance.

## Reuse Guidance

This model is intentionally product-agnostic:

- Keep `GovernanceProfile` in shared core libraries.
- Allow each product to choose profile versions (for example `*.v1`, `*.v2`) while preserving hash semantics.
- Use the same lock profile contract for:
- agent-framework quick starts
- semantic-kernel quick starts
- any orchestrated multi-step pipeline/runtime.
2 changes: 2 additions & 0 deletions src/Core.Application/Abstractions/IAgentFrameworkContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Goodtocode.AgentFramework.Core.Domain.Actors;
using Goodtocode.AgentFramework.Core.Domain.Chats;
using Goodtocode.AgentFramework.Core.Domain.Common;
using Goodtocode.AgentFramework.Core.Domain.Governance;
using Microsoft.EntityFrameworkCore.Metadata;

Expand All @@ -9,6 +10,7 @@ public interface IAgentFrameworkContext
{
DbSet<ChatMessageEntity> ChatMessages { get; }
DbSet<ChatSessionEntity> ChatSessions { get; }
DbSet<RequestIdempotencyEntity> RequestIdempotency { get; }
DbSet<ActorEntity> Actors { get; }
DbSet<ChatGovernanceEntity> ChatGovernance { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Goodtocode.AgentFramework.Core.Application.Abstractions;
/// Resolves an assistant reply while keeping chat presentation, intent routing, and AI integration
/// outside application command and query handlers.
/// </summary>
public interface IChatMessageRoutingService
public interface IChatMessageRouter
{
/// <summary>
/// Resolves the reply for <paramref name="message"/> in the specified chat session.
Expand Down
Loading
Loading