News
News
-
From Jev to Darkwaar: Building a Game About Decisions and Uncertainty on September 27, 2026
Jev is TypeSafe's first System One model. You send a state and a set of typed questions. It sends back typed answers, with probabilities where the question has more than one slot. There is no paragraph to parse.
A generative language model does the other job. It continues text. You then decide whether that text was a department name, a score, or a refusal. Jev's contract is the decision itself: the allowed answers are the ones you listed, and the response is one of those answers plus a distribution.
This week I did not wire Jev into Darkwood Flow. I used the study of that API to build a small game about the moment before a commit: do I know enough?
Three question types
The HTTP call is
POST https://api.typesafe.ai/v1/systemone. The body is a model name (jev-latestis the alias I used in the study), astate, and a map ofquestions. Official docs, retrieved for the study on 21 September 2026, describe three question types.Choice. Which of these options? The answer carries
choice,probabilities, andconfidence. The probabilities are a distribution over the criteria you supplied.Score. Where on this ordered rubric? The answer carries
score, alegendthat repeats the rubric,probabilities, andconfidence. The score is a position on the scale, so it can sit between two labels.Noul. Is this statement true? The answer carries
noul, a float from 0 to 1. That field is the model's degree of support for the statement. It is not a boolean, and the documented noul answer does not carry a separate confidence field. Choice and score do.One request evaluates every question against the same state. The docs describe those questions as independent: a later question that needs an earlier answer is a second request. I did not measure that latency here. The study's unauthenticated probe of the live API, with no key, returned HTTP 403 and
authentication_error.TYPESAFE_API_KEYwas empty, so this article does not report live confidence numbers, agreement rates, or timings.Probabilities are not a guarantee
Confidence, on choice and score, is a number you can branch on. The useful shape in application code is ordinary:
if confidence is high and the choice is billing → route if confidence is low, or noul sits near 0.5 → escalateThat branch is a policy. It is not a proof. A high confidence can still be the wrong department, because the number describes how peaked the distribution is, not whether the world matches it. A noul of 0.99 is strong support for the statement. It is still a float you chose to treat as yes.
The study kept those fields intact on the way through Symfony AI's
ObjectResult. It did not collapse them to a boolean inside the model client. Low confidence is a successful response. It is not an exception.The same study has a local Platform bridge under
/Users/math/Sites/tests/ai, package shapesymfony/ai-jev-platform, capabilityINPUT_TEXTonly. That bridge is local research. It was not submitted, merged, or released as part of this week's work. Symfony AI still has no core capability named decision, choice, or noul.OUTPUT_STRUCTUREDmeans Symfony's JSON-schema path for a generative model. Jev's structure is the questions in the request. Those are different mechanisms, and the bridge does not pretend otherwise.From a distribution to a puzzle rule
Darkwaar15 — Signal does not call Jev. There is no API key, no network request, and no sampled answer. The three names are the three operations the player commits:
- NOUL asks whether the lit marks are even.
- CHOICE asks which listed pattern matches the marks. A lit mark is
1, a dark mark is0. - SCORE asks which band holds the sum of the bars: low is 0–1, mid is 2–3, high is 4 and above.
Some wells start closed. A square counts for the current operation. A diamond is noise and never changes the answer. Opening a well reveals a value that was fixed when the level was written.
Confidence in the game is a collapse of the remaining answers, not a calibrated probability:
confidence = 1 when one answer is still possible confidence = 1 - (possible - 1) / (universe - 1) otherwiseThe universe is 2 for a noul, the number of patterns for a choice, and 3 for a score. The gate on every level is 0.70. One remaining answer is confidence 1, which clears the gate. Two remaining answers out of three is 0.50, which does not. The player can press commit anyway. Below the gate the console answers "Not enough signal" and does not reveal the reading. On or above the gate, a wrong output shows the reading and counts a miss. Three misses reset the level.
That is the translation. Jev's confidence can refuse to act. The puzzle makes the refusal the rule, and makes the hidden wells the reason the answer is not unique yet. Level 7 is the clearest case: two bars are enough for the sum to sit in high even if a third bar is still closed, because that bar's ghost height cannot leave the band. Opening the diamond does nothing. The interesting commit is the one you make before every well is open.
The solutions are data, checked by a headless Godot script that replays the scripted probes for all eight levels and then drives the real scene through a wrong commit, a low-confidence reject, a miss that shows the reading, a restart, and a clear. Both checks printed pass before the HTML5 export.
The console
The game lives in the Darkwaar monorepo as
2026-09-27-01M3H4X9806QZ6Z7D85F, legacy iddarkwaar15. Godot 4.6, portrait viewport 648×1152, oneControlscene. Three scripts do the work:rules.gdholds the eight levels and the confidence rule. It does not draw.signal_view.gddraws the wells, the connectors, and the confidence meter. The tick on the meter is the gate.main.gdis the commit loop: probe, select, commit, miss, restart, and the last screen.
Input and evaluation and output are stacked on the portrait canvas. Closed wells keep their shape, so a diamond is visible before you waste a probe on it. The meter is cyan under the gate and amber once the answer is unique. Mouse and touch both hit the wells and the buttons.



The web export is the same scene.
bin/build-game darkwaar15 --validate --zippackedmain.gdc,rules.gdc, andsignal_view.gdc.bin/smoke-web-build darkwaar15loaded the canvas at 648×1152, found a non-blank frame, and reported no fatal page errors. A click on commit in the browser build answered "Choose an output" when nothing was selected, so the HTML5 loop is taking input.Publication
The Darkwaar post is committed in darkwaar-com at
assets/docs/blog/2026-09-27-darkwaar15(f4abc7donmain) and pushed to GitHub. I requestedhttps://darkwaar.com/blog/2026-09-27-darkwaar15and got HTTP 500, which is also what that site returns for a slug it does not have. This clone has noupsungit remote. The Upsun CLI answersAuthentication is requiredtoplatform auth:info, somake upsun-pushcannot run from here. I am not citing that page as published.This essay is up at blog.darkwood.com and darkwood.com/news. Both answered HTTP 200.
The itch.io upload did not land. Butler's push to
darkwoodcom/darkwaar15:htmlreturneditch.io API error (400): /wharf/builds: invalid game. A request tohttps://darkwoodcom.itch.io/darkwaar15answers 404. itch.io creates a project page in the dashboard, not through the server API or Butler. This environment can list the existing Darkwaar games with the API key, and it cannot create the fifteenth page. The HTML5 zip is built and waiting for that page.Flow stays a pipeline
The original study asked whether Jev belonged inside Flow. The answer from the code, unchanged this week, is that Flow already has the place a decision sits. A job is
JobInterface: one input, one return value. The packet is anIp. Replacing a rule job with a Jev job changes what the packet carries. It does not change the driver, the IP strategy, or the stage graph.I did not add
Decision<T>,Choice<T>, or aJevDrivertodarkwood/flow. I did not run a Flow integration test, and I did not publish one. A low-confidence answer would still be a normal job result. Escalation would still be the next job's PHP. That work is postponed. This week's artifact is the research, the local Platform bridge left unsubmitted, and Darkwaar15.What the experiment is for
A decision procedure is a state, a closed set of answers, and a rule for when you are allowed to act. Jev is a remote version of the first two, with a distribution attached. Darkwaar15 keeps the closed set and replaces the distribution with a fact the player can see: how many answers the closed wells can still reach. The gate is the third part, and it is the part the application owns.
The console will refuse a correct button pressed too early. That is the property I wanted to feel. Enough information is a state of the puzzle, in the same way enough confidence is a state of the program, and neither number is a promise that the commit was right.