mail-address-semantics/workplans/MAS-WP-0013-harness-independent-flows.md
tegwick ecb1ba47f6 MAS-WP-0013 finished: mode contract flows runnable from the bundle alone
conformance/FLOWS.md defines setup, steps, captures and expectations, all
observable at the contract boundary. flows.json carries setups (peer ids),
fixed test keys, statute, scenario and explicit assign steps;
scenarios.json holds the callback scenarios (the stub loads them).
CONTRACT.md defines the case.assign response. Runner reads only the
bundle and rejects undefined keys; new flow s-006 (held over cap).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5787@bnt-lap001
Assistant-Session: 5db26b82-138b-40cc-9856-4d5eb0f752fd
2026-10-19 12:49:15 +02:00

81 lines
3.1 KiB
Markdown

---
id: MAS-WP-0013
type: workplan
title: "Mode contract flows independent of the Python harness"
domain: communication
repo: mail-address-semantics
status: finished
owner: claude
topic_slug: coulomb-social
created: "2026-10-19"
updated: "2026-10-19"
origin: residual
origin_ref: MAS-WP-0010
state_hub_workstream_id: "6d1d30c3-4373-59db-a6f6-d8a8ceb5fad9"
---
# Mode contract flows independent of the Python harness
Risk A in `history/2026-10-19T090725Z-scope-vs-intent.md`.
`mas-modes-v0.1-spec/conformance/flows.json` is language-neutral in
format, but it relies on harness details: the stub master assigns
`EXT-100`, `EXT-101`, ...; the role configuration is implied; and
expectation keys mirror `mas_modes.runner`. A second implementation could
not run the flows from the bundle alone.
## Make flows self-describing
```task
id: MAS-WP-0013-T01
status: done
priority: medium
state_hub_task_id: "95fe186c-d0af-5755-a78f-065e7da7afd1"
```
Write the inputs into each flow: role configuration, assigned ids, and
the stub scenarios. Define every expectation key in CONTRACT.md §7 or a
`conformance/FLOWS.md`, in terms of contract messages and sent mail only.
Remove any expectation that only the Python harness can observe.
## Runner follows the bundle
```task
id: MAS-WP-0013-T02
status: done
priority: medium
state_hub_task_id: "2e71569f-739a-513a-970f-0a0c867604d6"
```
Update `mas_modes.runner` and the stubs to read everything from the flow.
Keep `mas test` green. Add a fixture-level check that the bundle's flows
do not use undefined keys.
## Outcome
- **`conformance/FLOWS.md`** defines the format: how to set up a run (email
side, callback stub `callback-1`, master stub `cms-1`, controllable
clock, optional send cap), the five step types, captures and the 14
expectation keys. All of it is observable at the contract boundary:
messages the stubs receive, command responses, and sent mail.
- **`flows.json`** carries everything a run needs:
- `setups` with role configs by peer id (no URLs; `<mode:ID>` for a
primed webhook);
- fixed public test keys in `peers`, plus `statute`;
- per flow, a `scenario` and an optional `max_sent`;
- explicit `assign` steps with `EXT-100` instead of the stub's
auto-numbering.
- **Removed harness-only observables:** the ticket service's response
strings (now `event_accepted`, the 2xx) and `tick()`'s return value (now
`mode_received`, `mode_received_last` and `mails_sent`).
- **`conformance/scenarios.json`:** the callback scenarios as data. The
Python stub loads them from there.
- **CONTRACT.md §5** now defines the `case.assign` response, which flows
capture from.
- **New flow** `s-006` (a held send over the cap): 21 flows in all.
- **Runner** (`mas_modes.runner`) reads only the bundle and rejects
undefined keys. `tests/test_modes_conformance.py` checks that every flow
uses defined keys, existing setups and scenarios, and that every key is
documented in FLOWS.md. The drift test now also covers the vendored
FLOWS.md.
- **Checks.** A mutation check over 5 expectations, plus an undefined key,
was detected every time. `mas test`: mode corpus 195/195.