Skip to content

Environment and Remote Environment towards people; Machine stays the technical term (F28, base-instructions-15) - #109

Merged
immakermatty merged 20 commits into
mainfrom
claude/DEV-6628-environment-wording
Sep 30, 2026
Merged

immakermatty merged 20 commits into
mainfrom
claude/DEV-6628-environment-wording

Conversation

@immakermatty

@immakermatty immakermatty commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Closes #99.

Up to date with main at 5d6ddfc (after #100, #103 with #101, and #106). This PR is no longer stacked; main was merged in with merge commits. #106 took decision number F27 (the Steward preset), so this decision is F28. The new strings from #100 and the new hosted-organization-steward preset follow the wording too, and the guard covers that preset.

The decision (the Principal, 2026-09-29, recorded as F28)

What people read calls the place where they and their agents work the Environment; a hosted one is a Remote Environment. People know "Remote Environment" from tools they already use (Codex, T3 Code), and "Machine" is a defined architecture term they do not recognise. Czech keeps the word, masculine: ten Environment, tento Environment, na tomto Environmentu, Remote Environment. "Mašina", "Machine" (as the thing a person works in), "VM" and "server" are not used towards people. Machine stays the technical term for the boundary an Environment runs on: identifiers, JSON keys, commands (lazurio machine …), file names (manual/this-machine.md), schemas, custody, ARCHITECTURE.md and decision records.

What changes

  • Launchpad (src/launchpad/messages.ts, the page's fallback text): 43 English and 51 Czech strings, including the Czech Team rule from src/tools/team-github.ts, plus 4 English and 4 Czech strings that wacli sign-in: a paired wacli reads as signed in, "already signed in" instead of waiting, and a sign-in that shows nothing ends with a reason (#98) #100 added or changed. Czech strings that treated Environment as neuter (tohle Environment je sdílené) now use the masculine form.

  • CLI human output and help: about 66 English and 8 Czech strings in 13 files, plus wacli sign-in: a paired wacli reads as signed in, "already signed in" instead of waiting, and a sign-in that shows nothing ends with a reason (#98) #100's 2 new sentences in src/tools/curated-cli.ts: help text, human messages, the repair-agent prompt, the prepared public issue body, the install-standard prompt, and the doctor's group label. Commands, flags, JSON keys, codes and preset names are unchanged.

  • Generated Folder (AGENTS.md and manual/, every preset, both locales):

    • Every text says Environment or Remote Environment.
    • AGENTS.md gains one rule: say Environment and Remote Environment to people, never Mašina, VM or server; Machine stays the technical term.
    • The manual defines Machine once, in the glossary and in the boundary bullet of manual/lazurio.md.
    • "The Machines operator" is now "the hosting operator (Lazurio Machines)".
    • The catalog's target states and prompts follow. The SSH key title placeholder is now <hostname>, which is what the code actually uses.
    • The template revision goes from base-instructions-14 to base-instructions-15, so an installed Folder re-renders on the next refresh. Snapshots are updated.
  • Guard tests/environment-wording.test.ts scans (every preset, including hosted-organization-steward):

    • the message catalog in both locales;
    • the page's own text;
    • every prepared tool prompt and the MCP prompt;
    • AGENTS.md and the manual for every preset and locale, with relationships, entries, all tools and a note.

    It flags Mašin/mašin, VM and Machine(s) as a noun. The allowlist is explicit and short:

    1. The wording rule itself, because it has to name the words it replaces.
    2. Code spans: commands, paths, identifiers, JSON keys.
    3. **Machine** in bold, the defined technical term (glossary row and boundary bullet).
    4. "Lazurio Machines", the product name of the hosting.
    5. "Human and Machine", the name of the principle.
    6. Czech mašinérie, which means machinery (a different word).

    A self-test proves the guard catches the old wording and hides only these entries.

  • Docs: decision F28 in docs/decisions.md, and the Settings labels in docs/launchpad-development.md.

Before → after

Where Before After
Settings entry (cs) Tahle Mašina Tenhle Environment
Settings entry (en) This Machine This Environment
Settings legend (cs / en) Profil mašiny / Machine profile Profil Environmentu / Environment profile
Handover notice (en) Recorded from the Machine handover; shown here, changed only by the Machines operator. Recorded when this Remote Environment was handed over; shown here, changed only by the operator who hosts it.
Recovery (cs) Lazurio na téhle Mašině potřebuje opravu. Lazurio na tomhle Environmentu potřebuje opravu.
Recovery (en) Lazurio on this Machine needs a repair. Lazurio in this Environment needs a repair.
Tools, shared (cs) Tohle Environment je sdílené. … platí pro celé Environment Tenhle Environment je sdílený. … platí pro celý Environment
SSH key (en) The SSH key of this Machine is linked The SSH key of this Environment is linked
SSH key (cs) SSH klíč téhle Mašiny je propojený SSH klíč tohohle Environmentu je propojený
AGENTS.md (cs) ## Tahle Mašina · Je to jeho jediná osobní hostovaná Mašina. ## Tenhle Environment · Je to jeho jediný osobní Remote Environment.
AGENTS.md peers (en) example-workspace (work VM, work zone …) example-workspace (work Remote Environment, work zone …)
Manual zones (cs) osobní klient ↔ osobní VM; pracovní laptop ↔ pracovní VM osobní klient ↔ osobní Remote Environment; pracovní laptop ↔ pracovní Remote Environment
CLI help (en) or on a hosted Machine the declared operator's or in a Remote Environment the declared operator's
CLI blocked next (en) Ask the Machines operator to verify the handover Ask the operator who hosts this Remote Environment to verify the handover

What deliberately does not change

  • Contracts: identifiers, types, JSON keys and machine-readable values; commands and flags (lazurio machine inspect|folder-init|folder-refresh); codes (machine-context-*, not-hosted, hosted-entry-*); preset and kind names (personal-vm, workspace-vm, hosted-*); file names (manual/this-machine.md, lazurio.machine.json); the vendored schema lazurio.machine.v1; test names.
  • Behaviour: no change to src/tools sign-in logic or src/modules behaviour; only text changed there.
  • Architecture and decision documents keep "Machine". Other user guides are not rewritten in this PR.
  • Internal Error messages that are caught and turned into a code, never shown to a person, keep their text (e.g. "Stored profile does not match execution Machine" in src/folder/*).
  • "server" that is not the Environment stays: MCP server, GitHub's host keys ("klíče serverů GitHubu"), SSH server, the Launchpad's own server.
  • "this computer" in the GitHub device-code text stays, because it is the person's own device.

Verification

  • bun run check on the merge with main (5d6ddfc): lint (337 files clean), typecheck, bun test 1070 pass, 7 skip, 0 fail, 42 snapshots, 26246 expect() calls (1077 tests, 121 files), check:public PASS (394 files), build:proof, and smoke:proof PASS. The guard passes on the merged catalog and on every preset, including hosted-organization-steward, with an unchanged allowlist.
  • I read the snapshot diff for the generated AGENTS.md and manual in both locales.

Risks / follow-ups

  • Installed Folders show the new wording after their next folder-refresh or profile change (revision 15). An edited generated file blocks the refresh with drift, as before.
  • The Local Environment's name stays "Local workstation" / "Místní prostředí". The Principal did not name it.

🤖 Generated with Claude Code

immakermatty and others added 18 commits September 29, 2026 22:53
…fault preparation (#97)

Failing tests of the decision the Principal recorded on issue #97 (option
a), on the real consumers:

- tests/module-default-preparation.test.ts: a Folder with Organization delta
  (transition) whose modules are shaped like the real application packages
  of the replaced Launchpad: lazurio.runtime, a dev script, bun.lock beside
  the package, a local file: dependency, no lazurio.preparation and no
  packageManager. Through `lazurio module list`, `module start|status|stop`,
  the gateway's ensure and the Launchpad's session start: the undeclared
  module is executable and its start repairs a stale node_modules from the
  lockfile (the session app then serves the current dependency); a module
  without a lockfile is executable: false with preparation-lockfile-missing
  and every operation refuses with it; the explicit declaration's start
  still runs its check and installs nothing. What is known read-only
  (package manager, a local dependency outside the owner, a missing check
  script) is not executable in the list with the start's reason; what only
  the start can know (a Bun version mismatch, a frozen install that fails)
  is a typed refusal, never operation-failed.
- install authority: no packageManager is the operator's Bun; typed
  refusals for the lockfile, the package manager, an escaping dependency
  and an owner that is not a package object.
- bun toolchain: a package that names no Bun runs the selected Bun.
- preparation binding: the default owner is the application's own package.
- catalog and module views: every preparation reason reads as a sentence
  naming its file in both languages.
- fixtures: every catalog fixture app carries a lockfile beside its
  package, as a real one does (lockfile: false omits it); module-host gains
  undeclaredModule, the real application's shape.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n; the catalog and every surface name why a preparation cannot run (#97)

The default preparation (decision F25): when an application package
declares no lazurio.preparation, its own package.json is the owner and
preparing is the frozen install from the one Bun lockfile beside it, under
the existing install authority, checkout rule and guarded process; no
prepare script and no check script. The explicit declaration keeps its
full meaning.

- preparation-binding: the preparation in effect (declared or default);
  inspectPreparationShape, the read-only part the catalog runs;
  requireQualifiedInstall (the workspace refusal, now typed).
- declared-bun-preparation: the default has no check, so its start-time
  step is its frozen install; a failed default install is
  preparation-install-failed with the lockfile.
- install-authority: readInstallOwner shared by the snapshot and the shape;
  a package without packageManager runs with the operator's Bun whichever
  version it is; a pinned Bun is still exact.
- bun-toolchain: packageManager null observes the selected Bun;
  requireBunToolchain types a mismatch.
- preparation-refusal: the closed set of preparation-* reasons and
  PreparationRefused with the package or lockfile it concerns.
- lifecycle: a start check that failed with a known reason keeps it; a
  typed refusal is not swallowed as invalid-or-unavailable.
- module-operations: typed refusals with the module-relative file instead
  of operation-failed.
- catalog: executable also means the default app's preparation can run as
  far as is known read-only; otherwise the start's reason and file.
- CLI, Launchpad (English and Czech) and doctor name every reason; the
  Folder manual says what start installs (base-instructions-14).
- module-checkout-custody: the cloned module board is undeclared.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…module without a declaration (#97)

- docs/decisions.md: F25, the Principal's decision of 2026-09-29 (option a)
  with its reason, the exact default, the start, the toolchain rule, the
  catalog (amending F23 point 6 for the preparation's shape), the typed
  reasons, what the explicit declaration is still for and what it does
  not cover.
- docs/module-adoption.md: the absent declaration no longer means "not
  preparation-capable"; the start-time step of the default is its frozen
  install; the Bun rule.
- docs/launchpad-development.md: what executable means in the catalog, what
  a start runs, the typed reasons.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…out is an input of the default preparation (#97)

Failing tests of the coordinator's extension after a read-only check of
the build on a real hosted Organization work Machine: four modules share a
contracts package of the Organization's root repository through
file:../../../../launchpad/contracts/v1, which the replaced Launchpad
starts.

- module-default-preparation: an undeclared app/v3 that depends on
  launchpad/contracts/v1 at the fixture Organization's root is executable,
  starts through the module operations and ensure, and gets the package
  installed without it changing; a dependency that leaves the Organization,
  one through a symlinked directory and a missing one are not executable
  and refused by their reason (preparation-dependency-outside-owner,
  directory-not-regular with launchpad/linked, preparation-dependency-
  missing) in the list, the start and ensure.
- install-authority: with a dependency boundary above the owner such a
  dependency is an install input whose manifest change invalidates the
  observation; the boundary itself, beyond it and a missing directory are
  refused.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ganization checkout (#97)

A read-only check of this change on a real hosted Organization work
Machine found four of twenty served modules refused as
preparation-dependency-outside-owner: their application packages share a
contracts package of the Organization's root repository
(file:../../../../launchpad/contracts/v1 from workspace/<module>/app/v3/),
which the replaced Launchpad starts.

- local-dependency-inputs: roots are resolved relative to a dependency
  boundary (the owner, or for the default preparation the Organization or
  Personalspace owner directory), normalized as text, reached from the
  boundary one real directory at a time under the checkout rule, and only
  the declared dependency is inventoried; the boundary itself is never a
  dependency; a missing one is preparation-dependency-missing, named by the
  package that declares it.
- install-authority, bun-preparation: the boundary is part of the
  snapshot, so verification repeats the same inventory.
- preparation-binding: the default preparation's boundary is the
  Organization directory the caller names; a declared preparation keeps
  its owner.
- local-application-adapters, catalog: the Organization (or Personalspace
  owner) directory is that boundary; refusals are named relative to the
  module, else the Organization root.
- CLI and Launchpad (English and Czech) explain preparation-dependency-
  missing; the outside-owner sentence names the Organization.
- F25 point 1a, module adoption and Launchpad development docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…paration, the lockfile's file rule, overlapping applications, typed boundary reasons (#97)

Failing tests on the real consumers (module list, module
start|status|logs|stop, ensure, the Launchpad's session stop):

1. A running module whose lockfile is removed is still read (status
   running, logs, ensure healthy) and stopped, from the CLI over the user
   manager and from the Launchpad's session; the list says executable:
   false with preparationRefused, and only start and ensure refuse with
   preparation-lockfile-missing.
2. A symlink in place of bun.lock is not executable in the list, with the
   start's declaration-not-regular (app/bun.lock).
3. Application packages of one module that contain one another (a root
   package.json and app/v2) are refused as
   preparation-applications-overlap in the list and at the start of either;
   sibling packages app/v1, app/v2, app/v3, the last with a local package
   in its own directory, are executable and start.
4. A dangling symlink as a local dependency is directory-not-regular
   (app/dependency-link) and a missing declared owner
   preparation-owner-invalid (missing/package.json), in the list and at
   the start, never module-unavailable or operation-failed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ile's file rule in the catalog, no overlapping applications under the default, typed boundary reasons (#97)

1. Reading and stopping never depend on the preparation (F25 point 4a).
   catalog: a module refused only by its default app's preparation carries
   preparationRefused. module-operations targetOf: such a module still
   resolves for status, stop and logs; start refuses with the reason;
   ensure reports a running app and refuses only where it would start.
   local-application-adapters coordinateMutation: a session stop does not
   resolve the preparation (one line). catalog-panel keeps the lifecycle
   card for such a module.
2. install-authority readInstallOwner: the selected lockfile under the
   checkout's file rule (regular, the operator's, at most 16 MiB) before
   the empty check, so the catalog refuses a symlinked, foreign or
   oversized lockfile as the start does; inspectCheckoutConfiguration: the
   checkout's .npmrc and bunfig.toml down to the owner under the same rule,
   run by inspectPreparationShape.
3. preparation-binding requireSeparateApplications: the default preparation
   refuses an application whose directory contains, or lies inside, another
   declared application package of the module
   (preparation-applications-overlap); siblings and local packages inside
   the application are not affected.
4. owned-directory inspectCheckoutDirectory: a symlink is
   directory-not-regular without resolving it, so a dangling one is typed;
   local-dependency-inputs reach: a symlinked dependency root is
   directory-not-regular, a file dependency root under the file rule;
   install-authority inspectOwnerDirectories: a missing owner directory is
   preparation-owner-invalid with the owner's package.json.

F25 points 4, 4a and 6, module adoption and Launchpad development docs;
English and Czech sentences for preparation-applications-overlap.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…untime environment (#102)

A fixture application shaped like a real one binds the entrypoint aliases,
allows exactly the hostname of LAZURIO_RUNTIME_EXTERNAL_ORIGIN as its Host and
that origin as its Origin, and is started through the module operations:

- hosted Folder (Machine handover with entry), user manager: the unit's whole
  environment by exact equality, the entrypoint alone gets the origin, ambient
  manager names are unset, and the unit's definition run as the manager runs
  it answers its own hostname and refuses any other;
- session runner on a hosted Folder: the process itself receives it;
- workstation Folder: no external origin anywhere;
- a non-default app gets none, an unreadable Folder state refuses the start;
- a unit an older release started stays recognized, keeps its environment
  until Stop, and the next start carries the origin.

These fail now: the launch has only HOME, PATH and the keyed host/port.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ot module-unavailable (#97)

With inspectCheckoutDirectory refusing a symlink without resolving it
(review 5359095003, finding 4), the dangling workspace/ link of two
organization-applications tests is named by the checkout rule and its
file, as a symlink with a target already was. Nothing is followed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nt, with its external origin on a hosted Machine (#102)

The launch environment is built in one place
(src/modules/application-environment.ts) on the closed base HOME, PATH and
optional TMPDIR, in both runners: the keyed listener host/port, the
entrypoint aliases LAZURIO_RUNTIME_HOST/PORT, LAZURIO_RUNTIME_LISTENERS_JSON,
the runtime and Organization identity, NODE_PATH, NODE_ENV=development, the
Astro supervision flags and, for the module's default app on a hosted
Machine, the entrypoint's LAZURIO_RUNTIME_LISTENER_<ID>_EXTERNAL_ORIGIN and
LAZURIO_RUNTIME_EXTERNAL_ORIGIN.

The origin comes from the same function as runtime.url (the recorded entry's
module origin template), so it is exactly that URL without its slash. A
workstation, a non-default app, a Folder without an entry and every
auxiliary listener get none; an unreadable Folder state refuses the start
instead of being taken for a workstation. Nothing ambient is read.

The session-runner test compares the runtime names without depending on
their order.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…application (#102)

The complete table of what a started application gets, its source in the
replaced Launchpad, what is deliberately not carried over and why, and what
happens to an application that is already running when the Platform is
updated (it keeps its environment until Stop and Start).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ion' into claude/DEV-6628-runtime-environment
…zech and English (#99)

Decision F27 (the Principal, 2026-09-29): the place people work in is the
Environment, a hosted one a Remote Environment; Czech keeps the word and
makes it masculine (ten Environment, na tomto Environmentu).

- messages.ts: 43 English and 50 Czech strings; "This Machine" in Settings
  becomes "This Environment" / "Tenhle Environment", the handover notice
  names the operator who hosts it, the name row is "Name" / "Název", and
  the texts that treated Environment as neuter follow the masculine form.
- index.html: the page's fallback text follows the catalog.
- team-github.ts: the Czech Team rule is masculine ("Tenhle týmový
  Environment"); text only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…or agents (base-instructions-15) (#99)

- render.ts: AGENTS.md gains the wording rule (environmentWording): say
  Environment and Remote Environment to people, never Mašina, VM or
  server; Machine stays the technical term. "## This Environment", peers
  as personal/work Remote Environment, the hosting operator's pin.
- manual.ts: every preset and locale speaks of the Environment and the
  Remote Environment; the technical term **Machine** is defined once in
  the glossary and in the boundary bullet of lazurio.md; the hosting
  product keeps its name Lazurio Machines.
- outputs.ts: manual titles and summaries.
- catalog.ts: target states and prepared prompts say Environment; the SSH
  key title placeholder is <hostname>, as the code composes it.
- Template revision base-instructions-14 -> base-instructions-15;
  snapshots updated; test expectations follow the text (no test renamed).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
tests/environment-wording.test.ts scans the Launchpad message catalog
(both locales), the page's own text, the prompts a person copies and the
generated AGENTS.md and manual of every preset and locale. Its allowlist:
the wording rule itself, code spans (commands, paths, identifiers), the
bold defined term **Machine**, the product name Lazurio Machines, the
principle "Human and Machine" and Czech "mašinérie" (machinery). A self
test shows that it catches the old wording and hides only its entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ine as the technical term (#99)

- docs/decisions.md: F27, the Principal's decision of 2026-09-29 with its
  reason, the Czech form, where it applies, where "Machine" stays, the
  guard and its allowlist, and what is not covered.
- docs/launchpad-development.md: the Settings labels.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
#99)

Help text, human messages, the repair-agent prompt, the prepared issue
body and the install-standard prompt say Environment, and Remote
Environment where the text is about a hosted one; Czech uses "na tomhle
Environmentu". Commands (`lazurio machine inspect`, `folder-refresh`),
flags, JSON keys, codes and preset names are unchanged; the doctor's group
label is "Environment" in both locales; "the Machines operator" becomes the
operator who hosts the Remote Environment, and the hosting product keeps
its name Lazurio Machines. Test expectations follow the text; no test
renamed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t wording

Conflicts resolved so both sides stay:
- src/launchpad/messages.ts: #100's longer not-installed sentence kept, in
  the new wording (en and cs); the other hunks take this branch's wording.
  #100's new strings follow the rule too: already signed in (2 en, 2 cs)
  and the no-challenge sentence (en, cs).
- src/tools/curated-cli.ts: #100's no-challenge and already-signed-in
  sentences say Environment.
- docs/decisions.md: main's entries unchanged (F19 addendum of #98, F25,
  F26), F27 after them.
- src/folder/render.ts, tests/folder-tools.test.ts: main is still at
  base-instructions-14; this branch stays base-instructions-15.
- src/modules/module-cli.ts and the snapshots: main's content equals this
  branch's base there; this branch's side taken, snapshots unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@immakermatty
immakermatty marked this pull request as ready for review September 30, 2026 00:00
…nment wording; this decision becomes F28

- docs/decisions.md: main's F27 (the Steward preset) kept exactly; this
  branch's decision renumbered F28 after it (render.ts comment and the
  guard test follow).
- src/folder/render.ts: main's automation assignment line kept; the
  operator line stays masculine ("přiřazený Operátorovi").
- src/machine/cli.ts: main's help for hosted-organization-steward kept,
  "whether the Machine is assigned" says Remote Environment.
- tests/folder-handover.test.ts: main's allowed presets with this
  branch's next sentence.
- The guard now also renders hosted-organization-steward (automated
  handover); it passes without a new allowlist entry. Snapshots
  regenerated for every preset at base-instructions-15.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@immakermatty immakermatty changed the title Environment and Remote Environment towards people; Machine stays the technical term (F27, base-instructions-15) Environment and Remote Environment towards people; Machine stays the technical term (F28, base-instructions-15) Sep 30, 2026

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved on exact head 9b2e391 (no merge). Compared with current main/F27 and the prior 5d0855d head; F28 records issue #99 and distinguishes Principal wording from author choices. Reviewed Czech masculine agreement, both locale catalogs, CLI help/output, generated AGENTS.md and manual across all presets including hosted-organization-steward. No contract identifier/key/command/flag/schema or machine-readable value changed by this wording PR; Machine remains technical. The explicit guard allowlist is narrow. Mutation probes of the English Launchpad catalog and Czech Steward manual to the old wording each made the guard fail, then were restored. Local bun run check passed: 1070 pass, 7 skip, 0 fail, 42 snapshots; lint/typecheck/public guard/build/smoke passed. Exact-head CI passed on ubuntu-24.04 and macos-14; no unresolved threads. No blocking findings.

@immakermatty
immakermatty merged commit d64295f into main Sep 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wording: say "Environment" to the user instead of "Machine" / "Mašina"

2 participants