Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -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.
85 changes: 85 additions & 0 deletions .github/ISSUE_TEMPLATE/tool_proposal.yml
Original file line number Diff line number Diff line change
@@ -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).
71 changes: 71 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!--
Thanks for this. The checkboxes below aren't ceremony: the three rules are the ones a reviewer
cannot verify by reading a diff, and the verification line is the one that catches "it compiles on
my machine". Delete any section that genuinely doesn't apply.
-->

## What this changes

<!-- One paragraph. What was wrong or missing, and what it does now. -->

Closes #

## Area touched

<!-- The codebase is split by folder, not by feature. Tick the ones this PR lands in. -->

- [ ] `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

<!-- From docs/threat-model.md. A PR that breaks one is rejected even if everything else is good. -->

- [ ] **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

<!--
The `compress-dom`, `bisect` and `evaluatePredicate` suites were written first, as specifications.
Never make one pass by weakening an assertion, adding `.skip`, or deleting a case — a red test there
means the implementation is wrong. `no-eval.test.ts` is a security boundary, not a lint rule.

If you found a problem outside your area, say so here instead of fixing it: a patch that helpfully
repairs a neighbouring module hands its maintainer a conflict to resolve blind.
-->
Loading
Loading