Skip to content
Open
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
5 changes: 4 additions & 1 deletion eval/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ mutants/ naive React drafts the hidden tests must catch
results/ scored runs
```

Setup: `npm install` here (Solid 2.0.0-rc.21 from npm); `cargo build --release --bin rxc` in `../compiler` (its Solid pin is d2323b0, rc.19).
Setup: `npm install` here (Solid 2.0.0-rc.21 and Playwright from npm; set `CHROMIUM=/path/to/chromium` to drive a
system browser instead of Playwright's download); `cargo build --release --bin rxc` in `../compiler` (its Solid pin
is `ref/SOLID_NEXT`). A round is regradable only if its runs' sources are committed under `results/<round>/runs/`
(rounds 5, 7, 10 and 11 kept theirs in the session that ran them and cannot be regraded).
`RXC` and `RT_WEB` override the paths to the binary and `ref/compile/rt-web.ts`. (The pilot itself ran on PR #6's
crate before it merged, built with the same pin.)

Expand Down
3 changes: 2 additions & 1 deletion eval/harness/driver.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export async function serve(dist) {
return { url: `http://127.0.0.1:${http.address().port}/`, close: () => http.close() };
}

export async function launch() { return chromium.launch(); }
/** CHROMIUM=/path/to/chromium drives a system browser (NixOS and the like, where Playwright's download does not run). */
export async function launch() { return chromium.launch(process.env.CHROMIUM ? { executablePath: process.env.CHROMIUM } : {}); }

/** One test: a fresh page on the app, `run(app)` with the helpers below. Returns { ok, error }. */
export async function runTest(browser, url, test) {
Expand Down
28 changes: 28 additions & 0 deletions eval/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions eval/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"eslint-plugin-react-hooks": "7.0.0",
"eslint-plugin-solid": "^0.18.1",
"foldkit": "^0.170.0",
"playwright": "1.64.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"solid-js": "2.0.0-rc.21",
Expand Down
18 changes: 11 additions & 7 deletions eval/reference/chain2/rx/issues.rx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ export error NotFound(id: number) => `issue #${id} not found`

fn found(it, id: number) => it == null ? throw NotFound(id) : it

// the open list as shown (closes in flight already out of it) is the tab's count: it is read where the list is read,
// under the list's boundary, so it holds and reveals with the rows; other lists, loads and failures leave it as it was
component OpenCount(props: { n: number; onCount: (n: number) => void }) {
effect (props.n) {
props.onCount($0)
}
}

export component IssuesPage(props: { onOpenCount: (n: number) => void }) {
source user: string := "guest"
source filter: string := "open"
Expand All @@ -20,13 +28,6 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void }) {
source renameError: string = ""
source closeError: string = ""

// the open list as shown (closes in flight already out of it) is the tab's count; other lists, loads and failures
// leave the count as it was
effect ((filter == "open" ? issues.length : -1) catch (e) => -1) {
if ($0 >= 0) {
props.onOpenCount($0)
}
}

action assignTo(id: number, who: string) {
optimistic assignError := ""
Expand Down Expand Up @@ -83,6 +84,9 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void }) {
<div data-testid="list">
{loading on(filter) fallback { <p>loading {latest filter} issues</p> } {
{errored fallback(e) { <p>list error: {e.message}</p> } {
{if filter == "open" {
<OpenCount n={issues.length} onCount={n => { props.onOpenCount(n) }} />
}}
<ul>
{for it in issues {
<li data-testid="issue" onClick={() => {
Expand Down
18 changes: 11 additions & 7 deletions eval/reference/chain3/rx/issues.rx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export error NotFound(id: number) => `issue #${id} not found`

fn found(it, id: number) => it == null ? throw NotFound(id) : it

// the open list as shown (closes in flight already out of it) is the tab's count: it is read where the list is read,
// under the list's boundary, so it holds and reveals with the rows; other lists, loads and failures leave it as it was
component OpenCount(props: { n: number; onCount: (n: number) => void }) {
effect (props.n) {
props.onCount($0)
}
}

export component IssuesPage(props: { onOpenCount: (n: number) => void; onOpenHelp: (query: string, id: number) => void }) {
source user: string := "guest"
source filter: string := "open"
Expand All @@ -21,13 +29,6 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void; onOpenHel
source renameError: string = ""
source closeError: string = ""

// the open list as shown (closes in flight already out of it) is the tab's count; other lists, loads and failures
// leave the count as it was
effect ((filter == "open" ? issues.length : -1) catch (e) => -1) {
if ($0 >= 0) {
props.onOpenCount($0)
}
}

action assignTo(id: number, who: string) {
optimistic assignError := ""
Expand Down Expand Up @@ -84,6 +85,9 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void; onOpenHel
<div data-testid="list">
{loading on(filter) fallback { <p>loading {latest filter} issues</p> } {
{errored fallback(e) { <p>list error: {e.message}</p> } {
{if filter == "open" {
<OpenCount n={issues.length} onCount={n => { props.onOpenCount(n) }} />
}}
<ul>
{for it in issues {
<li data-testid="issue" onClick={() => {
Expand Down
18 changes: 11 additions & 7 deletions eval/reference/chain4/rx/issues.rx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export error NotFound(id: number) => `issue #${id} not found`

fn found(it, id: number) => it == null ? throw NotFound(id) : it

// the open list as shown (closes in flight already out of it) is the tab's count: it is read where the list is read,
// under the list's boundary, so it holds and reveals with the rows; other lists, loads and failures leave it as it was
component OpenCount(props: { n: number; onCount: (n: number) => void }) {
effect (props.n) {
props.onCount($0)
}
}

export component IssuesPage(props: { onOpenCount: (n: number) => void; onOpenHelp: (query: string, id: number) => void }) {
source user: string := "guest"
source filter: string := "open"
Expand All @@ -23,13 +31,6 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void; onOpenHel
// the newest row action's failure; row actions and the detail's leave each other's errors alone
source rowError: string = ""

// the open list as shown (closes in flight already out of it) is the tab's count; other lists, loads and failures
// leave the count as it was
effect ((filter == "open" ? issues.length : -1) catch (e) => -1) {
if ($0 >= 0) {
props.onOpenCount($0)
}
}

action assignTo(id: number, who: string, fromRow: boolean) {
if (fromRow) {
Expand Down Expand Up @@ -105,6 +106,9 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void; onOpenHel
<div data-testid="list">
{loading on(filter) fallback { <p>loading {latest filter} issues</p> } {
{errored fallback(e) { <p>list error: {e.message}</p> } {
{if filter == "open" {
<OpenCount n={issues.length} onCount={n => { props.onOpenCount(n) }} />
}}
<ul>
{for it in issues {
<li>
Expand Down
18 changes: 11 additions & 7 deletions eval/reference/count/rx/issues.rx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export error NotFound(id: number) => `issue #${id} not found`

fn found(it, id: number) => it == null ? throw NotFound(id) : it

// the open list as shown (closes in flight already out of it) is the tab's count: it is read where the list is read,
// under the list's boundary, so it holds and reveals with the rows; other lists, loads and failures leave it as it was
component OpenCount(props: { n: number; onCount: (n: number) => void }) {
effect (props.n) {
props.onCount($0)
}
}

export component IssuesPage(props: { onOpenCount: (n: number) => void }) {
source user: string := "guest"
source filter: string := "open"
Expand All @@ -19,13 +27,6 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void }) {
source renameError: string = ""
source closeError: string = ""

// the open list as shown (closes in flight already out of it) is the tab's count; other lists, loads and failures
// leave the count as it was
effect ((filter == "open" ? issues.length : -1) catch (e) => -1) {
if ($0 >= 0) {
props.onOpenCount($0)
}
}

action assignTo(id: number, who: string) {
optimistic assignError := ""
Expand Down Expand Up @@ -82,6 +83,9 @@ export component IssuesPage(props: { onOpenCount: (n: number) => void }) {
<div data-testid="list">
{loading on(filter) fallback { <p>loading {latest filter} issues</p> } {
{errored fallback(e) { <p>list error: {e.message}</p> } {
{if filter == "open" {
<OpenCount n={issues.length} onCount={n => { props.onOpenCount(n) }} />
}}
<ul>
{for it in issues {
<li data-testid="issue" onClick={() => {
Expand Down
72 changes: 72 additions & 0 deletions eval/results/rc21-regrade-2026-11-05/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Regrade on Solid 2.0.0-rc.21 (2026-11-05, not a round)

The rc.21 repin (41a6b1f) carried the fixes for every Solid issue the eval had filed but did not rerun anything. This
regrades what the repository holds, with rc.21 from npm and `rxc` from this commit. Round 10's and round 11's desks are
not in the repository (their run directories stayed in the session that ran them), so they are not here.

## References on the desk9 brief (`harness/grade.sh`: hidden, overlap, 20 fuzz seeds)

| app | hidden | overlap | fuzz seeds with a hole |
| --- | --- | --- | --- |
| chain4 .rx (count read with `latest issues`) | 77/77 | 38/38 | 3 |
| chain4 .rx (count read under the list's region) | 77/77 | 38/38 | 2 |
| chain4 React | 77/77 | 38/38 | 0 |
| recipe React (TanStack's optimistic-updates guide) | 77/77 | 22/38 | 7 |

The recipe React desk scores what round 9 recorded for it (22/38), so this setup grades as the rounds did. The chain4
.rx reference passes every hidden and overlap test, including "retry after not found" (#4425, #4627), which failed in
every .rx run from round 5 on.

The `latest issues` reference's three fuzz holes, replayed:

| seed | hole | cause | owner |
| --- | --- | --- | --- |
| 1 | the tab count shows 3 beside 2 rows, a close in flight | `latest issues` answers the re-asked truth, not the guess, once a list refresh lands under a pending close | Solid: `latest` should keep a shown guess until its hold commits (solidjs/solid#4689, ruled in #4695 decision 3, not built; DV-19) |
| 11 | an accepted rename's row shows the old title until the refresh lands | the row was not in the list when the rename was sent (`findIndex` -1): nothing was guessed on it | the app; `guide/async.md` §4 now says so |
| 15 | an accepted rename's detail heading shows the old title until the refresh lands | the detail was still loading when the rename was sent: nothing was guessed on it (the row guess held) | the app; the same |

Seed 1 was the reference as the checker suggested it: CN-3e refuses the count effect's read of `issues` outside the
`loading on(filter)` region and suggests `latest issues`. Four references (chain2, chain3, chain4, count) had the
outside read, predating the rule. By the spec (and Solid's own ruling, #4695 decision 3) `latest issues` answers the
guess the list shows, so that program is right and the hole is Solid's (DV-19, #4689, not built). The references
read the count where the list is read instead, in a small component under the list's region: it holds and reveals
with the rows, it is equally right by the spec, it does not depend on #4689, and it is what 10 of 12 agent desks in
rounds 10 and 11 wrote. With it, chain4 has two fuzz holes, both the app's (seeds 11 and 15), and chain2, chain3 and
count pass their own tasks' hidden and overlap tests (`graded/`).

Reducing seed 15 turned up a second Solid bug, solidjs/solid#4690: with nothing rendering a store, an effect reading it
sees a guess revert at the action's end, before the action's refresh lands, once an outside re-ask has landed under it.
A rendered reader keeps the guess, and so does an effect beside one; an effect over a source nothing renders reaches
it (DV-20, S-guess-reask-refresh's effect-only variant; `ref/oracle/repros/4690-guess-reask-refresh.mjs`). Fixed on
`next` (Ryan, 2026-11-05); recorded until the repin.

## Round 4's .rx apps (18, `results/change-2026-10-28/runs`) on rc.21 and this `rxc`

| | runs |
| --- | --- |
| pass every hidden and overlap test | 14 |
| refused by `STALE_WRITE_BACK` (AC-1e, added after round 4) | 3: small close-rx-1, small comments-rx-2, frontier rename-rx-3 |
| one overlap test failed | 1: small rename-rx-1, a guess on `detail` with `refresh issues` only |

The three refusals are the three the round 4 write-up predicted. The one failure is the shape `guide/async.md` §4 now
names ("refresh every question you guessed on"). Nothing in round 4's residue is Solid's.

## Reference suites on rc.21

Interpreter 114 pass; oracle and compiled 114 pass, 6 recorded divergences (DV-19 at four instants, DV-20 at two);
server render 107 pass, 7 skip (not rerun after the review fixes); types 156 pass; the crate agrees with ref/ on 321/321 programs.

S-store-8 (two actions' guesses on one row; a declined one reverts alone) had failed on the interpreter since the
commit that added it (edb76be): the interpreter kept one guess per node with one owner, so the newer action's guess took
the row and the older action's decline found nothing of its own to revert. Guesses are now entries per key and hold
(`ref/src/runtime.ts`), as H-11 says; the same-key variant added to S-store-8 passes on all three runners. A new answer that corrects a guess (D-34) marks
the action's entry spent instead of dropping it, so the action's re-ask still holds the corrected guess (D-35): with
the entry dropped, a closed row came back between the write landing and the re-ask (S-latest-reask's variant, `4 / 4`
for `2 / 4`; Solid shows `2 / 4`). The interpreter now follows #4695's D-34: a landing answer is compared with the guess (before,
only one that changed the truth corrected), the correction re-derives the graph, and the screen, the guess's effects
and `latest` of a shown guess keep it until the hold commits.

## Setup

`eval/package.json` now lists Playwright; `CHROMIUM=/path/to/chromium` drives a system browser in `harness/driver.mjs`
and `ref/ssr/run.ts`. `graded/`: the grade output per app above, and `round4-<tier>-<run>.txt` per round 4 app.
4 changes: 4 additions & 0 deletions eval/results/rc21-regrade-2026-11-05/graded/chain2-rx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
== hidden
64/64 passed
== overlap
29/29 passed
4 changes: 4 additions & 0 deletions eval/results/rc21-regrade-2026-11-05/graded/chain3-rx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
== hidden
70/70 passed
== overlap
32/32 passed
6 changes: 6 additions & 0 deletions eval/results/rc21-regrade-2026-11-05/graded/chain4-react.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
== hidden
77/77 passed
== overlap
38/38 passed
== fuzz
chain4-react: 0/20 seeds found a hole
10 changes: 10 additions & 0 deletions eval/results/rc21-regrade-2026-11-05/graded/chain4-rx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
== hidden
77/77 passed
== overlap
38/38 passed
== fuzz
chain4-rx: 2/20 seeds found a hole
seed 11 step 33: row title: #4 shows "Typo in footer", server "Delta"
tab help ; tab issues ; tab help ; land fetchIssues:open ; tab issues ; focus ; tab help ; tab issues ; land fetchIssues:open ; row-assign 1 ; land assign:3,guest ; filter closed ; user ann ; row-assign 0 ; focus ; land fetchIssues:open ; land assign:1,ann ; select #4 ; close ; land fetchIssues:closed ; close ; land fetchComments:4 ; fail fetchLabels:4 ; row-assign 0 ; close ; land fetchIssue:
seed 15 step 24: detail title: "#2 Old buglong gonesaving filescrash reportsretryassign to g", server "Bravo"
land fetchIssues:open ; row-assign 0 ; focus ; land assign:1,guest ; fail fetchIssues:open ; tab help ; tab issues ; land fetchIssues:open ; focus ; filter closed ; land fetchIssues:closed ; select #2 ; land fetchComments:2 ; rename Bravo ; select #2 ; assign ; land fetchIssue:2 ; row-assign 0 ; select #2 ; land fetchLabels:2 ; assign ; remove-label 0 ; land search:Old bug ; land renameIssue:2
4 changes: 4 additions & 0 deletions eval/results/rc21-regrade-2026-11-05/graded/count-rx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
== hidden
56/56 passed
== overlap
24/24 passed
Loading