Commit Graph
50 Commits
Author SHA1 Message Date
Bendik Aagaard LynghaugandClaude Fable 5.1 f516e26926 build: a mail is at most three short sentences and the link line
The mail prompt said "short"; it now says how short. The football
club's enrolment mails halved in length and read easier, and the
vel's evened out, with every link kept.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 09:00:15 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 6f2f7e271c runs: the football club with a sender, stage words and mails
The second Norwegian case: level with its earlier build on routing
inside the spread, desks 13 of 14 with outcomes in words, Norwegian
mails from Sonnet in one pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 08:28:26 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 1df710f32f runs: the friendliness judge passes a positive control
Live vel front door against a cold, bureaucratic twin: friendlier 9
of 10 to the live page, none to the twin, both orders. So the earlier
no-preference between the live doors and the rejected rewrite was a
verdict, not blindness; and judged clarity and measured routing are
different things.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 07:50:52 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 fd785288a4 runs: the rejected vel doors read clearer and route worse
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 07:15:58 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 4d22f4cb44 plan: a spectator role goes back to the model once; bare-word movers and unlabelled groups parse
Re-planning the contractor showed three wasted rounds: `moves_by: {
checking: submitter }` written as a bare word, a group without a
label, and the two featured owner roles left with nothing to play,
which the builder only warned about after the fact. The bare word and
the missing label now parse (a label defaults to the id), and a plan
that parses with spectator roles is sent back once with the finding;
on the contractor, round three fixed both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 06:42:05 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 6e49694211 build: turned_down_from, and uhhm's stages in words
A need may say which unfinished stages a case can still be turned
down from; the machine no longer offers the bad end from every stage.
uhhm's collaborators are declined before they start and depart after,
as the live site has it. The uhhm plan gets stages_text and three
desk buttons reworded: every uhhm desk scores full marks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 06:01:56 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 aeff4c8cbe CI: lint with iris v0.3.47
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 05:23:48 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 be14e33603 build: stages in the plan's own words
`stages_text` on a need gives each stage plain words in the plan's
language. The fallback mails, the road line and the desk buttons use
them, and needs.yaml carries them as `stage_words` so the desk score
describes an outcome the way the site would. The vel's plan has them;
its desks score 26 of 26 where the id-based outcome scored 24.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 05:17:18 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 8e6a93ebb7 rate: a desk row offers only the buttons that start from its state
The first desk score offered every button of the bucket, where portal
shows a row only the moves from its own state; that scored the live
vel 17 of 26 and sent a rewrite of the neighbour-help desk chasing an
instrument fault. With the row's buttons only: 24 of 26, and the
rewrite loses on the fair test too. Noted: an accent-stripped state id
(ikke_lost) reads as English even to a strong picker.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 04:39:13 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 9089503524 rate: the desks are scored on their buttons
The inside of the business reads button labels and nothing else. For
every desk and bucket with two or more buttons, a worker is told what
just happened to a case, in the state's own words, and picks the
button; scored right of total with what each miss was taken for. The
vel's neighbour-help desk scores 2 of 4 and the notice board 1 of 2:
the first numbers a desk has ever had.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 03:44:52 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 5e313b7d40 runs: the planned contractor rated
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 03:05:00 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 2622fdac88 plan: a budget that equals the form is reported as counted, not decided
Four of the planned contractor's five needs had max_fields equal to
their required fields: the model counted the form and called it the
person's tolerance. `plan` now says so when most needs do, and the
reference tells the model to decide the number before writing the
form.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 03:04:22 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 d132f1e4df runs: the contractor planned end to end, 7 of 8 across seeds
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 02:32:30 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 209e9d1258 plan: held-out personas are mapped to the plan's needs by a model, ids only
The one manual step left after `plan` was mapping the attached
personas' `need:` to whatever ids the model chose. A second call now
does it: the model sees the plan's needs and the persona texts and
returns ids only, after the plan is final, so no persona wording can
reach a page. An id the plan lacks is ignored and the reader is told.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 02:27:38 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 b1f0210691 build: personas naming undeclared needs is the reader's mapping, not a builder bug
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 01:55:39 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 20e5e16641 plan: the model that writes a plan learns this week's keys
`does`, `shows`, `mail`, `mails`, `invites_by`, `events`,
`attended_by`, and the measured guidance on doors: the plan reference
the model reads lagged the builder by a week, so a planned site had no
opener, no mails and no onboarding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 01:54:02 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 42059da48f CI: the tests, and every plan built and linted
The trainer had no CI. Every push now runs the tests and builds every
plan under plans/ against the iris release the live sites run, and
lints the onboarding site.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 01:16:35 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 07da3b40f7 Docs: the skill file says what the trainer does now
iris instead of question_lint everywhere; the skill's procedure is
plan, build, score: the opener and the look-around, mails and the
sender, moves for the person, doors only when measured, the lift
through a rebuild, the language and link guards, the descriptions
score over the headings score, and the spread a change has to beat.
README documents --llm-for.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 00:45:16 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 deee27d280 runs: the vel doors reworded by a model, worse across three seeds, rejected
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 00:12:57 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 8c7fb870bf build: a reply in the wrong language keeps the words it had; the vel's mails
A model asked for Norwegian sometimes answers in English. The commonest
function words of each language are counted across a reply, and one
that reads as the other language is refused with a line saying so.
Tomter Vel's six mails, worded by Sonnet in Norwegian, are round 2 of
runs/tomtervel-opener-2026-09-23 and live.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 23:35:32 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 72a081ed59 build: a model may not lose the submitter's link; uhhm round 7, the mails
Sonnet wrote the ten uhhm mails and replaced the decide link with a
bare {chain}. keep_links puts the fallback's link line back into any
mail that lost it. The mails read easier than the fallbacks (LIX 9 to
33 against 18 to 28) and say something.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 23:02:48 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 b5f5c46ff2 build --llm-for <prefix>, and rate reads the mails
The words model can be pointed at a subset of pages (`aggregates.yaml`
for the mails alone) while everything else keeps the words it has.
`rate --repo` rates each mail's prose on its own, LIX and length,
since a person reads a mail with no card around it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 23:00:37 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 1191551f28 README: the noise floor, measured over four seeds
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:59:10 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 c240d3a646 spread.sh: the engine path is absolute
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:46:44 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 cc50249d7f answer --seed, and runs/spread.sh: a score comes with its spread
Every score so far was one run of a small visitor. `answer --seed n`
answers the same tasks with other shuffles and sampling, and
runs/spread.sh prints a run's score per seed, so a change can be told
from the visitor's mood.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:46:25 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 ec2f07da77 runs: Tomter Vel keeps its doors and gains the opener; merged
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:43:55 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 09aea7061c The visitor and the rater read what the page says first
iris now hands a task the cards that lead nowhere as `page` context;
the answerer shows it before the options and the rater before the
cards, and the gutted twin loses it like everything else. The Tomter
Vel plan keeps its four doors and gains the opener, the mails and the
member's own move: flat scored worse and the doors stay.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:36:13 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 e3dae063d4 English in the code: fixtures, identifiers, and one phrase table
The fallback mail phrases move into a `Phrases` table, the one place a
language other than English appears in this code; the `navn` special
case goes (a form names the person's field `name`). Test fixtures
speak English: traffic, board, hazards, report, fixed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:09:04 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 713f8ff3a0 build: words follow a card across pages when a site is restructured
`--words-from` matched page by page, so flattening Tomter Vel lost
every heading its door pages carried. Now a second pass pools every
alternative in the repo and hands a rendered card the pooled card
with the same strong identity (bucket, own page, invite group; never
a bare action like `/`). Two things stood in the way and are fixed:
needs.yaml is no longer a source of words (its `via` named the door),
and a live feature's `name` no longer blocks a positional match, so
placeholders and guidance lines come along too. Rebuilding the vel
flat from the live repo now lifts all ten headings and every hint.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:01:55 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 a8e9d38a6a runs: uhhm round 6, the mails
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 21:19:38 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 8341089898 build: a plan says who hears when a case moves, and the words write the mail
`mails: { <stage>: submitter | <address> }` on a need becomes `mail:`
on that state in aggregates.yaml (portal 0.3.43+), and `mail: { from,
reply_to }` on the plan becomes site.yaml's sender. The words map
gains `aggregates.yaml`, one subject and body per mailing stage, so
the model writes them like any other page; the fallback, in the
plan's language, says what happened and where the submitter's own
move is. A submitter mail needs a required email on the form; any
mail needs a sender. The uhhm and Tomter Vel plans tell the submitter
at every stage that matters to them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 21:18:14 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 f5f5132056 build: the lift matches cards by identity, not position
Sequences were walked side by side, so a rebuilt page whose cards sit
in a different order, or with a new card in front, gave every card
its neighbour's words: uhhm.no's front door got "Attention is earned"
on the wrong card that way. Items now match on the bucket they record
into, the page they lead to, a field's name, the group they invite
into or the bucket they read; information features with no identity
still match by position. Lifting live uhhm.no into the current plan
puts each of its three headings on the card with its bucket.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 20:48:47 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 bf60879de9 score: the whole grading of a built site as one command
iris writes the tasks and the model, the blind visitor answers with
descriptions and with headings only, iris scores, rate reads the
cards; the routing numbers land in summary.json. Replaces the
score.sh every run carried. Proven on runs/uhhm-2026-09-23/site.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 20:25:55 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 9ff9924374 build: --words repeats and layers; the desk's confirm slot says what it is
Two things the uhhm rounds ran into. Only the first --words was read,
so a round of hand changes had to be merged into the previous words
by hand; now each file layers over the last. And the desk's one
confirm slot was described like any button, so a model wrote "Send
invite" under the cases list; it now says it serves every list.
README: the lift is positional, and where that bit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 20:02:30 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 9e7f16c489 build: the front door opens modestly, and a featured role must have a move
`does:` on a plan, at most two features, each `for:` a need: the first
card of the front door says what the business does, one role each,
headed by what that role gets, and asks for nothing. `shows:` is the
second card, portal resource blocks passed through verbatim plus every
public view. Only then the offers, as more alternatives on the same
page; the front-door warning moves to seven and stops recommending
doors. `Plan::spectators()` warns when a featured need gives the
submitter neither a move nor a view. uhhm.no rounds 4 and 5 (flat,
at least as good per persona) and Tomter Vel flat (worse: ten offers
on one page, the close pairs collide) are in runs/.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-23 18:24:23 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 9e511b5b57 runs: uhhm.no from a plan, three rounds of wording
Sonnet writes, qwen3:8b routes: 16 then 19 of 27 with descriptions,
19 then 21 of 27 on headings alone. One card took seven personas
until it named redoal; what remains is on the front door and mostly
a judgment the plan could make differently, not the words.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 15:09:35 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 04a6eeea85 build: a plan keeps a live site's event names, and names its automations
`events:` on a need overrides the event a stage is entered by. Portal
replays records by event name, so rebuilding a site that already holds
records has to keep what its aggregates.yaml says, or the desks empty.
`attended_by:` writes portal's annotation for a bucket an automation
moves. plans/uhhm.yaml: uhhm.no from a plan - the five live buckets
with their names, plus trials (the trainer tried on a client's
business, approved by hand) and custody_requests (UHHM as redoal's
custodian, a desk of its own).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 14:49:25 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 93a6fc0e10 build: invites from the plan, and rebuilding a live site without losing its words
`invites_by` on a plan (and `invited_by` on a group) put an invite form
per fillable group on the inviting group's desk, plus a list of the
invites sent - portal's `invite:` does the onboarding. Every desk
group invites into itself by default; an inviter without a desk is
refused.

`--words-from <repo>` lifts the words an existing repo carries back
into the words map by structure: the plan is rendered with a token in
every slot and walked alongside the repo's files. Hand edits and
model-chosen icons survive a rebuild; only new slots get fallbacks,
which `--words <json>` can override. The words as used are written to
words.json. First use: Tomter Vel, additions only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-23 12:42:23 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 255aeb4f4b plan: intake to plan by a model; doors, labelled groups, the whole card
Work from another session, committed as found (tests green):

- `plan` reads an intake into a plan.yaml (a model decides needs,
  stages, forms and budgets; a person reads the result before build).
- Plans gain `doors` (a first question before the forms, when a front
  door would carry more than five needs), `groups` with labels that a
  select may draw its options from (`options_from: groups`), `private`
  fields kept off public pages, `multiple` selects, and `max_fields`
  as what the intake said the person will tolerate.
- `card.rs`: an alternative as the visitor meets it, in text, so the
  answering visitor and `rate` read the served card, not the heading.
- `rate` reads followup pages from the repo and reports "what happens
  next" as not measured rather than zero when it cannot.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-23 12:31:51 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 baf36319b7 Overlapping roles on one aggregate, relay routes, and a dry run
plan.yaml: `moves_by` says who presses the button into a stage when it
is not `handled_by` - other groups, several groups, or `submitter`,
the person who sent the form, through their own link (the form must
then collect a required email). `watched_by` puts a bucket on a
group's desk with no buttons. Each group's desk carries its own buttons
only; a submitter's moves become a followup page of self_transitions;
needs.yaml gains `also_moved_by` for portal's verifier.

simulate: a route is now a relay across every role that holds a legal
button, the submitter included, and each step is judged as the role
that presses it. `--dry` asks no model anything and walks every simple
route of every aggregate, for needs_replay to put through the real
engine.

plans/contractor-full.yaml: 13 needs, 6 roles, 10 aggregates. Verifier
green by construction; 40 routes, 78 transitions accepted by the real
engine, none refused. What it exposed is in its run README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 21:46:12 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 aef0fe1396 build: slots instead of placeholders, and the first worded run
Fallback words read like finished copy, and nemotron handed the front
door straight back. The prompt now shows every string as a slot saying
what belongs there; a slot echoed back counts as no answer and keeps
the fallback.

runs/contractor-build-2026-09-21: nemotron-3.5-lightning:30b-a3b, the
model that produced no loadable site free-form, words a complete
contractor site in 130 s. Verifier green by construction; held-out
personas route 8/8 with descriptions and 8/8 on headings alone
(qwen3:8b as the visitor). "What happens next" is still 0/2 on the
front door: no heading or description says who reads a submission.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 21:08:08 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 8c286a8483 build: structure from the plan, words from the model
A plan.yaml is a needs spec that also says what each form collects
(and which stages a case may pass over). `portal-trainer build`
derives everything structural from it with no model involved:
needs.yaml, aggregates.yaml with the state machine read off `stages`
(walk the line, be turned down anywhere, succeed only from the end),
the front door, a followup page per need, a gated directory per group
holding its desk and the pages only that group may open, and every
desk button the machine allows.

The model is asked for words only, one page at a time, as a JSON object
whose shape is fixed by built-in fallbacks. Its strings are merged over
the fallbacks key by key, so a missing, malformed or partial reply
costs wording, never a working site, and it can neither add nor drop
structure. `via` in needs.yaml is filled mechanically from the heading
the words gave.

plans/contractor.yaml builds with no model into a site portal's
question_lint accepts: 6 needs met, 12 pages, 5 aggregates.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 21:01:35 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 e016698dc0 generate: drop a needless mut
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 20:22:05 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 b53e7e6aca generate: a Norwegian run on a local model, and what it took to read it
Every prompt and reply is now kept under <out>/llm/. An empty reply is
a retry, not a fatal error; a spec that never parses stops the run
before the structure phase; --visitor-llm lets a different model play
the visitor. The file-block parser finds markers anywhere in a line,
accepts a short END and lets a new FILE close an open one, after a
reply glued two files together with `<<<END>></think>`. The reference
gains a language section: copy in the intake's language, identifiers
in ASCII.

runs/rehab-entreprenor-no-2026-09-21: nemotron-3.5-lightning:30b-a3b
did not produce a loadable site. Written up with the reason and the
way forward: structure from needs.yaml deterministically, words from
the model.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 20:21:46 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 b9f2acb7b8 rate and prefer: understanding, readability, friendliness, page load
Readability is counted (LIX), not judged. Understanding is three
yes-or-no questions per persona, with a gutted twin of every page as
the control: an instrument that still says yes to "Option 1, Option 2"
is not measuring the page. Friendliness is a preference between two
versions shown in both orders; a pick that flips with the order counts
as no preference. Page load (options offered, required fields in the
step) flags a page that should be split into a further question or
have fields moved to a later stage.

First run on the generated contractor site, qwen3:8b as the visitor:
control passed on every need; "what happens next" was 0/2 everywhere
and 2/2 everywhere once the page said who reads it and when (LIX 28 to
30); an official-voice control reads LIX 63 against 27. Friendliness
mostly came back "no preference" at two personas per need: directionally
right (never preferred the cold version), too thin to rely on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 19:48:25 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 612745bc66 runs: simulating the generated contractor site, with what held up and what did not
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 19:35:47 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 02672547ee simulate: play every case through every state, judge only what a model can
`portal-trainer simulate` reads the model `question_lint --needs-sim`
exports. A visitor model picks an alternative and fills the form in a
manner that varies by run; the case is then walked along the handling
group's own desk buttons to a finished state, a different one each
run, so every state and button is exercised. At each button the
handler model is asked one thing: with only what the form collected,
could this role really do what the button claims? Its question goes
back to the visitor, who may not know.

Who wins is deliberately not simulated. The first version let the
handler decide: qwen3:8b sent every case to "won", and after one
sentence of prompt change, every case to "lost". Outcomes belong to
the live bucket; `success` in needs.yaml is what a report over real
records counts.

`compare` sets two score files side by side. engines/ollama.sh honours
SEED, FORMAT=json and TEMPERATURE so the same case replays the same
way against two versions of a site. generator/reference.md documents
`success` and `stages`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 19:16:28 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 e163c22792 First generated site, a held-out test, and the leak it exposed
runs/contractor-2026-09-21: the generator's first end-to-end run, on
intakes/contractor.yaml. Needs parsed first round, structure green
first round, 10/10 on its own personas - and 8/10 headings-only on
ten held-out personas with qwen3:8b as the visitor, because the pages
had been written with the personas in view. Phase 2 now shows the
model the needs without the personas.

`portal-trainer answer` exposes the blind answerer on its own. README
rewritten around what this is: an intake in, a verified content repo
out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 18:18:08 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 b6bdac6f62 Generator, LLM backends, and the onboarding site
`portal-trainer generate` turns a plain-words business intake into a
content repo in three phases, each held to portal's question_lint:
needs.yaml (then frozen, so the generator cannot weaken the spec to
pass), structure (revised against the lint's findings until green),
and wording (personas answered blind, misroutes fed back; a rewrite
that breaks structure is reverted). Model output is written to disk
only under aggregates.yaml, site.yaml and questions/**.yaml.
`portal-trainer answer` is the blind answerer alone.

The LLM is an external command, prompt on stdin, text on stdout:
engines/ollama.sh (local Ollama), engines/anthropic.sh (API key),
engines/mailbox.sh (hand each prompt to an agent or a person).

portal-portal/ is the onboarding site as a portal content repo: the
front door is the intake interview, records land in `onboardings`
(open -> drafted <-> revising -> live | declined), and it passes its
own needs spec.

runs/uhhm-2026-09-21/ollama: qwen3:8b and granite4.1:8b as blind
answerers on the same eight tasks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 18:14:25 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 7caaa27ba7 portal-trainer: the loop around portal's needs verifier
The trainer procedure as an agent skill, the engine contract, two
sector specs (software-studio: UHHM's own, green; construction: a
target with no pages yet), and the first wording run against uhhm.no.
The verifier itself is portal's question_lint (uhhm/portal 188f9bf).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-21 16:31:37 +02:00