Add attendee transformation workflows

This commit is contained in:
2026-07-01 11:10:36 +02:00
parent 92e359646b
commit 5c67738939
23 changed files with 694 additions and 123 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-01
@@ -0,0 +1,30 @@
# Design
## Event Model
Add a workflow event type, `attendee_added`, that carries the attendee string being added. The event is used as a transformation hook before a caller stores the attendee in the meeting note. Rules can match the event with `equals`, `contains`, or `regex` trigger filters over the current attendee value.
## Transformation Contract
The workflow engine exposes `TransformAttendeeAsync`, mirroring `TransformTranscriptLineAsync`. During `attendee_added` events:
- conditions can read `attendee.name`,
- Razor templates can read `Model.Attendee.Name`,
- `set_property attendee.name` mutates the attendee value returned to the caller.
Other workflow steps keep their existing semantics, but the intended transformation path is `set_property attendee.name`.
Rules triggered by `attendee_added` are limited to that transformation path so the value transform does not hide unrelated note or context side effects.
Direct meeting note file edits remain outside the workflow event model. If a user or agent writes a meeting note file/frontmatter directly, Meeting Assistant preserves that content verbatim and does not emit `attendee_added`.
## Call Sites
Callers transform attendee candidates before writing them:
- metadata and accepted prompt metadata after canonicalization,
- workflow `add_attendee` steps before de-duplication,
- screenshot OCR candidates before canonicalization and merge,
- summary-agent `add_attendee` tool calls before duplicate checks and note writes,
- speaker identity attendee additions before adding matched names.
Unchanged metadata attendees preserve the existing canonicalizer output, including email display strings.
@@ -0,0 +1,17 @@
## Why
Attendees enter Meeting Assistant from several paths: calendar metadata, accepted recording prompts, workflow actions, screenshot OCR, speaker identity updates, and summarizer add-attendee tools. Today those paths can normalize display names, but they cannot apply local transformation rules such as trimming company suffixes, replacing aliases, or cleaning attendee strings consistently.
## What Changes
- Add an `attendee_added` workflow trigger that runs whenever Meeting Assistant adds an attendee to a meeting note.
- Allow `attendee_added` triggers to filter the added attendee with full equality, substring, or regex matching.
- Expose `attendee.name` to workflow conditions and Razor templates.
- Allow `set_property` to update `attendee.name` during `attendee_added` events, mirroring transcript-line transformation.
- Apply attendee transformations to attendees added by metadata import, prompted-start metadata, workflow `add_attendee`, screenshot OCR, and summary/workflow editor agent tools.
## Impact
- Workflow engine, rules schema validation, and workflow documentation.
- Attendee write paths in recording metadata, screenshot OCR, summary tools, and workflow actions.
- Behavior tests for workflow transformation and representative attendee-add sources.
@@ -0,0 +1,29 @@
## MODIFIED Requirements
### Requirement: Meeting automation rules support lifecycle triggers
Meeting Assistant SHALL support rule triggers for `created`, `state_transition`, `speaker_identified`, `transcript_line`, and `attendee_added`.
An `attendee_added` trigger MAY filter by `equals`, `contains`, or `regex` against the attendee value being added. `equals` and `contains` filters SHALL match case-insensitively.
Meeting Assistant SHALL apply attendee-added transformations before storing attendees added from meeting metadata, accepted recording-prompt metadata, workflow `add_attendee` steps, screenshot OCR, speaker identity updates, and summarizer add-attendee tools.
#### Scenario: Attendee added rule filters and transforms a metadata attendee
- **GIVEN** a configured rule that triggers on added attendees containing `@contoso.com`
- **AND** the rule sets `attendee.name` to a display name derived from the added attendee
- **WHEN** Meeting Assistant adds attendee `Ada Lovelace <ada@contoso.com>` from meeting metadata
- **THEN** the stored meeting attendee is the transformed attendee name
- **AND** the original attendee string is not stored
### Requirement: Meeting automation rules support conditions and steps
Meeting Assistant SHALL expose the added attendee name to `attendee_added` rule conditions and Razor step templates as `attendee.name`.
The `set_property` step SHALL support setting `attendee.name` during `attendee_added` events.
Rules with an `attendee_added` trigger SHALL be limited to transforming `attendee.name` with `set_property`.
Direct meeting note file writes SHALL NOT emit `attendee_added` or transform attendee values.
#### Scenario: Attendee added rules can use regex and Razor
- **GIVEN** a configured `attendee_added` rule with a regex filter over the added attendee
- **WHEN** Meeting Assistant adds an attendee matching the regex
- **THEN** the rule can set `attendee.name` with a Razor template using `Model.Attendee.Name`
@@ -0,0 +1,8 @@
# Tasks
- [x] Add OpenSpec scenarios for attendee-added trigger filtering and transformation.
- [x] Add a failing workflow-engine behavior test for transforming an added attendee through `attendee_added`.
- [x] Implement attendee-added workflow event, trigger filters, `attendee.name` condition/template value, and `set_property attendee.name`.
- [x] Apply attendee transformations from metadata/prompted starts, workflow `add_attendee`, screenshot OCR, and agent attendee tools.
- [x] Update workflow engine documentation.
- [x] Run focused tests plus `openspec validate transform-added-attendees --strict`.
+17 -90
View File
@@ -221,105 +221,32 @@ Meeting Assistant SHALL expose a diagnostic endpoint that reloads application co
- **AND** future workflow events use the reloaded workflow automation configuration
### Requirement: Meeting automation rules support lifecycle triggers
Meeting Assistant SHALL support rule triggers for `created`, `state_transition`, `speaker_identified`, and `transcript_line`.
Meeting Assistant SHALL support rule triggers for `created`, `state_transition`, `speaker_identified`, `transcript_line`, and `attendee_added`.
A `state_transition` trigger MAY filter by `from`, `to`, or both state values.
An `attendee_added` trigger MAY filter by `equals`, `contains`, or `regex` against the attendee value being added. `equals` and `contains` filters SHALL match case-insensitively.
A `speaker_identified` trigger MAY filter by speaker name.
Meeting Assistant SHALL apply attendee-added transformations before storing attendees added from meeting metadata, accepted recording-prompt metadata, workflow `add_attendee` steps, screenshot OCR, speaker identity updates, and summarizer add-attendee tools.
A `transcript_line` trigger MAY filter by speaker name.
Workflow rule execution SHALL log each triggered rule with its rule name and event type.
Workflow rule execution SHALL log rule failures with the rule name and event type.
#### Scenario: State transition rule matches from and to
- **GIVEN** a configured rule that triggers on a state transition from `collecting metadata` to `transcribing`
- **WHEN** Meeting Assistant transitions that meeting from `collecting metadata` to `transcribing`
- **THEN** it applies the rule steps
#### Scenario: Speaker identified rule filters by name
- **GIVEN** a configured rule that triggers when speaker `Ada` is identified
- **WHEN** Meeting Assistant identifies speaker `Grace`
- **THEN** it does not apply the rule
- **WHEN** Meeting Assistant identifies speaker `Ada`
- **THEN** it applies the rule steps
#### Scenario: Transcript line rule rewrites masked profanity after durable append
- **GIVEN** a configured rule that triggers on transcript line writes and sets `transcript.line` by replacing `*****` with `[redacted]`
- **WHEN** Meeting Assistant writes a transcript line for speaker `Guest-1` containing `*****`
- **THEN** Meeting Assistant first appends the original formatted line to the transcript file
- **AND** rewrites that written line to contain `[redacted]`
- **AND** the final written transcript line does not contain `*****`
#### Scenario: Transcript line workflow failure keeps transcript writing
- **GIVEN** a configured transcript line workflow rule fails while processing a transcript line
- **WHEN** Meeting Assistant receives that live transcript segment
- **THEN** Meeting Assistant keeps the original formatted line in the transcript file
- **AND** logs the workflow rule failure
- **AND** continues processing later transcript segments
#### Scenario: Attendee added rule filters and transforms a metadata attendee
- **GIVEN** a configured rule that triggers on added attendees containing `@contoso.com`
- **AND** the rule sets `attendee.name` to a display name derived from the added attendee
- **WHEN** Meeting Assistant adds attendee `Ada Lovelace <ada@contoso.com>` from meeting metadata
- **THEN** the stored meeting attendee is the transformed attendee name
- **AND** the original attendee string is not stored
### Requirement: Meeting automation rules support conditions and steps
Meeting Assistant SHALL support rule conditions using an expression engine.
Meeting Assistant SHALL expose the added attendee name to `attendee_added` rule conditions and Razor step templates as `attendee.name`.
Rules SHALL support nested `and`, `or`, and `not` condition groups.
The `set_property` step SHALL support setting `attendee.name` during `attendee_added` events.
Step values SHALL support Razor syntax against the current meeting event model.
Rules with an `attendee_added` trigger SHALL be limited to transforming `attendee.name` with `set_property`.
Rendered step values SHALL be treated as plain UTF-8 text for markdown artifacts and SHALL NOT persist Razor HTML entity encoding.
Direct meeting note file writes SHALL NOT emit `attendee_added` or transform attendee values.
Step values SHALL treat `@` characters inside valid email address tokens as literal text rather than Razor transitions.
Meeting Assistant SHALL expose the formatted transcript line and transcript speaker to `transcript_line` rule conditions and Razor step templates.
Meeting Assistant SHALL support these initial rule steps:
- `add_attendee`
- `remove_attendee`
- `set_property`
- `add_context`
- `add_project`
The `set_property` step SHALL support setting `transcript.line` during `transcript_line` events.
#### Scenario: Nested conditions choose a matching rule
- **GIVEN** a configured rule with nested `and`, `or`, and `not` conditions over meeting title, attendees, and event data
- **WHEN** the condition evaluates to true
- **THEN** Meeting Assistant applies the rule
- **WHEN** the condition evaluates to false
- **THEN** Meeting Assistant skips the rule
#### Scenario: Templated context mentions identified speaker
- **GIVEN** a configured `speaker_identified` rule with an `add_context` step using Razor syntax
- **WHEN** Meeting Assistant identifies matching speaker `Ada`
- **THEN** it appends rendered context text containing `Ada` to the assistant context note
#### Scenario: Email addresses do not trigger Razor templating
- **GIVEN** a configured rule step value containing `Support@contoso.com`
- **WHEN** the rule runs
- **THEN** Meeting Assistant preserves the email address as literal text
#### Scenario: Email addresses can appear beside Razor templating
- **GIVEN** a configured rule step value containing both `Support@contoso.com` and a Razor expression
- **WHEN** the rule runs
- **THEN** Meeting Assistant renders the Razor expression and preserves the email address as literal text
#### Scenario: Razor-rendered transcript line preserves UTF-8 text
- **GIVEN** a configured `transcript_line` rule uses Razor to replace part of a transcript line containing `heißt`, `Schimpfwörter`, and `nächstes`
- **WHEN** the rule changes `transcript.line`
- **THEN** the resulting transcript line contains the original UTF-8 characters
- **AND** does not contain HTML entities such as `&#xDF;`, `&#xF6;`, or `&#xE4;`
#### Scenario: Rule can clean a meeting title
- **GIVEN** a configured state-transition rule that matches a title containing a configured marker
- **WHEN** the rule runs
- **THEN** Meeting Assistant can update the meeting title through `set_property`
#### Scenario: Transcript line conditions can use the written line and speaker
- **GIVEN** a configured `transcript_line` rule with conditions over `transcript.line` and `transcript.speaker`
- **WHEN** Meeting Assistant writes a transcript line that matches both conditions
- **THEN** Meeting Assistant applies the rule steps after the original formatted line is durably appended
- **AND** rewrites the written line if a rule changes `transcript.line`
#### Scenario: Attendee added rules can use regex and Razor
- **GIVEN** a configured `attendee_added` rule with a regex filter over the added attendee
- **WHEN** Meeting Assistant adds an attendee matching the regex
- **THEN** the rule can set `attendee.name` with a Razor template using `Model.Attendee.Name`
### Requirement: Workflow rules and speaker identities can be edited through a tray-launched assistant
Meeting Assistant SHALL expose an `Open agent` item from the tray icon menu.