Landing picks an environment; each environment is a tabbed page opening on Play
The environment page was a linear scroll of eight narrative beats. That is an essay, and it is the wrong shape for somebody who has just chosen an environment and wants to use it. It is now four tabs — Play, Watch, Reward, Evidence — opening on Play, with the board above the fold at 390x844 and the anatomy strip directly beneath it. The landing page leads with the picker instead of burying it under the thesis. The contract changed rather than layering tabs over beats. `Narrative.beats` is gone; `claims: Record<DemoTabId, string>` replaces it, one required sentence per tab. Writing the claim is how an author discovers whether a tab has anything to say — a tab whose claim is hard to write is usually a tab with nothing in it. Doing this now costs one migration; doing it after eleven more environments costs twelve. Tabs are derived, never declared: Play iff the demo ships an `interactive` mode, Watch iff it has recorded runs. A demo that could name its own tabs would mean environment seven inventing a fifth one and the site ceasing to be one product. One thing the browser caught that no gate would have. The header stat strip describes the RECORDED RUN, and on Play it sat above the visitor's own empty board reading "Outcome: failed" — which parses as your game having already failed before you touch a key. It now renders only on the tabs whose subject is that run, which also moved the board 54px up the page. The picker is honest about the shape of the lineup by construction: one built environment gets its own block and the demo's real board as its thumbnail, twelve written specifications render dimmed with a Spec badge, and every count on the page is derived from the data rather than typed. 206 contract checks pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019mt6sHQHEnEYrJZvoMCJSB
This commit is contained in:
@@ -15,6 +15,10 @@
|
||||
* · Every step sets a non-empty `announce`. Reduced motion clamps the
|
||||
* animation to nothing, so for a screen-reader user the announcement IS
|
||||
* the result, not a courtesy (rule 13).
|
||||
* · `meta.ts` never imports this file. The demo page is four tabs and Play
|
||||
* is the one a demo is allowed not to have, so the eager half — meta,
|
||||
* narrative, reward — has to render with the interactive half absent
|
||||
* (rule 14).
|
||||
*/
|
||||
|
||||
import { defineDemo, type DemoEpisode, type DemoStep, type RewardValues } from '@/lib/demo-kit';
|
||||
@@ -128,14 +132,53 @@ export default defineDemo<__Pascal__State>({
|
||||
'The queue is not the problem. Deciding which three of four hundred items are worth a person is the ' +
|
||||
'problem, and that decision is exactly the kind of judgement a reward can be written down for.',
|
||||
anxiety: 'What stops it escalating everything so it never misses one?',
|
||||
beats: [
|
||||
{ id: 'hero', title: 'One queue, one decision', claim: 'Every item is either worth a person or it is not.', surface: 'hero' },
|
||||
{ id: 'anatomy', title: 'What the environment is', claim: 'A task, a fixed action set, a grader, and a score that moves.', surface: 'anatomy' },
|
||||
{ id: 'play', title: 'Watch a recorded run', claim: 'These are recorded turns, not a scripted animation.', surface: 'split-play' },
|
||||
{ id: 'reward', title: 'Move the weights yourself', claim: 'Pay only for catches and the queue gets escalated whole.', surface: 'reward-editor' },
|
||||
{ id: 'receipt', title: 'The code that scored it', claim: 'The number on this page came out of the function below it.', surface: 'receipt' },
|
||||
{ id: 'limits', title: 'What this does not show', claim: 'One queue, one grader, and no cost of being wrong.', surface: 'limits' },
|
||||
],
|
||||
|
||||
/**
|
||||
* ── THE FOUR CLAIMS ──────────────────────────────────────────────────
|
||||
*
|
||||
* The demo page is four tabs — Play, Watch, Reward, Evidence — and this is
|
||||
* the one sentence each of them has to earn. You do not choose the tabs or
|
||||
* their order; the shell does, and it drops Play when there is no
|
||||
* `interactive` and Watch when there are no recorded runs. You only write
|
||||
* what each one asserts.
|
||||
*
|
||||
* Write all four even if this demo will not render all four. A tab whose
|
||||
* claim you cannot write is a tab with nothing in it, and finding that out
|
||||
* here is cheaper than finding it out in review.
|
||||
*
|
||||
* A good claim is:
|
||||
*
|
||||
* · a SENTENCE, not a label. "The reward" is a heading. "Move one weight
|
||||
* and the ranking of the runs re-orders under it" is a claim.
|
||||
* · falsifiable BY THE TAB IT SITS ON. The reader should be able to look
|
||||
* at the surface below it and agree or disagree within a few seconds.
|
||||
* · about this environment, not about reinforcement learning. The thesis
|
||||
* above is where the general argument goes.
|
||||
* · addressed to the person in `meta.persona`, in their words.
|
||||
*
|
||||
* The four below are real claims for this worked example. Replace them —
|
||||
* do not delete the shape.
|
||||
*/
|
||||
claims: {
|
||||
// Play: what the visitor learns by doing the task themselves, and why
|
||||
// doing it first makes the other three tabs mean something.
|
||||
play:
|
||||
'Work the queue yourself for thirty seconds and you will feel the trade the agent is being scored on: ' +
|
||||
'every item you escalate has to be worth someone opening it.',
|
||||
// Watch: what the recorded run proves that a claim about the run cannot.
|
||||
watch:
|
||||
'This is a real recorded run, replayed one turn at a time — the reasoning, the model call and the cost ' +
|
||||
'of each decision are exactly what came off the wire.',
|
||||
// Reward: what changes on screen when the reader changes what "good"
|
||||
// means. Name the thing that moves.
|
||||
reward:
|
||||
'Take the weight off restraint and the run that escalated everything climbs to the top of the ranking. ' +
|
||||
'That is not a bug in the score; it is the score doing what you asked.',
|
||||
// Evidence: what the reader can go and check, and what this does not show.
|
||||
evidence:
|
||||
'The grader is a short Python function, printed here with the command that ran it, so you can disagree ' +
|
||||
'with the number by reading the code rather than by trusting us.',
|
||||
},
|
||||
limits: [
|
||||
{
|
||||
text: 'The grader knows which items needed a person because the dataset says so. A real queue has no such column, and building one is most of the work.',
|
||||
@@ -213,6 +256,29 @@ export default defineDemo<__Pascal__State>({
|
||||
|
||||
adapt,
|
||||
Surface: Board,
|
||||
|
||||
/**
|
||||
* ── ADDING PLAY ──────────────────────────────────────────────────────────
|
||||
*
|
||||
* There is deliberately no `interactive` here, because a scaffolded demo
|
||||
* starts as `spec`. Add one and the shell grows a Play tab and OPENS ON IT —
|
||||
* that is the whole shape of the page, so it is worth doing:
|
||||
*
|
||||
* interactive: {
|
||||
* init: (seed: number) => empty__Pascal__(seed), // pure in the seed
|
||||
* Controls: __Pascal__Controls, // its own module
|
||||
* },
|
||||
*
|
||||
* `init` must be deterministic in the seed: the shell re-inits on reset and
|
||||
* on a shared link, and a board that comes back different has quietly told
|
||||
* the visitor the environment is not reproducible.
|
||||
*
|
||||
* `Controls` gets `{ state, onChange, seed }` and nothing else. It owns no
|
||||
* state the board does not — hand the next board to `onChange` and let the
|
||||
* shell re-render, or Play and the replay will drift apart. Put it in its own
|
||||
* file and import it here, never from `meta.ts` (rule 14).
|
||||
*/
|
||||
|
||||
verify: recompute,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,75 +1,30 @@
|
||||
import type { Narrative } from '@/lib/demo-kit';
|
||||
|
||||
/**
|
||||
* The six beats, in order. The shell renders them; this file decides what the
|
||||
* page argues and in what sequence.
|
||||
* What this environment argues, tab by tab.
|
||||
*
|
||||
* The page is a set of tabs rather than an essay because an executive who has
|
||||
* chosen an environment wants to be doing the task, not reading a case for it.
|
||||
* Each claim is the one sentence that tab has to earn.
|
||||
*/
|
||||
export const narrative: Narrative = {
|
||||
thesis:
|
||||
'This is the smallest complete reinforcement-learning environment we could find that needs no ' +
|
||||
'domain knowledge at all. It has everything the ones that matter to your business have: a task, ' +
|
||||
'a fixed set of legal moves, a grader that cannot be argued with, and a score that moves when ' +
|
||||
'the model gets better. Learn the machine here, and every demo after this is the same machine ' +
|
||||
'with a different grader.',
|
||||
'the model gets better. Learn the machine here, and every environment after this is the same ' +
|
||||
'machine with a different grader.',
|
||||
anxiety: 'How would we know it was actually working?',
|
||||
beats: [
|
||||
{
|
||||
id: 'hero',
|
||||
title: 'Their hello-world, not ours',
|
||||
claim:
|
||||
'Prime Intellect ship this exact game as a starter environment in three of their public repositories. We did not pick a game. We picked theirs.',
|
||||
surface: 'hero',
|
||||
},
|
||||
{
|
||||
id: 'anatomy',
|
||||
title: 'What an environment actually is',
|
||||
claim:
|
||||
'Four parts: a task, the moves that are legal, a grader that computes rather than opines, and a number that moves.',
|
||||
surface: 'anatomy',
|
||||
},
|
||||
{
|
||||
id: 'play',
|
||||
title: 'You and the model get the same word',
|
||||
claim:
|
||||
'Same hidden word, same six guesses, same rules. Play it, then watch what the model did with it.',
|
||||
surface: 'split-play',
|
||||
},
|
||||
{
|
||||
id: 'watch',
|
||||
title: 'Watch it think',
|
||||
claim:
|
||||
'This is not a video. It is a recorded attempt replayed at the speed it actually happened, and you can step through it one guess at a time.',
|
||||
surface: 'scrubber',
|
||||
},
|
||||
{
|
||||
id: 'reward',
|
||||
title: 'You decide what good means',
|
||||
claim:
|
||||
'Move one slider and the winner changes. That is not a trick — it is the product.',
|
||||
surface: 'reward-editor',
|
||||
},
|
||||
{
|
||||
id: 'metric',
|
||||
title: 'The number that moves',
|
||||
claim:
|
||||
'Out of the box, this model solved none of eight. Letting it think first is the cheapest intervention there is, and you can measure exactly what it bought.',
|
||||
surface: 'metric',
|
||||
},
|
||||
{
|
||||
id: 'receipt',
|
||||
title: 'The whole environment, in one screen',
|
||||
claim:
|
||||
'The grader is thirty lines of Python. Here it is, and here is the command that runs it.',
|
||||
surface: 'receipt',
|
||||
},
|
||||
{
|
||||
id: 'limits',
|
||||
title: 'What this does not teach',
|
||||
claim:
|
||||
'A word game is missing four things your business has. Each one is why the next demo exists.',
|
||||
surface: 'limits',
|
||||
},
|
||||
],
|
||||
claims: {
|
||||
play:
|
||||
'Play it yourself first. Everything else on this page is about what happened when a model tried the same thing.',
|
||||
watch:
|
||||
'This is not a video. It is a recorded attempt replayed at the speed it actually happened, and you can step through it one guess at a time.',
|
||||
reward:
|
||||
'Move one slider and the winner changes. That is not a trick — it is the product.',
|
||||
evidence:
|
||||
'The grader is thirty lines of Python. Here it is, here is the command that runs it, and here is what this environment does not teach you.',
|
||||
},
|
||||
limits: [
|
||||
{
|
||||
text:
|
||||
|
||||
Reference in New Issue
Block a user