Skip to content

Dogfood a source-traced SpecDraft live preview - #804

Merged
SoundBlaster merged 9 commits into
mainfrom
codex/specdraft-live-preview-proposal
Oct 26, 2026
Merged

SoundBlaster merged 9 commits into
mainfrom
codex/specdraft-live-preview-proposal

Conversation

@SoundBlaster

@SoundBlaster SoundBlaster commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Add a small local read-only SpecDraft mind map that follows saved note revisions while the conversation continues.
  • Dogfood the complete preparation path: original quotation -> existing notes tools -> proposal 0228 -> specification draft -> bounded technical prototype and observations. Specification acceptance/canonical publication stay pending.

Motivation

  • Saved conversational sketches had no live browser view. The person should see the agent's captured understanding early enough to correct it, using existing storage and identities.

Goals

  • Serve one selected local sketch, preserve structure and source attribution, and update the open map without manual reload.
  • Keep editing, promotion, history selection/rollback, remote hosting and custom agent plugins outside this slice.

Changes

  • Add proposal/source/declaration and a review packet with four draft obligations and six addressed criteria. Preserve unrelated notes and historical hash-bound packets.
  • Add a fixed loopback HTTP boundary and offline SVG browser UI with pan/zoom, node source inspection and visible connection/read failures. Reuse read_notes; no second store or filesystem-watcher dependency.
  • Put stale/unavailable/empty display rules and saved-head continuity in separate named Specifications with immutable facts. HTTP parsing, asset serving, snapshot projection and UI rendering remain mechanics.
  • Add make specdraft-preview, focused tests, DocC and runtime/promotion tracking. Retain bounded technical observations with explicit gaps; screenshots stay local.
  • Review correction: preserve original source — label → target in the inspector for either selected endpoint, including external endpoints and self-links; add four dependency-free JS regressions and a Node 24 CI job.

Spec Evidence

Spec-ID: SG-SPEC-0007, SG-SPEC-0050, SG-SPEC-0051
Proposal-ID: 0045, 0228
Spec-Impact: tooling
Spec-Rationale: Implement a bounded visualization of existing pre-canonical notes, preserving source attribution and existing promotion authority. Core implementation-agnostic specification nodes are unchanged.

Intent-Decision-Review: tools/intent_decision_reviews/0228_specdraft_live_preview.json

Validation

  • Tests added/updated for changed behavior
  • Local checks passed

Commands run:

.venv/bin/python -B -m pytest -q tests/test_specdraft_preview.py tests/test_conversation_notes.py
.venv/bin/python -B tools/python_quality.py
node --check tools/specdraft_preview/static/app.js
node --test tests/specdraft_preview_inspector.cjs
make docc-sync proposal-tracking-gate materialization-packet-check proposal-spec-trace pre-spec-semantics
make spec-evidence-gate SPEC_EVIDENCE_BASE_REF=origin/main
make intent-decision-review SPEC_EVIDENCE_BASE_REF=origin/main INTENT_DECISION_REVIEW_ARGS='--pr-body-file "$PR_BODY_FILE"'

Results:

  • 52 focused Python tests passed; one optional reference Hypercode CLI compatibility check skipped because its binary was not configured. Four inspector JS regressions failed before the correction and passed after it. The DOM-double checks execute the shipped app and click handlers; they are not a new real-browser audit.
  • Real browser observation: the existing tool update changed 8 -> 9 displayed nodes without reload; source quotation inspection worked. One later nine-node foreground revision was rendered after 588 ms. This is one local wall-clock sample, not the 100-node profile.
  • Desktop 1440x960 and narrow 420x900 inspected; no horizontal page overflow. Narrow fit overview needs zoom to read labels. All screenshots remain local.
  • Notes source revision e255d0f2dce94685a353da78669b0886; proposal handoff b7244c6348c64bfb8ec08f3ba630d9d3; measured live revision 002d3ceea1cc439489546a7deb13afa5.
  • Canonical atoms remain 302; separately declared proposal obligations increase 8 -> 12. Individual engineering dispositions are source-bound, not semantic approval.

Risks / Notes

  • Backward compatibility impact: existing note storage/API and canonical semantics unchanged; the new viewer is opt-in and loopback-only.
  • Migration/config changes required: none. Run make specdraft-preview SPECDRAFT_PREVIEW_WORKSPACE=/path/to/sketch; optional SPECDRAFT_PREVIEW_ARGS='--node-id existing_note' selects a branch. Port 0 prints a free local URL.
  • Known limitations: the 100-node foreground browser profile, browser-level error recovery, hostile-text browser execution and general security audit remain unverified. Model/HTTP tests cover the corresponding bounded data/state contracts. A request to open the page in Codex was queued; rendering in that panel was not independently verified.
  • The specification draft remains review_pending; no human acceptance, canonical allocation/materialization or evidence admission is manufactured. Prototype execution is technical evidence attached to candidates.
  • Original browser observations and code hashes remain historical in verification.json; review-fix-verification.json binds the later correction. CI must rerun for the correction. Local preview remains available; no merge or external deployment performed.

Checklist

  • PR title clearly describes the change
  • Scope is focused and minimal
  • Documentation updated (or N/A)
  • Workflow/artifact changes distinguish presence from readiness/status
  • Consumers prefer authoritative repaired/promoted/latest artifacts where relevant
  • Temporary or intermediate paths are scoped to the current run/task where relevant
  • No secrets or sensitive data added

Capture the operator idea through existing notes tools and prepare proposal 0228 plus a review-pending specification draft. Serve the saved sketch through a loopback-only viewer, with named display policies, focused tests and bounded browser observations.

Spec-ID: SG-SPEC-0007, SG-SPEC-0050, SG-SPEC-0051

Proposal-ID: 0045, 0228

Spec-Impact: tooling

Spec-Rationale: Dogfood source capture and bounded visualization without canonical promotion or hidden note mutations.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T09:16:45.182362Z 2a9ac4c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Comment thread Sources/SpecGraph/Documentation.docc/SpecDraftLivePreview.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2a9ac4ce09

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/specdraft_preview/static/app.js Outdated
@SoundBlaster

Copy link
Copy Markdown
Member Author

HyperReview

Эскиз по исходникам · 2a9ac4ce

Состав · изменения в проекции

--- before.hc
+++ after.hc
@@ -0,0 +1,5 @@
+SpecDraftLivePreview
+  NotesSnapshotAdapter
+  DisplayStatePolicy
+  LocalPreviewBoundary
+  NotesMindMapView

Выбранные связи · после

DisplayStatePolicy:
  calls: "display_state → DISPLAY_STATE_SPEC.decide"
LocalPreviewBoundary:
  calls: "create_server → NotesPreview"
NotesMindMapView:
  calls: "refresh → /api/notes"
NotesSnapshotAdapter:
  calls: "NotesPreview.observe → display_state; NotesPreview.observe → read_notes"
Пояснения, источники и ограничения

Суть изменения

В PR добавлены локальный просмотр сохранённых заметок, адаптер снимков, классификация состояний, HTTP-граница и браузерная mind map; в `SpecGraph.md` добавлена ссылка на новую DocC-страницу. Код реализует чтение текущей revision, отображение свежего/пустого/устаревшего/недоступного состояния и сохранение последнего успешного снимка при ошибках. Документы уточняют статус как технический прототип при ожидающем рассмотрения SpecDraft, сохраняют границу существующего NotesStore и исключают редактирование, историю, продвижение и каноническую публикацию. Указанные в документах тестовые и браузерные наблюдения — сообщения источников; здесь выполнение не проверялось.

Интерпретация выбранных исходников; порядок узлов не означает порядок выполнения.

− и + показывают удаление и добавление в соответствующей ветке проекции; смена родителя тоже выделена, даже если строка узла не изменилась.

Связи и основания

Связи описаны отдельно от вложенности .hc; основания — в правой колонке.

Связь Что видно в источниках Основания
NotesPreview.observe → read_notes После; интерпретация исходников; вызов операции. В `NotesPreview.observe` непосредственно вызывается `read_notes(self.workspace, node_id=self.node_id, history_limit=0)`; это связывает адаптер с существующим чтением только текущего снимка. Реализация целевой функции не представлена, поэтому детали её внутреннего поведения не выводятся. snapshot.py: NotesPreview L14–51, observe L21–51
NotesPreview.observe → display_state После; интерпретация исходников; вызов операции. После попытки чтения `observe` формирует `DisplayFacts` из `failed`, наличия snapshot и наличия nodes и непосредственно передаёт их в `display_state`; это решение состояния для ответа API. snapshot.py: NotesPreview L14–51, observe L21–51
display_state → DISPLAY_STATE_SPEC.decide После; интерпретация исходников; вызов операции. `display_state` вызывает `DISPLAY_STATE_SPEC.decide(facts, recorder=recorder)` и возвращает значение решения. Порядок правил задан `FirstMatch.with_fallback`: stale, unavailable, empty, затем current. display_state.py: display_state L22–22
create_server → NotesPreview После; интерпретация исходников; вызов операции. `create_server` непосредственно создаёт `preview = NotesPreview(workspace, node_id)`, а обработчик маршрута `/api/notes` вызывает `preview.observe()` и сериализует результат в JSON. Здесь показан путь подготовки ответа для HTTP; выполнение сервера не наблюдалось. server.py: create_server L18–69; snapshot.py: NotesPreview L14–51, observe L21–51
refresh → /api/notes После; интерпретация исходников; вызов операции. Браузерная функция `refresh` вызывает `fetch("/api/notes", {cache: "no-store"})`, разбирает JSON и передаёт полученный snapshot в `render`; после завершения назначает следующий опрос через `setTimeout(refresh, 650)`. Серверный маршрут выдаёт этот JSON из `preview.observe()`. app.js: JSON, setTimeout L145–154; server.py: L1–69

Связи в Hypercode (.hcs)

Это неполные выборки связей из каждой версии. Отсутствие связи в одной из выборок не устанавливает её добавление или удаление. Пустой лист означает, что связи для этой версии не выбраны.

before.hcs

# Paired review context; no relationship recorded on this side.

after.hcs

DisplayStatePolicy:
  # После; интерпретация исходников; вызов операции. `display_state` вызывает `DISPLAY_STATE_SPEC.decide(facts, recorder=recorder)` и возвращает значение решения. Порядок правил задан `FirstMatch.with_fallback`: stale, unavailable, empty, затем current.
  # Sources: src_2ec4ac4224dbf53a03652f3e95aa721f67ddf9e29a6e6209c1acb4b4d3720e19
  calls: "display_state → DISPLAY_STATE_SPEC.decide"
LocalPreviewBoundary:
  # После; интерпретация исходников; вызов операции. `create_server` непосредственно создаёт `preview = NotesPreview(workspace, node_id)`, а обработчик маршрута `/api/notes` вызывает `preview.observe()` и сериализует результат в JSON. Здесь показан путь подготовки ответа для HTTP; выполнение сервера не наблюдалось.
  # Sources: src_315b5e1b41f782f04b654f3a465f7c4225ab9b9daceaa74cf58ddee08e94d3d5, src_47e3f6cde990f0e0aa35a6332ef0ff2c2a4a6d5cf1436350da3f971ff99aacb6
  calls: "create_server → NotesPreview"
NotesMindMapView:
  # После; интерпретация исходников; вызов операции. Браузерная функция `refresh` вызывает `fetch("/api/notes", {cache: "no-store"})`, разбирает JSON и передаёт полученный snapshot в `render`; после завершения назначает следующий опрос через `setTimeout(refresh, 650)`. Серверный маршрут выдаёт этот JSON из `preview.observe()`.
  # Sources: src_f85dc2a9a7fc023fb86e5252cdabf432c33a24dc851ba0d0de062129ce61c877, src_315b5e1b41f782f04b654f3a465f7c4225ab9b9daceaa74cf58ddee08e94d3d5
  calls: "refresh → /api/notes"
NotesSnapshotAdapter:
  # После; интерпретация исходников; вызов операции. После попытки чтения `observe` формирует `DisplayFacts` из `failed`, наличия snapshot и наличия nodes и непосредственно передаёт их в `display_state`; это решение состояния для ответа API.
  # Sources: src_47e3f6cde990f0e0aa35a6332ef0ff2c2a4a6d5cf1436350da3f971ff99aacb6
  # После; интерпретация исходников; вызов операции. В `NotesPreview.observe` непосредственно вызывается `read_notes(self.workspace, node_id=self.node_id, history_limit=0)`; это связывает адаптер с существующим чтением только текущего снимка. Реализация целевой функции не представлена, поэтому детали её внутреннего поведения не выводятся.
  # Sources: src_47e3f6cde990f0e0aa35a6332ef0ff2c2a4a6d5cf1436350da3f971ff99aacb6
  calls: "NotesPreview.observe → display_state; NotesPreview.observe → read_notes"

Ответственности и источники

  • SpecDraftLivePreview — Новая реализация подготавливает локальный просмотрщик сохранённых заметок. `NotesPreview.observe` читает текущий снимок, удерживает последний успешный при ошибке и классифицирует состояние; `create_server` предоставляет фиксированные HTTP-маршруты. Документы задают границу: просмотр только текущего чернового снимка, без редактирования, утверждения, отката и канонической публикации. Корневого .hc для этой продуктовой области нет среди представленных источников, поэтому это выведенная композиция, а не перенос роли существующей карты. docs/proposals/0228_specdraft_live_preview.md — после; Sources/SpecGraph/Documentation.docc/SpecDraftLivePreview.md — после; tools/specdraft_preview/snapshot.py — после; tools/specdraft_preview/server.py — после

  • NotesSnapshotAdapter — Новая ответственность адаптера заметок: `NotesPreview.observe` обращается к `read_notes` с `history_limit=0`, сохраняет только revision/canonical/nodes/links/omitted_nodes и публикует `canonical: false`. На ошибке прежний снимок остаётся доступен; потеря ранее наблюдавшейся revision отвергается проверкой непрерывности. Это не NotesStore: предложение прямо сохраняет существующее хранилище как источник, а реализация описывает себя как адаптер и per-sidecar last-good projection. tools/specdraft_preview/snapshot.py — после; docs/proposals/0228_specdraft_live_preview.md — после

  • DisplayStatePolicy — Новая политика отображения получает неизменяемые факты и выбирает состояние через упорядоченный `FirstMatch.with_fallback`: stale, unavailable, empty, затем current. Предикаты различают неудачное чтение с/без снимка и успешное чтение без узлов; continuity запрещает трактовать пропажу ранее сохранённой головы как пустую заметку. Это решение состояния, отдельное от файлового и HTTP-ввода согласно предложению. tools/specdraft_preview/context.py — после; tools/specdraft_preview/display_state.py — после; tools/specdraft_preview/empty_snapshot_spec.py — после; tools/specdraft_preview/snapshot_continuity_spec.py — после; tools/specdraft_preview/stale_snapshot_spec.py — после; tools/specdraft_preview/unavailable_snapshot_spec.py — после

  • LocalPreviewBoundary — Новая граница локальной доставки: `create_server` создаёт `NotesPreview`, привязывает HTTP-сервер к 127.0.0.1 и обслуживает только фиксированные assets и `/api/notes`; POST отклоняется, запрос произвольного пути возвращает 404. Это новая responsibility, выведенная из кода, а не существующая спецификация. Документация отдельно указывает read-only/loopback как предложенные инженерные ограничения, не как требования исходного пользователя. tools/specdraft_preview/server.py — после; tools/specdraft_preview_cli.py — после; docs/reviews/0228_specdraft_live_preview/specdraft.md — после

  • NotesMindMapView — Новый браузерный потребитель строит mind map, показывает revision, атрибуцию источников и выбранные связи, а также опрашивает `/api/notes` каждые 650 мс и обновляет вид при изменении снимка. Текст записывается через `textContent`. Это реализует визуальную часть заявленного живого просмотра; 100-узловой профиль и браузерная обработка ошибок в документах отмечены непроверенными. tools/specdraft_preview/static/app.js — после; docs/proposals/0228_specdraft_live_preview.md — после; docs/reviews/0228_specdraft_live_preview/specdraft.md — после

Границы анализа

PR #804: ddf10b48fe8c0c288cf5597a04313185a4879e95 → 2a9ac4ce09b357a3ff83e613f48a9005e7210939.

Исходников в анализе: 30; пропущено: 23.

Компилятор проверил структуру Hypercode и ссылки. Соответствие интерпретации коду и поведение программы этим не доказаны. Анализ ограничен предоставленными исходниками и фрагментами контекста; выполнение программы не наблюдалось.

  • Конфигурация: tools/intent_decision_reviews/0228_specdraft_live_preview.json; after; охват complete; фрагментов 1.

Неизменённых файлов контекста по Git blob: 5. Их фрагменты до и после могут различаться охватом.

  • До и после нет представленных .hc/.hcs для этой продуктовой области; композиция и роли выведены по документам и коду, а не подтверждены авторской картой.

  • В change_inventory есть 12 изменённых записей с политически скрытыми путями; содержание этих файлов недоступно, поэтому их изменения нельзя описать или отнести к узлам.

  • В коде вызываются `conversation_notes.api.read_notes` и используются `NotesError`, но их реализации не представлены; точный контракт чтения за пределами приведённых вызовов неизвестен.

  • Реализация `SpecificationCore.FirstMatch`, `PredicateSpec` и `TraceRecorder` не дана; анализ опирается на видимые вызовы и определения предикатов.

  • Статические файлы `index.html`, `style.css` и `icon.svg` перечислены в сервере, но не предоставлены; их содержимое не оценивалось.

  • Тестовый файл присутствует и его проверки можно прочитать, однако запуск тестов не наблюдался. Документация отдельно называет непроверенными браузерное восстановление после ошибок, hostile-text rendering и профиль на 100 узлов.

  • Одинаковый полный blob `Sources/SpecGraph/Documentation.docc/SpecGraph.md` в diff-контексте и одинаковые blobs в `unchanged_files` подтверждают только неизменность перечисленных контекстных файлов; они не описывают скрытые изменения.

  • Пропущено: CONTRIBUTING.md — context_excerpted (после: 1, до: 1).

  • Пропущено: docs/product_workspace_graph_versioning_roadmap.md — input_byte_limit (после: 1, до: 1).

  • Пропущено: docs/static_artifact_publish.md — input_byte_limit (после: 1, до: 1).

  • Пропущено: docs/supervisor_refactor_roadmap.md — input_byte_limit (после: 1); incomplete_pair (до: 1).

  • Пропущено: docs/experiments/ontology_decision_change.md — context_excerpted (до: 1).

  • Пропущено: docs/experiments/ontology_decision_counts.md — context_excerpted (до: 1).

  • Пропущено: docs/product_workspace_stable_mode_guide.md — context_excerpted (до: 1).

  • Пропущено: путь скрыт политикой — unsupported_format (после: 12).

Точные диапазоны источников по узлам

SpecDraftLivePreview

  • docs/proposals/0228_specdraft_live_preview.md — после: L1–132

  • Sources/SpecGraph/Documentation.docc/SpecDraftLivePreview.md — после: L1–57

  • tools/specdraft_preview/snapshot.py — после: L14–51, L21–51

  • tools/specdraft_preview/server.py — после: L18–69

NotesSnapshotAdapter

DisplayStatePolicy

  • tools/specdraft_preview/context.py — после: L1–24

  • tools/specdraft_preview/display_state.py — после: L1–24

  • tools/specdraft_preview/empty_snapshot_spec.py — после: L1–10

  • tools/specdraft_preview/snapshot_continuity_spec.py — после: L1–10

  • tools/specdraft_preview/stale_snapshot_spec.py — после: L1–10

  • tools/specdraft_preview/unavailable_snapshot_spec.py — после: L1–10

LocalPreviewBoundary

  • tools/specdraft_preview/server.py — после: L18–69

  • tools/specdraft_preview_cli.py — после: L1–38

  • docs/reviews/0228_specdraft_live_preview/specdraft.md — после: L20–23, L57–60

NotesMindMapView

  • tools/specdraft_preview/static/app.js — после: L7–11, L13–22, L46–52, L69–74

  • docs/proposals/0228_specdraft_live_preview.md — после: L1–132

  • docs/reviews/0228_specdraft_live_preview/specdraft.md — после: L1–98

Ок или не ок?

CI · результаты проверок

Снимок для 2a9ac4ce · 2026-10-26T09:18:08Z (UTC).

Результат check-run не доказывает выполнение конкретного теста, полноту покрытия или соответствие архитектуре.

Проверка Статус Результат
Deploy landing page to static host completed skipped
Deploy bundle to static host completed skipped
deploy completed skipped
Prepare case-sensitive redirect artifact completed skipped
publication-diagnostic-compatibility (3.14) completed success
publication-diagnostic-compatibility (3.10) completed success
spec-evidence completed success
registered-rule-reuse completed success
test completed success
python-quality completed success
Build static artifact bundle completed success
Build DocC technical surface completed success

Снимок неполный: показано не более 12 проверок.

Отсутствие, ожидание или сбой CI не блокируют архитектурный обзор.

Review gate: review thread.

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Intent Atoms · v1

Scope: specification YAML in specs/nodes

Status: complete
Count: 302 → 302 (+0)
Diff: +0 added, −0 removed, 0 modified
Revisions: c4e98034fb01 → f97463498b51
Profile: specgraph-intent-atoms-v1 (SHA-256 54caf075dafc)
Analyzer: 1.0.1 (SHA-256 aa7c646a25ea)

Proposal obligations · draft

Status: complete for declared fields
Count: 8 → 12 (+4)
Diff: +4 added, −0 removed, 0 modified
Coverage: explicit YAML declarations in docs/proposals; unannotated Markdown is not assessed.
Draft counts are separate from specification counts; they do not establish review, approval or canonical promotion.

Informational only; this report does not gate merge readiness.

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

SpecificationMetrics · diagnostic PR measurement

Metric Base PR head (Δ)
Specifications (S) 121 125 (+4)
Remaining opportunities (U) 10285 10294 (+9)
S/U 0.0117647 0.012143
Dead Specifications 0 0
Unknown Specifications 0 0

Collection: base complete, head complete.
Primary provisional: base False, head False.
Revisions: c4e98034fb01 → f97463498b51; contract 943b09cbbe20.
Base diagnostics: none reported.
Head diagnostics: none reported.

  • Python CC / Cog: cc_sum +17; cc_max +0; cog_sum +17; cog_max +0; sloc +190
  • Clone pairs / duplicate lines / tokens: clone_pairs +0; duplicate_lines +0; duplicate_tokens +0

Scope: files assigned application by the manifest; tests/ is test, and the comment renderer is framework.
Informational only. Counts and metrics do not decide eligibility, correctness, or merge readiness.
Collection run
Detailed JSON reports and counting contract
Artifact presence does not imply a complete measurement; inspect report statuses and diagnostics. Downloads require GitHub access and expire with artifact retention.

Comment thread Sources/SpecGraph/Documentation.docc/SpecDraftLivePreview.md
…preview-proposal

# Conflicts:
#	tools/docc_sync_contract.json
#	tools/proposal_promotion_registry.json
#	tools/proposal_runtime_registry.json
Comment thread Sources/SpecGraph/Documentation.docc/SpecDraftLivePreview.md
@SoundBlaster
SoundBlaster merged commit 5b50da3 into main Oct 26, 2026
14 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.

1 participant