Skip to content

feat(effect-zod): transform support + walk memoization + flattened checks#23203

Merged
kitlangton merged 1 commit intodevfrom
kit/effect-zod-transform-support
Apr 17, 2026
Merged

feat(effect-zod): transform support + walk memoization + flattened checks#23203
kitlangton merged 1 commit intodevfrom
kit/effect-zod-transform-support

Conversation

@kitlangton
Copy link
Copy Markdown
Contributor

Summary

Fourth walker extension in the Zod-from-Schema pipeline. Adds transform support and two refinements to the existing code path that were worth doing together.

Transform support (Schema.decodeTo / Schema.transform)

When an AST has an `encoding` chain, the walker now threads each link's decode getter through a Zod `.transform()`. This enables migrating any Zod schema that uses `.transform()` or `.preprocess(...).transform()` — notably `agent.ts` and `permission.ts#Info`.

Crucial nuance: `Schema.Class` uses `Declaration` + encoding internally to construct class instances. For Zod consumers we want plain objects, not class instances, so Declaration nodes fall through to `body()` and skip encoding. Regression-guarded by a dedicated test.

Memoized `walk()`

AST nodes are immutable and frequently shared across schemas (a single `Schema.Class` embedded in multiple parents is common). Added a module-scoped `WeakMap` cache keyed by AST identity:

  • Same AST → same derived Zod instance.
  • Nested reuse shares children by reference.
  • `WeakMap` auto-GCs with the AST.

Flattened check refinements

Previously N checks produced N stacked `.superRefine` wrappers, each traversed per parse. `applyChecks()` now collects all filters from `checks` + `FilterGroup` into one linear list and runs them inside a single `.superRefine` — one Zod wrapper regardless of count, still all checks fire and all error messages are emitted.

Tests (9 new)

Transform:

  • Number → Duration-ish (mirrors `DurationFromSeconds` in `account.ts`)
  • String → Number via `parseInt`
  • Transform inside a struct field
  • Chained `decodeTo` exercising the `encoded()` reduce
  • Schema.Class guardrail — parsed output is a plain object, not an instance

Memoization:

  • `walk()` memoizes by AST identity
  • Nested reuse shares cached children by reference

Flattened checks:

  • Multiple independent checks all fire in one refinement layer
  • `FilterGroup` flattens alongside its siblings

Correctness

  • All 1950 opencode tests pass, zero failures
  • Typecheck clean
  • SDK byte-identical (confirmed via `./packages/sdk/js/script/build.ts`)

Performance

  • Transform / check work moved from per-parse layer allocation to per-walk setup
  • Shared AST subtrees cached by identity, eliminating duplicate walks when multiple schemas embed the same class
  • `EMPTY_PARSE_OPTIONS` hoisted to module scope (no per-parse allocation)

Simplify pass

Ran the /simplify workflow. Aggregated findings from three parallel reviews and applied the worthwhile ones: inlined `runDecode` into `decode` (dropped ast-threading for error messages, collapsed double cast), consolidated walk-level intermediate consts per the style guide, added the memoization + check-flattening above. Pre-existing style nits and out-of-scope perf ideas deferred to future PRs.

Follow-ups unlocked

  • `config/agent.ts` — top-level `.catchall` + `.transform`
  • `config/permission.ts#Info` — `.preprocess` + `.transform` + key-order hack

…ecks

Third walker extension in the Zod-from-Schema pipeline. This one is
a bit richer than the catchall/tuple/check additions because it
touches the hot code path.

## Transform support (Schema.decodeTo)

When an AST has an 'encoding' chain (from Schema.decodeTo /
Schema.transform) the walker now threads each link's decode getter
through a Zod .transform(). Schema.Class uses Declaration + encoding
internally to construct class instances, so Declaration nodes fall
through to body() instead of encoded() — Zod consumers keep getting
plain objects as before.

## Memoized walk()

AST nodes are immutable and frequently shared across schemas. Added a
module-scoped WeakMap cache keyed by AST identity. Same AST -> same
derived Zod instance, and nested reuse (a Schema.Class embedded in
two parents) shares the child Zod by reference.

## Flattened check refinements

Previously N checks produced N stacked .superRefine wrappers, each
traversed per parse. Now applyChecks() collects all filters from
checks + FilterGroups into one linear list and runs them inside a
single .superRefine — one wrapper regardless of count.

## Tests (9 new)

- 5 transform cases: Number->Duration-ish, String->Number, in-struct,
  chained decodeTo through the reduce, Schema.Class guardrail.
- 2 memoization cases: identity for same AST, nested reuse shares
  children.
- 2 check-flattening cases: multiple filters, FilterGroup alongside
  siblings.

## Correctness

All 1950 opencode tests pass. SDK byte-identical.

## Follow-ups unlocked

- agent.ts (top-level .catchall + .transform)
- permission.ts#Info (.preprocess + .transform)
@kitlangton kitlangton enabled auto-merge (squash) April 17, 2026 23:49
@kitlangton kitlangton merged commit f3d1fd9 into dev Apr 17, 2026
13 checks passed
@kitlangton kitlangton deleted the kit/effect-zod-transform-support branch April 17, 2026 23:55
NicholasDominici added a commit to jairad26/opencode that referenced this pull request Apr 20, 2026
* fix: ensure azure sets prompt cache key by default (anomalyco#22957)

* refactor: unwrap BusEvent namespace + self-reexport (anomalyco#22962)

* refactor: unwrap Identifier namespace + self-reexport (anomalyco#22963)

* refactor: unwrap Ripgrep namespace + self-reexport (anomalyco#22965)

* refactor: unwrap MDNS namespace + self-reexport (anomalyco#22968)

* refactor: unwrap FileTime namespace + self-reexport (anomalyco#22966)

* refactor: unwrap ServerProxy namespace + self-reexport (anomalyco#22969)

* refactor: unwrap Server namespace + self-reexport (anomalyco#22970)

* refactor: unwrap ConfigMCP namespace + self-reexport (anomalyco#22948)

* chore: generate

* refactor: unwrap Workspace namespace + self-reexport (anomalyco#22934)

* refactor: unwrap McpOAuthCallback namespace + self-reexport (anomalyco#22943)

* refactor: unwrap ConfigProvider namespace + self-reexport (anomalyco#22949)

* refactor: unwrap ACP namespace + self-reexport (anomalyco#22936)

* refactor: unwrap CopilotModels namespace + self-reexport (anomalyco#22947)

* refactor: unwrap McpAuth namespace + self-reexport (anomalyco#22942)

* refactor: unwrap Heap namespace + self-reexport (anomalyco#22931)

* refactor: unwrap UI namespace + self-reexport (anomalyco#22951)

* refactor: unwrap Agent namespace + self-reexport (anomalyco#22935)

* refactor: unwrap PluginMeta namespace + self-reexport (anomalyco#22945)

* refactor: unwrap FileIgnore namespace + self-reexport (anomalyco#22937)

* refactor: unwrap TuiConfig namespace + self-reexport (anomalyco#22952)

* refactor: unwrap Protected namespace + self-reexport (anomalyco#22938)

* refactor: unwrap ConfigSkills namespace + self-reexport (anomalyco#22950)

* chore: generate

* tooling: add unwrap-and-self-reexport + batch-unwrap-pr scripts (anomalyco#22929)

* refactor: unwrap Shell namespace + self-reexport (anomalyco#22964)

* tui: fix Windows terminal suspend and input undo keybindings

On Windows, native terminals don't support POSIX suspend (ctrl+z), so we now
assign ctrl+z to input undo instead of terminal suspend. Terminal suspend is
disabled on Windows to avoid conflicts with the undo functionality.

* tui: convert TuiConfig namespace to ES module exports

* refactor: unwrap session/ tier-2 namespaces + self-reexport (anomalyco#22973)

* chore: generate

* refactor: unwrap SessionEntry namespace + self-reexport (anomalyco#22977)

* refactor: unwrap SessionV2 namespace + self-reexport (anomalyco#22978)

* refactor: unwrap ExperimentalHttpApiServer namespace + self-reexport (anomalyco#22979)

* refactor: unwrap TuiPluginRuntime namespace + self-reexport (anomalyco#22980)

* chore: delete empty v2/session-common + collapse patch barrel (anomalyco#22981)

* refactor: extract Diagnostic namespace into lsp/diagnostic.ts + self-reexport (anomalyco#22983)

* tui: stabilize session dialog ordering (anomalyco#22987)

* refactor: split config lsp and formatter schemas (anomalyco#22986)

* perf: speed up skill directory discovery (anomalyco#22990)

* chore: generate

* refactor: normalize AccountRepo to canonical Effect service pattern (anomalyco#22991)

* refactor: unwrap Question namespace + fix script to emit "." for index.ts (anomalyco#22992)

* refactor: collapse auth/ barrel — merge auth.ts into index.ts + self-reexport (anomalyco#22993)

* refactor: eliminate account/ barrel, route consumers to sibling files (anomalyco#22995)

* refactor: convert Flag namespace to const object with getters (anomalyco#22984)

* refactor: split config parsing steps (anomalyco#22996)

* refactor: unwrap FileWatcher namespace + self-reexport (redo) (anomalyco#23000)

* fix: prefer real undo filenames over /dev/null (anomalyco#23006)

* chore: generate

* app: use tanstack query to load session vcs state (anomalyco#22277)

* refactor: make formatter config opt-in (anomalyco#22997)

* chore: generate

* fix: preserve plugin tool metadata in execute result (anomalyco#22827)

Co-authored-by: jquense <jquense@ramp.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* chore: retire namespace migration tooling + document module shape (anomalyco#23010)

* refactor: move provider and config provider routes onto HttpApi (anomalyco#23004)

* feat(tui): animated GO logo + radial pulse in free-limit upsell dialog (anomalyco#22976)

* feat(app): hide desktop titlebar tools behind settings (anomalyco#19029)

Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>

* fix(tui): tui resiliency when workspace is dead, disable directory filter in session list (anomalyco#23013)

* refactor(tui): inline final Go shimmer settings (anomalyco#23017)

* chore: generate

* refactor: move project read routes onto HttpApi (anomalyco#23003)

* fix(app): use fetchQuery instead of ensureQueryData in global sync (anomalyco#23025)

* chore: update nix node_modules hashes

* fix: preserve prompt input across unmount/remount cycles (anomalyco#22508)

* chore: delete filetime module (anomalyco#22999)

* chore: generate

* remove accidental commit of daytona plugin (anomalyco#23030)

* fix crash on experimental

* refactor(core): move server routes around to clarify workspacing (anomalyco#23031)

* fade in prompt metadata transitions (anomalyco#23037)

* chore: generate

* core: migrate config loading to Effect framework (anomalyco#23032)

* fix(app): workspace loading and persist ready state (anomalyco#23046)

* chore: generate

* upgrade opentui to 0.1.100 (anomalyco#22928)

* chore: update nix node_modules hashes

* release: v1.4.8

* remove log

* feat(core): exponential backoff of workspace reconnect (anomalyco#23083)

* chore: generate

* zen: routing logic

* chore: generate

* back to opentui 0.1.99

* roll back opentui

* sync

* fix: conditionally show file tree in beta channel (anomalyco#23099)

* fix(opencode): rescrict github copilot opus 4.7 variants to "medium" (anomalyco#23097)

* docs: adding Mistral to docs as a provider (it is already a provider, just docs update) anomalyco#23070 (anomalyco#23072)

* chore: generate

* feat: add LLM Gateway provider (anomalyco#7847)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>

* chore: update nix node_modules hashes

* fix incorrect light mode in ghostty

* tui: fix session resumption with --session-id flag to navigate after app initialization

Previously when passing a session ID directly, the route was set during initial
render which could cause navigation issues before the router was fully ready.
Now the session navigation happens after initialization completes, ensuring
the TUI properly loads the requested session when users resume with --session-id.

* release: v1.4.9

* Improve light mode dark mode copy

* chore: bump gitlab-ai-provider to 6.6.0 (anomalyco#23057)

* fix(opencode): pass `EXA_API_KEY` to `websearch` tool to avoid rate limits (anomalyco#16362)

Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* chore: bump @ai-sdk/anthropic to 3.0.71 and dependents (anomalyco#23120)

* tui: fix agent cycling and prompt metadata polish (anomalyco#23115)

* chore: generate

* when generating sdk only format sdk, much faster (anomalyco#23122)

* chore: update nix node_modules hashes

* fix(core): add historical sync on workspace connect (anomalyco#23121)

* fix: revert sdk generation script change (anomalyco#23133)

* trace npm fully

* do not flock until reify

* test: align plugin loader npm mocks

- switch plugin loader tests to the effect npm module
- return Option.none() for mocked npm entrypoints
- keep test fixtures aligned with the current Npm.add contract

* chore: bump ai to 6.0.168 and @ai-sdk/gateway to 3.0.104 (anomalyco#23145)

* refactor: consolidate npm exports and trace flock acquisition (anomalyco#23151)

* feat(tui): minor UX improvements for workspaces (anomalyco#23146)

* chore: generate

* chore: update nix node_modules hashes

* fix(core): move instance middleware after control plane routes (anomalyco#23150)

* fix(opencode): normalize provider metadata and tag otel runs (anomalyco#23140)

* fix(core): pass OTEL config to workspace env (anomalyco#23154)

* fix(opencode): untrace streaming event hot paths (anomalyco#23156)

* chore: generate

* release: v1.4.10

* docs(opencode): annotate plugin loader flow (anomalyco#23160)

* chore: generate

* fix(opencode): skip share sync for unshared sessions (anomalyco#23159)

* docs(http-api): refresh bridge inventory and clarify Schema.Class vs Struct (anomalyco#23164)

* refactor(config): migrate mcp schemas to Effect Schema.Class (anomalyco#23163)

* chore: generate

* refactor(config): migrate lsp schemas to Effect Schema (anomalyco#23167)

* refactor(config): migrate permission Action/Object/Rule leaves to Effect Schema (anomalyco#23168)

* fix(core): more explicit routing to fix workspace instance issue (anomalyco#23171)

* feat(effect-zod): translate Schema.check filters into zod .superRefine + promote LSP refinement to Effect layer (anomalyco#23173)

* chore: generate

* refactor(config): migrate skills, formatter, console-state to Effect Schema (anomalyco#23162)

* chore: generate

* feat(server): wrap remaining route handlers in request spans (anomalyco#23169)

* refactor(config): migrate model-id and command to Effect Schema (anomalyco#23175)

* chore: generate

* feat(effect-zod): add tuple support; migrate config/plugin to Effect Schema (anomalyco#23178)

* chore: generate

* fix: ensure copilot model list filters out disabled models (anomalyco#23176)

* refactor(npm): use object-based package spec for install API (anomalyco#23181)

* release: v1.4.11

* feat(server): auto-tag route spans with route params (session.id, message.id, …) (anomalyco#23189)

* feat(tui): show session ID in sidebar on non-prod channels (anomalyco#23185)

* feat(effect-zod): add catchall (StructWithRest) support to the walker (anomalyco#23186)

* refactor(server): align route-span attrs with OTel semantic conventions (anomalyco#23198)

* refactor(config): migrate provider (Model + Info) to Effect Schema (anomalyco#23197)

* chore: generate

* feat(effect-zod): transform support + walk memoization + flattened checks (anomalyco#23203)

* chore: generate

* docs(effect): refresh migration status specs (anomalyco#23206)

* refactor(v2): tag session unions and exhaustively match events (anomalyco#23201)

* feat(effect-zod): translate well-known filters into native Zod methods (anomalyco#23209)

* feat(effect-zod): translate Schema.withDecodingDefault into zod .default() (anomalyco#23207)

* chore: generate

* refactor(config): drop ZodOverride from PositiveInt in provider.ts (anomalyco#23215)

* fix(observability): standardize session telemetry attrs (anomalyco#23213)

* refactor(config): migrate Server + Layout to Effect Schema (anomalyco#23216)

* chore: generate

* refactor: pass formatter instance context explicitly (anomalyco#23020)

* refactor: remove ambient instance reads from lsp (anomalyco#23023)

* chore: generate

* fix: gh copilot issue w/ haiku (eager_input_streaming not supported) (anomalyco#23223)

* feat(effect-zod): add ZodPreprocess annotation for pre-parse transforms (anomalyco#23222)

* chore: generate

* refactor: use InstanceState context in File service (anomalyco#23015)

* refactor: use instance state in small services (anomalyco#23022)

* refactor(config): migrate keybinds.ts to Effect Schema (anomalyco#23227)

* fix(generate): make openapi output deterministic by formatting in-place (anomalyco#23228)

* fix: stop rewriting dev during release publish (anomalyco#22982)

* refactor: use InstanceState context in worktree cleanup paths (anomalyco#23019)

* refactor(config): migrate permission.ts Info to Effect Schema (anomalyco#23231)

* chore: generate

* refactor(config): migrate agent.ts Info to Effect Schema (anomalyco#23237)

* chore: generate

* fix(desktop): adjust ui tool diff sticky header offset (anomalyco#23149)

* refactor(config): migrate config.ts root Info to Effect Schema (anomalyco#23241)

* docs(effect): track schema migration progress with concrete file checklists (anomalyco#23242)

* chore: generate

* fix: make skills logic more token efficient (anomalyco#23253)

* core: extract session entry stepping logic into dedicated module

Move the step function from session-entry.ts to session-entry-stepper.ts and remove immer dependency. Add static fromEvent factory methods to Synthetic, Assistant, and Compaction classes for cleaner event-to-entry conversion.

* chore: generate

* core: track retry attempts with detailed error context on assistant entries

users can now see when transient failures occur during assistant responses,
such as rate limits or provider overloads, giving visibility into what
issues were encountered and automatically resolved before the final response

* tui: fix sync loading indicator to properly show loading state on startup

* core: fix early return when node_modules is missing during package install

* core: support OTEL_RESOURCE_ATTRIBUTES environment variable for custom telemetry attributes

Users can now pass custom OpenTelemetry resource attributes via the OTEL_RESOURCE_ATTRIBUTES environment variable (comma-separated key=value format). These attributes are automatically included in all telemetry data sent from both the main process and workspace environments, enabling better observability integration with existing monitoring systems that rely on custom resource tags.

* chore: generate

* fix: detect attachment mime from file contents (anomalyco#23291)

* chore: generate

* release: avoid package.json drift during publish

* tui: allow full-session forks from the session dialog (anomalyco#23339)

* chore: bump @ai-sdk/amazon-bedrock (anomalyco#23341)

* fix: ensure display: summarized is sent by default for bedrock (anomalyco#23343)

* chore: update nix node_modules hashes

* zen: redeem credit

* zen: redeem go

* chore: generate

* Stefan/enterprise forms waitlist (anomalyco#23158)

Co-authored-by: Ryan Vogel <me@ryan.ceo>

* test: fix bedrock test (anomalyco#23351)

* ci: fix

* ci

* ci

* fix plugins reinstalling too often

* core: ensure executable permissions are set before Docker builds

Fixes an issue where GitHub artifact downloads could strip executable bits
from binaries, causing Docker builds to fail when using unpacked dist files
directly rather than published tarballs. The chmod now runs before the
publish check to guarantee binaries are executable.

* chore: bump electron and fix taskbar icon (anomalyco#23368)

* sync release versions for v1.14.17

* fix incorrect config directory by lazily loading electron-store (anomalyco#23373)

* chore: update nix node_modules hashes

* docs: document --dangerously-skip-permissions CLI flag (anomalyco#23371)

* chore: generate

* fix (anomalyco#23385)

* core: allow users with credits but no payment method to access zen mode

* chore: generate

* chore: generate

* fix: change Free download button text to Download (anomalyco#23388)

* chore: update nix node_modules hashes

* fix(ripgrep): restore native rg backend (anomalyco#22773)

Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>

* chore: update nix node_modules hashes

* fix(desktop-electron): run JSON migration before spawning sidecar (anomalyco#23396)

* chore: update nix node_modules hashes

* fix(version): remove --target flag from beta release creation (anomalyco#23403)

* sync release versions for v1.14.18

* feat: add terminal font settings and built-in Nerd Font (anomalyco#23391)

* chore: generate

* stabilize TUI theme persistence and KV writes (anomalyco#23188)

* chore: update nix node_modules hashes

* flip toolcall prune defaults

* ci: skip Docker builds during preview releases to save time

* chore: generate

* core: fix session compaction test to properly enable prune config option

* ci: skip beta smoke fixes for now

* feat(provider): add NVIDIA to popular providers, docs, and attribution headers (anomalyco#22927)

Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* fix(core): fix Windows managed install and bump ripgrep to 15.1.0 for ARM64 support (anomalyco#23477)

* chore: generate

* refactor(app): move QueryProvider to AppInterface (anomalyco#23484)

* fix: parallel edits sometimes would override each other (anomalyco#23483)

* chore: generate

* app: better loading (anomalyco#23489)

* fix: patch arborist to get around bun bug (anomalyco#23460)

* tweak: rename tail_tokens -> preserve_recent_tokens (anomalyco#23491)

* chore: generate

* chore: update nix node_modules hashes

* fix: defer MessageV2.Assistant.shape access to break circular dep in compiled binary (anomalyco#23495)

* sync release versions for v1.14.19

* fix(ui): use parentID matching instead of positional scan for assistant messages (anomalyco#23093)

* fix(app): fall back to icon.url in sidebar avatar (anomalyco#18747)

* zen: tpm based routing

* docs(go): add Kimi K2.6 to Go and Zen content (anomalyco#23558)

* chore: generate

---------

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Jason Quense <monastic.panic@gmail.com>
Co-authored-by: jquense <jquense@ramp.com>
Co-authored-by: Jay <air@live.ca>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>
Co-authored-by: James Long <longster@gmail.com>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Sebastian <hasta84@gmail.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Jen Person <personjeh@gmail.com>
Co-authored-by: Ismail Ghallou <ismai23l@hotmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
Co-authored-by: rasdani <73563550+rasdani@users.noreply.github.com>
Co-authored-by: Ryan Vogel <ryan@inbound.new>
Co-authored-by: Ryan Vogel <me@ryan.ceo>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Ariane Emory <97994360+ariane-emory@users.noreply.github.com>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Annie Surla <110621965+anniesurla@users.noreply.github.com>
Co-authored-by: 黑墨水鱼 <heimoshuiyu@gmail.com>
Co-authored-by: Chris Yang <18487241+ysm-dev@users.noreply.github.com>
Co-authored-by: Jack <jack@anoma.ly>
xywsxp pushed a commit to xywsxp/opencode that referenced this pull request Apr 24, 2026
dgokeeffe pushed a commit to dgokeeffe/opencode-databricks that referenced this pull request May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant