From 15d1a59168b919f58347c1898f531256598cf070 Mon Sep 17 00:00:00 2001 From: ribdsp <113304041+ribdsp@users.noreply.github.com> Date: Tue, 1 Sep 2026 06:41:18 +0700 Subject: [PATCH] docs: complete the open-source community standards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub's community profile sat at 57%: a code of conduct, a security policy, issue templates and a PR template were all missing. Adding them as templates would have been easy and useless, so each one carries the rules this repository actually has rather than the generic text. CODE_OF_CONDUCT.md — Contributor Covenant 2.1, plus one project-specific clause. A session recording is a full reconstruction of a page and everything that was on it, so publishing a real person's recording is treated as publishing their private information: a conduct matter, not a technical one. The existing rule against committing recordings covers this repository; it did not cover an issue comment with a file attached. SECURITY.md — private reporting route, and an explicit in-scope list, because the boundaries here are testable rather than aspirational: nothing from the model is executed (no-eval.test.ts greps the source and fails the build), every response has a budget, the recorder captures shapes and not values, and no committed recording is real. bugbait/ being broken on purpose is stated as out of scope so nobody files its wrong API responses as vulnerabilities. Issue templates — bug reports ask which WebMCP mode you were in, because the polyfill, the origin trial and the webmcp-tools inspector are three different execution paths and a bug in one often does not exist in the others. The tool proposal template asks why the page must compute the answer rather than a server, which is the question that decides most proposals. PR template — the three non-negotiable rules as checkboxes, since a reviewer cannot verify any of them by reading a diff, plus the tsc/test line that catches "it compiles on my machine". Also, from reading these files as a newcomer would: - git clone was a placeholder in both README and CONTRIBUTING. It is now the real URL. - CONTRIBUTING's setup block said `cd bugbait` after `cd traces`, which fails from inside traces/. Fixed to `cd ../bugbait`, matching the README. - The video badge said "under 3 min", which describes the contest rule rather than the video. - Added the Devpost submission link, so the repository and the write-up point at each other. Verified: tsc --noEmit clean, 309 tests passing across 25 files, all three issue-template YAML files parse. --- .github/ISSUE_TEMPLATE/bug_report.yml | 104 ++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 17 +++ .github/ISSUE_TEMPLATE/tool_proposal.yml | 85 +++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 71 +++++++++++++ CODE_OF_CONDUCT.md | 128 +++++++++++++++++++++++ CONTRIBUTING.md | 14 ++- README.md | 19 +++- SECURITY.md | 88 ++++++++++++++++ 8 files changed, 518 insertions(+), 8 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/tool_proposal.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..6f5d254 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,104 @@ +name: Bug report +description: Something in Traces behaves incorrectly. +labels: [bug] +body: + - type: markdown + attributes: + value: | + Two things make a Traces bug report actionable, and neither is obvious: + + **Which WebMCP mode you were in.** The polyfill, the origin trial and the `webmcp-tools` + inspector are three different execution paths, and a bug in one often does not exist in the + others. The header pill in the app tells you: `live` means real WebMCP, `polyfill` means the + 17 tools are not registered with a host. + + **Which recording.** Every recording is synthetic and reproducible, so naming it makes the bug + reproducible too. If it only happens on a recording you made yourself, **describe it — do not + attach it.** A recording is a full reconstruction of a page and everything that was on it; see + [CODE_OF_CONDUCT.md](https://github.com/ribdsp/Traces/blob/main/CODE_OF_CONDUCT.md). + + Found a security problem instead? Don't file it here — see + [SECURITY.md](https://github.com/ribdsp/Traces/blob/main/SECURITY.md). + + - type: textarea + id: what-happened + attributes: + label: What happened + description: What you saw, and what you expected instead. + validations: + required: true + + - type: dropdown + id: surface + attributes: + label: Where + options: + - A WebMCP tool + - The replay player / timeline + - The findings panel (markers, hypotheses, tasks, report) + - The activity feed or undo + - bugbait (the demo checkout app) + - Build, install, or typecheck + - Somewhere else + validations: + required: true + + - type: input + id: tool-name + attributes: + label: Tool name and arguments + description: If a tool was involved, name it and paste the arguments verbatim. + placeholder: 'bisect_state — { selector: "select[name=province]", predicate: { kind: "optionCount", equals: 0 } }' + + - type: dropdown + id: webmcp-mode + attributes: + label: WebMCP mode + description: The header pill in the app says which one. + options: + - live — Chrome/Edge origin trial + - polyfill — the development fallback + - webmcp-tools browser extension + - Not applicable — the bug is in the UI + validations: + required: true + + - type: input + id: agent-client + attributes: + label: Agent client + description: Which agent called the tool, if one did. "By hand from the inspector" is a valid answer. + placeholder: ChatGPT Desktop 1.2026.x / by hand from the inspector + + - type: input + id: recording + attributes: + label: Recording + description: The slug from the picker, plus the timestamp in ms if the bug is at a particular moment. + placeholder: empty-province, around 28000ms + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + value: | + 1. + 2. + 3. + validations: + required: true + + - type: input + id: browser + attributes: + label: Browser and OS + placeholder: Chrome 149 / Windows 11 + validations: + required: true + + - type: textarea + id: console + attributes: + label: Console output + description: Errors from the devtools console, if there were any. + render: text diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..e382621 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,17 @@ +blank_issues_enabled: false +contact_links: + - name: Security vulnerability + url: https://github.com/ribdsp/Traces/security/advisories/new + about: Report privately. Please don't open a public issue for a security problem. + - name: The 17-tool contract + url: https://github.com/ribdsp/Traces/blob/main/docs/tools.md + about: Every tool's arguments, response shape, budget and failure modes. Read this before proposing an 18th. + - name: Architecture and threat model + url: https://github.com/ribdsp/Traces/blob/main/docs/architecture.md + about: How the pieces fit, and which boundaries are deliberate. + - name: The WebMCP specification + url: https://github.com/webmachinelearning/webmcp + about: Questions about WebMCP itself — including the missing "image" content type — belong upstream. + - name: The submission this was built for + url: https://devpost.com/software/traces-3snwtz + about: Traces was built for The WebMCP Challenge. Context, video, and the write-up live here. diff --git a/.github/ISSUE_TEMPLATE/tool_proposal.yml b/.github/ISSUE_TEMPLATE/tool_proposal.yml new file mode 100644 index 0000000..c0213a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tool_proposal.yml @@ -0,0 +1,85 @@ +name: Tool proposal +description: Propose an 18th WebMCP tool, or a change to one of the 17. +labels: [tool proposal] +body: + - type: markdown + attributes: + value: | + The tool surface is the interface a model reads, so it is designed rather than accumulated. The + questions below are the ones a proposal has to answer — they map onto + [CONTRIBUTING.md § Adding a tool](https://github.com/ribdsp/Traces/blob/main/CONTRIBUTING.md#adding-a-tool), and the second + one is the one that decides most proposals. + + - type: textarea + id: what + attributes: + label: What the tool does + description: One paragraph. Include the name you'd give it and the shape of what it returns. + validations: + required: true + + - type: textarea + id: why-the-page + attributes: + label: Why the page must compute this, rather than a server + description: > + The point of WebMCP here is that the answer lives in live browser state — a replayed DOM, + computed styles, layout boxes, a binary search that has to re-render the page 17 times. If the + same answer could come from an API call over the recording JSON, it does not need to be a tool. + validations: + required: true + + - type: textarea + id: prompt + attributes: + label: The prompt an agent would be answering + description: > + Written the way a user would phrase it, not the way the tool would. A tool that only works when + the caller already knows the right arguments is a tool a model will not reach for. + placeholder: "Why is the Pay button still disabled at the end of the recording?" + validations: + required: true + + - type: input + id: budget + attributes: + label: Proposed response budget + description: > + Every response has one — lines, characters, entries, or matches — plus a `truncated` flag and a + sentence telling the agent what to do about it. Say which. + placeholder: 20 entries, truncated → "narrow the time range" + validations: + required: true + + - type: textarea + id: failure-modes + attributes: + label: How it fails readably + description: > + Every rejection path returns a sentence an agent can correct itself from, not a thrown + exception. List the rejections you can foresee and what each one would say. + validations: + required: true + + - type: checkboxes + id: boundaries + attributes: + label: Boundaries + description: > + These come from the [threat model](https://github.com/ribdsp/Traces/blob/main/docs/threat-model.md). A proposal that needs one + of them relaxed is a discussion about the threat model first, and a tool second. + options: + - label: Nothing the model supplies would be executed — no `eval`, no `new Function`, no compiled regex, no interpolated expression. + required: true + - label: It reads recorded state only. It does not need a real user's session. + required: true + - label: It does not return input values or request/response bodies. The recorder never captures those. + required: true + + - type: textarea + id: alternatives + attributes: + label: What you tried with the existing 17 + description: > + Which of the current tools you composed, and where the composition fell short. See + [docs/tools.md](https://github.com/ribdsp/Traces/blob/main/docs/tools.md). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..b3374f7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,71 @@ + + +## What this changes + + + +Closes # + +## Area touched + + + +- [ ] `lib/replay` — recording load, checkpoints, event digest +- [ ] `lib/dom` — DOM compression, diff, layout +- [ ] `lib/bisect` — binary search and predicate evaluation +- [ ] `lib/report` — report building and verification +- [ ] `lib/webmcp` — tool registration, schemas, blocking gates +- [ ] `components/` — UI +- [ ] `bugbait/` — the demo checkout app +- [ ] Docs only + +PRs touching `lib/dom`, `lib/bisect` or `lib/webmcp` need a second reader — those are where bugs hide +without announcing themselves. + +## The three rules + + + +- [ ] **Nothing from the model is executed.** No `eval`, no `new Function`, no dynamic `import()` of a + model-supplied string, no compiled regex from model text. New predicate capability means a new + variant plus its evaluator, never an escape hatch. +- [ ] **Every new or changed tool response has a budget**, a `truncated` flag, and a sentence telling + the agent what to do about it rather than only that something was cut. +- [ ] **No real user recording is added.** Every recording here is synthetic, generated by `bugbait/`. + +## Verification + +```bash +cd traces && npm install && npx tsc --noEmit && npm test +``` + +- [ ] `npx tsc --noEmit` is clean +- [ ] `npm test` passes +- [ ] If this touches `lib/dom`, `lib/bisect` or `lib/report`: tests added + +Paste the test summary line: + +``` +``` + +## If this touches a tool + +- [ ] Called from the `webmcp-tools` inspector with hand-typed arguments +- [ ] Called from a real agent, with a task phrased the way a user would phrase it +- [ ] Failures come back as readable tool errors, not thrown exceptions +- [ ] [docs/tools.md](https://github.com/ribdsp/Traces/blob/main/docs/tools.md) updated — the contract is documentation, not just code + +## Not done + + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c6b02bb --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a +harassment-free experience for everyone, regardless of age, body size, visible or invisible +disability, ethnicity, sex characteristics, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or +sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and +healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the + experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit + permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## One project-specific addition + +This project handles session recordings, and a recording is a full reconstruction of a page and +everything that was on it. **Publishing a recording of a real person's session — in an issue, a pull +request, a discussion, or a linked file — is treated as publishing their private information**, and +falls under the standards above rather than under a technical rule. + +Use the synthetic recordings generated by [`bugbait/`](bugbait). If you need to demonstrate a bug that +only reproduces on a real site, describe it; don't attach the recording. See +[SECURITY.md](SECURITY.md) if you believe one has already been published here. + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior +and will take appropriate and fair corrective action in response to any behavior that they deem +inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, +code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and +will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is +officially representing the community in public spaces. Examples of representing our community include +using an official email address, posting via an official social media account, or acting as an +appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the maintainers +by contacting [@ribdsp](https://github.com/ribdsp) on GitHub. All complaints will be reviewed and +investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any +incident. + +If a report concerns a maintainer, or you would rather not contact a maintainer directly, use +[GitHub's own abuse reporting](https://github.com/contact/report-abuse), which reaches GitHub Support +rather than this project. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for +any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or +unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the +nature of the violation and an explanation of why the behavior was inappropriate. A public apology may +be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people +involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified +period of time. This includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate +behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the +community for a specified period of time. No public or private interaction with the people involved, +including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this +period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained +inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes +of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at +https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ee8361..9f489e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,16 +4,24 @@ Thanks for looking. Traces started as a hackathon project, so the codebase is sm conventions are few — but the few there are exist for reasons, and this document is where they're written down. +Two neighbours to this file: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) covers participation, including +the one project-specific clause about publishing recordings of real people, and +[SECURITY.md](SECURITY.md) is where a vulnerability goes instead of into a public issue. + --- ## Getting set up ```bash -git clone -cd traces && npm install && npm run dev # the app → localhost:3000 -cd bugbait && npm install && npm run dev # the broken demo → localhost:3001 +git clone https://github.com/ribdsp/Traces.git +cd Traces + +cd traces && npm install && npm run dev # the app → localhost:3000 +cd ../bugbait && npm install && npm run dev # the broken demo → localhost:3001 ``` +Two terminals: both dev servers run at once, and the app is not much use without a recording to load. + To exercise the tool surface you need WebMCP available in the browser. Three options, in descending order of fidelity: diff --git a/README.md b/README.md index a5421cf..f42d159 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **A session replay engine that an AI agent can interrogate — through WebMCP.** [![Live demo](https://img.shields.io/badge/demo-traces.ribdsp.com-111827?style=flat-square)](https://traces.ribdsp.com) -[![Video](https://img.shields.io/badge/video-under_3_min-b91c1c?style=flat-square)](https://youtu.be/KyME2kG7_PI) +[![Video](https://img.shields.io/badge/Video-watch-b91c1c?style=flat-square)](https://youtu.be/KyME2kG7_PI) [![WebMCP tools](https://img.shields.io/badge/WebMCP-17_tools-374151?style=flat-square)](docs/tools.md) [![Tests](https://img.shields.io/badge/tests-309_passing-374151?style=flat-square)](CONTRIBUTING.md) [![Licence](https://img.shields.io/badge/licence-MIT-374151?style=flat-square)](LICENSE) @@ -22,6 +22,7 @@ Built for [The WebMCP Challenge](https://webmcp.devpost.com/). - **Live demo:** [traces.ribdsp.com](https://traces.ribdsp.com) - **Video:** [youtu.be/KyME2kG7_PI](https://youtu.be/KyME2kG7_PI) +- **Submission:** [devpost.com/software/traces-3snwtz](https://devpost.com/software/traces-3snwtz) - **Tool reference:** [docs/tools.md](docs/tools.md) - **Architecture:** [docs/architecture.md](docs/architecture.md) · **Threat model:** [docs/threat-model.md](docs/threat-model.md) @@ -305,10 +306,11 @@ Traces is one workspace with two participants, and it's built so you can always Requires Node 20+. ```bash -git clone && cd Traces +git clone https://github.com/ribdsp/Traces.git +cd Traces -cd traces && npm install && npm run dev # the app → http://localhost:3000 -cd ../bugbait && npm install && npm run dev # the broken demo → http://localhost:3001 +cd traces && npm install && npm run dev # the app → http://localhost:3000 +cd ../bugbait && npm install && npm run dev # the broken demo → http://localhost:3001 ``` Open `localhost:3000`, pick one of the three bundled recordings, and connect an agent. @@ -449,7 +451,8 @@ nothing leaves the page that wasn't asked for.** - **Every committed recording is synthetic.** Full analysis, including what is deliberately **out of scope**: -**[docs/threat-model.md](docs/threat-model.md)**. +**[docs/threat-model.md](docs/threat-model.md)**. To report something rather than read about it: +**[SECURITY.md](SECURITY.md)** — privately, please, not in a public issue. --- @@ -512,6 +515,12 @@ See [CONTRIBUTING.md](CONTRIBUTING.md). Three rules matter more than the rest: * model is ever executed**, **every tool response has a budget**, and **no real user recordings in this repository**. +Bugs and tool proposals both have [issue templates](https://github.com/ribdsp/Traces/issues/new/choose) +— the questions in them are the ones that make a report actionable, particularly *which WebMCP mode* +you were in. Participation is covered by the [Code of Conduct](CODE_OF_CONDUCT.md), which has one +project-specific clause: publishing a recording of a real person's session is treated as publishing +their private information. + ## Licence [MIT](LICENSE) — © 2026 the Traces contributors. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..bca4b11 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,88 @@ +# Security Policy + +Traces hands a language model influence over a running page, so the security posture is a design +constraint here rather than a checklist. The reasoning, the trust boundaries, and the things +deliberately left out of scope are all in [docs/threat-model.md](docs/threat-model.md) — read that +first if you want to know what this project already considers an attack. + +This file is the short version, plus how to tell us. + +## Supported versions + +There is one supported version: whatever is on `main`. There are no release branches and no +backports. + +| Version | Supported | +|---|---| +| `main` | ✅ | +| Anything else | ❌ | + +## Reporting a vulnerability + +**Please do not open a public issue for a security problem.** + +Use GitHub's private reporting: +[**Report a vulnerability**](https://github.com/ribdsp/Traces/security/advisories/new). It creates a +private thread visible only to you and the maintainers. + +If that link is unavailable, contact [@ribdsp](https://github.com/ribdsp) on GitHub and say only that +you have a security report — no details in a public channel. + +What helps: + +- The tool name, if a WebMCP tool is involved, and the exact arguments +- Which WebMCP mode you were in: real origin trial, the polyfill, or the `webmcp-tools` inspector +- Browser and version +- Whether the input came from a model, a human, or a recording file +- What you expected the boundary to be, and what actually happened + +What to expect: this started as a hackathon project and is maintained on a best-effort basis. You will +get an acknowledgement, and a real answer rather than a template. If a report is valid we will say so +publicly in the fix. + +## In scope + +The boundaries below are the ones this project claims to hold. A way past any of them is a +vulnerability, and the first three are the ones with tests behind them: + +- **Nothing that comes from the model is executed.** Bisect predicates are a closed set of validated + structured objects — never `eval`, never `new Function`, never an interpolated expression, never a + compiled regex. `no-eval.test.ts` greps the source and fails the build if `eval(` or `new Function` + appears anywhere. Any path that gets model-supplied text evaluated is in scope. +- **Every tool response has a size budget**, enforced by tests rather than by intention. A response + that can be made to exceed its budget — or a compression path that leaks the full DOM — is in scope. +- **No real user recordings in this repository.** Every committed recording is synthetic, produced by + [`bugbait/`](bugbait). If you find one that looks like a real session, that is a valid report and an + urgent one. +- **The recorder records shapes, not contents.** `maskAllInputs: true` is mandatory: the recorder + stores that a field was typed into and how many characters, never the value. The XHR/fetch recorder + stores method, URL, status and timing, never request or response bodies. A path that captures a + value or a body is in scope. +- **Selector and timestamp validation.** A selector or timestamp from a model that reaches an unguarded + API, or escapes the recording's time range, is in scope. +- **Origin-trial token handling.** The token belongs in `.env.local` and must never be committed. A + token in git history is a valid report. + +## Out of scope + +Not because they don't matter, but because they are known and stated rather than hidden: + +- **A malicious recording file you load yourself.** Traces replays recordings you give it. Loading a + hostile file is equivalent to opening a hostile document — see the threat model for where the line + is drawn. +- **The WebMCP spec itself,** including the absence of an `"image"` content type. Report those + upstream at [webmachinelearning/webmcp](https://github.com/webmachinelearning/webmcp). +- **Anything requiring a compromised browser, extension, or agent client.** If the agent host is + already hostile, it does not need our tools. +- **`bugbait/` being insecure on purpose.** It is a deliberately broken checkout app whose whole job is + to produce bugs to record. Its API routes return wrong data by design. Do not report those as + vulnerabilities; do report anything in `bugbait/` that could harm someone running it locally. +- **Denial of service against your own tab.** A bisect over a huge range is slow. That is a budget + question, not a security one. + +## Nothing to log into + +There is no backend, no database, no API key, and no account. Recordings are static JSON, and every +computation — replay, binary search, DOM compression, report validation — happens in the tab. Nothing +is uploaded. That removes an entire class of report, and it is the main reason the attack surface here +is small.