@haus-tech/haus-workflow 4.9.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/cli.js +847 -499
  3. package/library/catalog/manifest.json +97 -34
  4. package/library/global/agents/request-assessor.md +2 -2
  5. package/library/global/agents/request-scorer.md +13 -8
  6. package/library/global/agents/request-specifier-eskalerad.md +1 -1
  7. package/library/global/agents/request-specifier.md +1 -1
  8. package/library/global/skills/request/SKILL.md +675 -363
  9. package/library/global/skills/request/scripts/archive.mjs +1376 -0
  10. package/library/global/skills/request/scripts/check-lasta.mjs +64 -0
  11. package/library/global/skills/request/scripts/compare-scores.mjs +23 -15
  12. package/library/global/skills/request/scripts/contract-check.mjs +108 -36
  13. package/library/global/skills/request/scripts/lib.mjs +66 -0
  14. package/library/global/skills/request/scripts/precheck.mjs +30 -27
  15. package/library/global/skills/request/scripts/report.mjs +571 -0
  16. package/library/global/skills/request/scripts/resolve-anchors.mjs +243 -0
  17. package/library/global/skills/request-assess-impact/SKILL.md +10 -10
  18. package/library/global/skills/request-score/SKILL.md +19 -10
  19. package/library/global/skills/request-sync/SKILL.md +4 -4
  20. package/library/global/skills/request-write-spec/SKILL.md +6 -6
  21. package/library/global/skills/request-write-spec/references/specformat.md +2 -2
  22. package/package.json +1 -1
  23. package/library/global/agents/request-classifier.md +0 -55
  24. package/library/global/skills/request/scripts/compare-classifications.mjs +0 -94
  25. package/library/global/skills/request/scripts/quote-repair.mjs +0 -166
  26. package/library/global/skills/request-classify/SKILL.md +0 -79
  27. package/library/global/skills/request-classify/references/klassningsinstruktion.md +0 -152
@@ -1,28 +1,29 @@
1
1
  ---
2
2
  name: request
3
- description: Enda ingången till Haus requestflöde. Använd när användaren säger "/request", "kör requestflödet", "speca och bedöm", "prisa den här posten", "ta önskemålet hela vägen", "vad ligger i kön", "detaljer <post>", eller när flera request-skills ska kedjas i en följd. Enskilda request-skills (request-write-spec, request-classify m.fl.) fungerar fortfarande fristående; den här skillen äger kedjan, arkivet och dispatchen till subagenter.
3
+ description: Enda ingången till Haus requestflöde. Använd när användaren säger "/request", "kör requestflödet", "speca och bedöm", "prisa den här posten", "ta önskemålet hela vägen", "vad ligger i kön", "detaljer <post>", eller när flera request-skills ska kedjas i en följd. Enskilda request-skills (request-write-spec, request-score m.fl.) fungerar fortfarande fristående; den här skillen äger kedjan, arkivet och dispatchen till subagenter.
4
4
  ---
5
5
 
6
6
  # /request — requestflödets ingång
7
7
 
8
- Tunn orkestrering ovanpå de fem request-skillsen. Den här skillen innehåller
9
- **noll domänregler**: allt om specformat, klassning, poäng och Asana-fält bor i
8
+ Tunn orkestrering ovanpå de fyra request-skillsen. Den här skillen innehåller
9
+ **noll domänregler**: allt om specformat, poäng och Asana-fält bor i
10
10
  respektive skill. Här bor bara routing, kontextbärande, arkivet och dispatchen.
11
11
 
12
12
  ## Uppgifter
13
13
 
14
14
  `/request [uppgift]` — utan argument: visa menyn nedan.
15
15
 
16
- | Uppgift | Gör |
17
- | -------------------------------------- | ---------------------------------------------------------------------------------------- |
18
- | `speca <önskemål eller gid>` | Källmanifest → dispatcha `request-specifier` → arkivera spec + granskarblock |
19
- | `bedöm <gid, slug eller nr>` | Grind → säkra analys → dispatcha `request-classifier` ∥ `request-scorer` → arkivera JSON |
20
- | `status` | Kö-läge via request-sync, BLUF-tabell med radnummer |
21
- | `godkänn <nr eller gid>` | Flytta Offer status framåt via request-sync — se grindavsnittet |
22
- | `underkänn <nr eller gid> <skäl>` | Skäl som Asana-kommentar + iterationsräknare via request-sync |
23
- | `detaljer <gid, slug eller nr> [steg]` | Skriv ut arkiverad JSON/dokument för posten |
24
- | `utvärdera <post…> [modell]` | A/B-kör hela flödet per modellvariant till experimentytan; `sammanställ` ger svepvyn |
25
- | `hjälp` | Förklara uppgifterna, rör inga filer |
16
+ | Uppgift | Gör |
17
+ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
18
+ | `speca <önskemål eller gid>` | Källmanifest → dispatcha `request-specifier` → arkivera spec + granskarblock |
19
+ | `bedöm <gid, slug eller nr>` | Grind → säkra analys → dispatcha `request-scorer` → arkivera JSON |
20
+ | `status` | Kö-läge via request-sync, BLUF-tabell med radnummer |
21
+ | `godkänn <nr eller gid>` | Flytta Offer status framåt via request-sync — se grindavsnittet |
22
+ | `underkänn <nr eller gid> <skäl>` | Skäl som Asana-kommentar + iterationsräknare via request-sync |
23
+ | `döm <post>` | Människodom vid OLIKA: välj körning, beställ omkörning eller underkänn underlaget |
24
+ | `detaljer <gid, slug eller nr> [steg]` | Skriv ut arkiverad JSON/dokument för posten |
25
+ | `utvärdera <post…> <modell…>` | Kör flödet en gång per namngiven modell mot experimentytan, minst en modell; `sammanställ` ger svepvyn, `rapport` en läsbar jämförelse |
26
+ | `hjälp` | Förklara uppgifterna, rör inga filer |
26
27
 
27
28
  ## Hårda regler
28
29
 
@@ -32,20 +33,30 @@ respektive skill. Här bor bara routing, kontextbärande, arkivet och dispatchen
32
33
  Skill-verktyget (`request-sync`).
33
34
  - **En skrivare i taget mot Asana.** Batchresultat skrivs tillbaka sekventiellt,
34
35
  en post i taget, aldrig parallellt.
35
- - **Dokument klistras bytetroget** in i subagent-prompter. Klassningens och
36
- poängens belägg är ordagranna citat; en trunkerad eller omformaterad inklistring
37
- ger tyst fel svar. Klistra aldrig in en sammanfattning.
38
- - **Prislistan och repot hålls borta från classifier/scorer.** Deras
39
- agentdefinitioner saknar sök- och shellverktyg (Grep/Glob/Bash), men Read
40
- finns kvar för skillens referensfil — läs-scopet är alltså en promptregel,
36
+ - **Dokument klistras bytetroget** in i specifier- och assessor-prompter
37
+ (önskemål, spec, granskarblock). En trunkerad eller omformaterad
38
+ inklistring flyttar källtexten under agentens fötter och ger tyst fel
39
+ svar. Klistra aldrig in en sammanfattning.
40
+ - **Prissättningens underlag pekas ut per sökväg (ADR-0099).** Scorerns
41
+ prompt bär två namngivna absoluta sökvägar (`spec.md`, `impact.md`) i
42
+ stället för inklistrad text — agenten läser filerna själv via Read, så
43
+ ingen avskrift kan trunkeras, och beläggens ankare (källa + delsträng)
44
+ löses av scripten mot exakt samma filer på disk. Läs-scopet är EXAKT
45
+ dessa två filer plus skillens egen katalog, aldrig
46
+ körningskatalogen som helhet: `granskarblock.md` är assessorns underlag
47
+ och äldre pricing-JSON vore ren kontaminering av dubbelkörningens
48
+ oberoende.
49
+ - **Prislistan och repot hålls borta från scorern.** Dess
50
+ agentdefinition saknar sök- och shellverktyg (Grep/Glob/Bash), och Read
51
+ är promptbegränsad enligt regeln ovan — läs-scopet är en promptregel,
41
52
  inte en fysisk spärr. Därför: lägg aldrig prislistans innehåll i prompten,
42
53
  och lägg inga egna sökvägar i dispatcherns rader utöver etiketterna i mallen.
43
- Sökvägar som redan står i det bytetrogna underlaget (analysen namnger filer,
54
+ Sökvägar som redan står i underlaget (analysen namnger filer,
44
55
  det är dess jobb) är inte ett brott — regeln gäller det dispatchern
45
56
  lägger till. Granska `LÄSTA:`-raden i svaret (se dispatch-kontraktet).
46
57
  - **Granskarblocken når aldrig kunden.** Specens granskarblock arkiveras separat
47
58
  (`granskarblock.md`). Analysens "## Till granskaren"-block ligger kvar i
48
- `impact.md` (det är del av underlaget för klassningen) — men inget
59
+ `impact.md` (det är del av underlaget för poängsättningen) — men inget
49
60
  granskarblock får någonsin skickas med i material som går till request-sync
50
61
  för kundsynliga fält.
51
62
  - **Arkivet är cache, Asana är sanningen.** Vid konflikt vinner brädan.
@@ -56,6 +67,12 @@ respektive skill. Här bor bara routing, kontextbärande, arkivet och dispatchen
56
67
  huvudkonversationen. `experiments/`-trädet är inte postkataloger: sync,
57
68
  batch och guard läser bara `.haus/requests/<gid-eller-slug>/` på toppnivån
58
69
  och rör aldrig `experiments/`.
70
+ - **Maskinen kör om enbart vid scriptbevisat kontraktsbrott.** Omdispatch
71
+ (budget EN per agent) svarar på ett fel som precheck, resolve-anchors eller
72
+ contract-check har bevisat. En oenighet mellan två GILTIGA körningar är en
73
+ bedömningsfråga och går alltid till människan via uppgiften `döm`: fler
74
+ maskinkörningar producerar fler röster, aldrig mer sanning. Ingen ny
75
+ omkörningsmekanism får läggas till som bryter mot detta.
59
76
 
60
77
  ## Arkivet: `.haus/requests/`
61
78
 
@@ -63,8 +80,8 @@ Orkestreringens kuvert. De haus-hanterade request-skillsen känner inte till det
63
80
  den här skillen (och agenterna via sina prompter) underhåller det.
64
81
 
65
82
  **En katalog = en spec = en prissättningsbar post.** En bunt (flera specar ur
66
- samma önskemål) blir flera kataloger — klassningen räknar omfattning per spec
67
- och poängen sätts per post, så en katalog med flera specar går inte att bedöma.
83
+ samma önskemål) blir flera kataloger — poängen sätts per post, så en katalog
84
+ med flera specar går inte att bedöma.
68
85
 
69
86
  ```
70
87
  <repo-rot>/.haus/requests/<gid-eller-slug>/
@@ -73,13 +90,22 @@ och poängen sätts per post, så en katalog med flera specar går inte att bed
73
90
  │ kopieras till varje delkatalog)
74
91
  ├── impact.md påverkansanalysen, ordagrann inkl. sitt
75
92
  │ Till granskaren-block
76
- ├── classification-pricing-vN.json nytt varv = ny fil, skriv aldrig över
77
- ├── score-pricing-vN.json N är gemensamt för paret (se bedöm steg 8)
78
- ├── classification-guard-vN.json guard-utfall synkas aldrig, bara arkiveras
79
- ├── score-guard-vN.json
93
+ ├── score-pricing-vN.json nytt varv = ny fil, skriv aldrig över
94
+ ├── score-guard-vN.json guard-utfall synkas aldrig, bara arkiveras
95
+ │ (egen N-sekvens per typ, skild från pricing)
80
96
  └── state.json
81
97
  ```
82
98
 
99
+ Äldre arkiv (före ADR-0098) bär även `classification-pricing-vN.json` /
100
+ `classification-guard-vN.json` från den borttagna klassaxeln. De läses och
101
+ visas som förut (`detaljer`, rapporten, `archive.mjs`) men skrivs aldrig av
102
+ nya körningar.
103
+
104
+ Förkastade försök bär `-avvisad`-suffix och står utanför N-räkningen:
105
+ prissättningens `<typ>-pricing-vN-avvisad.json` och textstegens
106
+ `spec-avvisad-<datum>.md` / `impact-avvisad-<datum>.md` (ADR-0099) — se
107
+ omdispatch-regeln i dispatch-kontraktet.
108
+
83
109
  - Katalognamn: Asana-gid när posten finns på brädan, annars en kebab-slug av
84
110
  spec-rubriken. Bunt utan gid: `<slug>-1`, `<slug>-2`, … När gid myntas senare:
85
111
  döp om katalogen till gid och notera sluggen i `state.json.former_slug`.
@@ -113,36 +139,44 @@ och poängen sätts per post, så en katalog med flera specar går inte att bed
113
139
  `{ "source": "asana" | "manual", "by": "<namn, krävs vid manual>",
114
140
  "status_read": "<värde>", "date": "YYYY-MM-DD" }`.
115
141
  Anteckningen är spårbarhet, aldrig själva godkännandet.
116
- - `granskarutslag` är en lista, en rad per viktningsutslag (granskaren
117
- konstaterar att en körning hade rätt, utan att någon sakuppgift ändras).
118
- `bedöm` steg 6 APPENDAR en rad, skriver ALDRIG över tidigare rader:
119
- `{ "varv": N, "date": "YYYY-MM-DD", "beslut": "<granskarens beslut,
120
- ordagrant>" }`. Tom lista (`[]`) när inget viktningsutslag ännu skett.
121
- Listan är ett revisionsspår och läses medvetet ALDRIG tillbaka in i någon
122
- prompt: utslaget är granskarens dom över körningarna, och når den agenterna
123
- styr den nästa bedömning i stället för att dokumentera den föregående.
124
- Nollas (töms) vid respec, av samma skäl som `approval` nollas (se `speca`
125
- steg 5): ett utslag mot en ersatt spec är inte längre giltigt. Bor ENDAST
126
- i `state.json`. Ett sakändringsutslag går i stället in i `impact.md` som
127
- Granskarutslag-blocket (se `bedöm` steg 6), aldrig hit.
142
+ - `granskarutslag` är en lista, en rad per dom, skriven via `archive.mjs utslag`, aldrig för hand.
143
+ Radform: `{ "typ": "viktning" | "kalibrering" | "sakandring", "date": "YYYY-MM-DD", "beslutad_av": "<namn>", ... }`.
144
+ Viktning bär dessutom `beslut` (ordagrant), `axel` (`score`; `classification`
145
+ förekommer i äldre arkiv), `n` och `galler_fil`: raden ÄR spärrlyftet,
146
+ `archive.mjs sparr` läser den.
147
+ Kalibrering bär `fraga`, `lasning1`, `lasning2`: en notis om att en
148
+ protokollfråga lät två giltiga läsningar divergera, underlag för nästa
149
+ instruktionsversion. Sakändring bär `beslut`: kvittot i `state.json` för
150
+ samma händelse som citatblocket i `impact.md` (se `döm`, vägen "Underlaget
151
+ är fel"). Det ordagranna beslutet bor i citatblocket, raden här är bara
152
+ revisionsspåret, aldrig underlaget självt.
153
+ Listan läses medvetet ALDRIG tillbaka in i någon prompt, oavsett typ: ett
154
+ utslag som når agenterna styr nästa bedömning i stället för att dokumentera
155
+ den föregående. Nollas (töms) vid respec, av samma skäl som `approval`
156
+ nollas (se `speca` steg 5): ett utslag mot en ersatt spec är inte längre
157
+ giltigt. Bor ENDAST i `state.json`. Rader skrivs aldrig om.
128
158
  - `runs[]` får en rad per dispatch, även spec- och analyskörningar:
129
159
  `{ "file": "spec.md" | "impact.md" | "<run>.json", "skill": "...",
130
- "agent": "...", "model": "<ur MODELL-raden>", "effort": "<ur agentdefinitionen>",
160
+ "agent": "...",
161
+ "model": { "uppgiven": "<ur MODELL-svansraden>", "fakturerad": "<känd fakturerad modell, annars null>" },
162
+ "effort": "<ur agentdefinitionen>",
131
163
  "date": "YYYY-MM-DD",
132
164
  "reference_sha256": { "<referensfil>": "<sha256>" },
133
165
  "underlag_sha256": { "spec.md": "<sha256>", "impact.md": "<sha256>" },
134
166
  "double_run": "bekräftad" | "olika" | "tolerans" | null,
135
- "superseded_by": null, "partial_rerun": false, "pairs_with": null,
136
- "quote_repairs": <antal> }`.
137
- `quote_repairs` är frivilligt (utelämnas när det är 0): antal RÄTTAT-rader
138
- från `quote-repair.mjs` för den körningen.
139
- `partial_rerun` och `pairs_with` är frivilliga och sätts bara på en
140
- pricing-rad ur ett riktat varv (se `bedöm` steg 6): `partial_rerun: true`
141
- markerar att raden kom ur en enaxlig omkörning, och `pairs_with` namnger
142
- den stående axelns fil den paras med. Pekaren bor på den omkörda axelns
143
- nya rad, aldrig på den stående axelns äldre rad, som aldrig skrivs om.
144
- Saknas (eller står `false`/`null`) på spec- och analysrader och på rader
145
- ur ett fullt varv.
167
+ "superseded_by": null, "partial_rerun": false, "pairs_with": null }`.
168
+ `model` bär två fält (ADR-0099): `uppgiven` är agentens självrapport ur
169
+ MODELL-svansraden, `fakturerad` fylls när dispatchern känner den
170
+ fakturerade modellen (`add-run --fakturerad`), annars `null` — faktureringens
171
+ sanning per körning bor i `proveniens.fakturerade_modeller`. Äldre arkiv bär
172
+ `model` som ren sträng och läses som förut.
173
+ `quote_repairs` förekommer i äldre arkiv (före ADR-0092) och läses men
174
+ skrivs aldrig av nya körningar.
175
+ Stämplingen görs alltid via `archive.mjs add-run`; hur N räknas ut, vilket
176
+ suffix en fil får och hur en riktad omkörnings parning skrivs bor i
177
+ scriptet och testerna. VILKA `--typ` som skickas till `archive.mjs next-n`,
178
+ alltså vilka axlar som faktiskt kördes i varvet, är fortfarande
179
+ orkestratorns beslut, inte scriptets.
146
180
  `underlag_sha256` är underlagsproveniensen: hashen för de dokument körningen
147
181
  faktiskt såg. Precheck vägrar bedöma när analysens spec-hash inte matchar
148
182
  nuvarande `spec.md`, och guard ska vägra diffa mot en körning vars underlag
@@ -154,45 +188,73 @@ ordagrant>" }`. Tom lista (`[]`) när inget viktningsutslag ännu skett.
154
188
  alla arkiverade körningar. Samma verktyg används för `underlag_sha256`.
155
189
  Referensfilerna ligger under Claude-konfigkatalogen (`CLAUDE_CONFIG_DIR`
156
190
  eller `~/.claude`). En senare guard-körning jämför hash och vägrar diffa vid
157
- skevhet ("omklassning krävs, skalan har ändrats").
191
+ skevhet ("ompoängsättning krävs, skalan har ändrats").
158
192
  - `status` blir ALDRIG `priced` när något stopputfall finns i varvets
159
- körningar, eller när det GÄLLANDE paret har `double_run: "olika"` olyft.
160
- Spärren gäller det gällande paret, inte varje enskild rad för sig: har ett
161
- senare riktat varv landat LIKA eller LIKA_TOLERANS, är spärren lyft för
162
- hela paret, även om den oeniga axelns äldre rader fortfarande bär
163
- `double_run: "olika"` (de skrivs aldrig om, se `partial_rerun`/
164
- `pairs_with` ovan). Läs upplåsningen på den omkörda axelns senaste rad,
165
- aldrig på en äldre. `double_run: "tolerans"` räknas som bekräftad och
166
- blockerar inte `priced`.
193
+ körningar, eller när den GÄLLANDE raden har `double_run: "olika"` olyft, eller
194
+ när den gällande raden bär `partial_rerun: true` utan en matchande
195
+ dom (en beställd omkörning väntar på granskaren, se uppgiften `döm`).
196
+ `archive.mjs sparr` avgör bägge skälen identiskt (`sparrSkal`).
197
+ Spärren lyfts av ett viktningsutslag (`archive.mjs sparr` är den enda tolken,
198
+ se uppgiften `döm`) eller av en beställd omkörning vars dom landat i ett
199
+ viktningsutslag; ingen annan väg lyfter den, och den oeniga axelns äldre
200
+ rader skrivs aldrig om även efter lyft.
201
+ `double_run: "tolerans"` räknas som bekräftad och blockerar inte `priced`.
202
+ I äldre arkiv som bär en klassaxel (före ADR-0098) vägrar
203
+ `archive.mjs set-status priced` därutöver ett OFULLSTÄNDIGT par:
204
+ klass- och poängaxelns gällande varvnummer skiljer sig utan att skillnaden
205
+ är en förklarad enaxlig omkörning (`partial_rerun: true` på den högre
206
+ axelns gällande rad), eller poängaxeln saknas helt. Ett arkiv utan
207
+ klassaxel prövas aldrig mot par-regeln — poängen är den enda axeln.
208
+ Det här skälet prövas av `pricedBlockers` (`archive.mjs set-status`),
209
+ inte av `archive.mjs sparr` — reglerna bor i scriptet och dess tester.
167
210
  - `spec_synced` sätts av speca steg 7 (posten lagd på brädan);
168
211
  `guard_run` reserveras för guard-kommandot (senare byggsteg).
169
212
 
170
213
  ### Experimentytan: `experiments/`
171
214
 
172
- A/B-körningar från `utvärdera` bor i ett eget träd och är aldrig prisposter:
215
+ Modellkörningar från `utvärdera` bor i ett eget träd och är aldrig prisposter:
173
216
 
174
217
  ```
175
218
  <repo-rot>/.haus/requests/experiments/<slug>/
176
- ├── experiment.json ticketreferens, datum, kandidatmodell,
177
- │ modell per agent per varv, manifest-hash, status
178
- ├── jamforelse.md skrivs när båda varven är klara
179
- ├── baseline/ full standardstruktur enligt arkivkontraktet ovan
180
- └── <kandidatmodell>/ samma struktur; delkataloger del-N/ vid DELA_UPP
219
+ ├── experiment.json ticketreferens, datum, modellista, manifest-hash,
220
+ │ status per körning
221
+ ├── <modell>/ `default` som modellvärde ger katalognamnet
222
+ │ `baseline/`
223
+ │ ├── k1/
224
+ │ ├── k1/korning.json headless-svaret RÅTT: USD, tokens, dispatcher
225
+ │ ├── k1/matning.json startarens egen mätning: startad, avslutad, wall_ms
226
+ │ ├── k2/ senare körning av SAMMA modell
227
+ │ └── k2/del-1/ … delkataloger vid DELA_UPP
228
+ └── <annan modell>/k1/ …
181
229
  ```
182
230
 
183
- - Katalognamnet `experiments` är reserverat — en spec vars rubrik skulle
184
- sluggas till `experiments` får suffixet `-post`.
185
- - Variantkatalogerna följer postkatalogens kontrakt bytetroget (spec.md,
186
- granskarblock.md, impact.md, pricing-JSON, state.json, `runs[]`-reglerna) —
187
- därför fungerar `precheck.mjs` och `contract-check.mjs` oförändrade, och
188
- proveniensen (modell, effort, hashar) följer med gratis.
189
- - `state.json` i en variantkatalog bär markören `"experiment": true`.
190
- `approval` förblir `null` och `status` blir ALDRIG `priced` — ett
231
+ - **Två filer, två ägare.** `korning.json` är headless-svaret ordagrant och
232
+ ägs av CLI:n; `matning.json` är startarens klocka och ägs av oss. En
233
+ haus-nyckel inne i `korning.json` skulle göra den till ett blandat format
234
+ som inte längre går att ställa mot CLI:ns egen utdata.
235
+ - **Ingen körning skrivs någonsin över.** Värdet i en gammal körning är att
236
+ kunna jämföra samma modell före och efter en ändring i skillen eller
237
+ agentprompterna; skriver en ny körning över den är den jämförelsen borta för
238
+ alltid. Varje körning får därför en egen katalog `k<N>` under sin modell.
239
+ - **Körningskatalogen ÄR postkatalogen.** Den följer arkivkontraktet
240
+ bytetroget (spec.md, granskarblock.md, impact.md, pricing-JSON, state.json,
241
+ `runs[]`-reglerna), så `precheck.mjs` och `contract-check.mjs` fungerar
242
+ oförändrade, de pekas bara på `<modell>/k<N>/`. Proveniensen följer med gratis.
243
+ - **Numret allokeras aldrig av skillen själv**, alltid med
244
+ `archive.mjs ny-korning <modellkatalog>`, som skapar katalogen
245
+ atomiskt och skriver dess sökväg. Två samtidiga processer, till exempel två
246
+ Claude-konton mot samma checkout, får då `k2` och `k3`, aldrig samma katalog.
247
+ Räknar skillen själv förlorar den ena processens körning tyst.
248
+ - `state.json` i en körningskatalog bär markören `"experiment": true`.
249
+ `approval` förblir `null` och `status` blir ALDRIG `priced`: ett
191
250
  experimentresultat kan inte förväxlas med en prispost.
192
- - `experiment.json` bär `status` per variant: `"klar"` (båda stegen
193
- arkiverade och jämförelse-underlag komplett), `"ofärdig"` (avbruten,
194
- subagentdöd, kontraktsbrott eller MODELL-avvikelse), `"stopp"` (arkiverat
195
- stopputfall).
251
+ - Katalognamnet `experiments` är reserverat: en spec vars rubrik skulle sluggas
252
+ till `experiments` får suffixet `-post`.
253
+ - `experiment.json` bär `varianter: []` i deklarationsordning och `status` per
254
+ körning: `"klar"`, `"ofärdig"`, `"stopp"`, `"väntar på dom"`. Literalerna
255
+ skrivs exakt så, mellanslag och diakritiska tecken inkluderade. Äldre filer
256
+ med `baselinemodell` och `kandidatmodell` läses utan fel; nya skrivningar
257
+ använder bara `varianter`.
196
258
  - `experiments/` ärver gitignore-skyddet från `.haus/requests/`.
197
259
 
198
260
  ## Uppgift: `speca`
@@ -218,8 +280,14 @@ A/B-körningar från `utvärdera` bor i ett eget träd och är aldrig prisposter
218
280
  kopieras till varje katalog som `granskarblock.md`). Bunt ur en gid-post:
219
281
  del 1 behåller gid-katalogen, resterande delar får slug-kataloger med
220
282
  `bundle.parent_slug` satt till gid:t; syskontasks på brädan mintas först
221
- vid sync. Lägg en `runs`-rad (`file: "spec.md"`, med `underlag_sha256`
222
- tomt) i varje berörd state.json.
283
+ vid sync. Stämpla varje berörd `state.json` med
284
+ `node <skillkatalog>/scripts/archive.mjs add-run <katalog> --file spec.md
285
+ --skill request-write-spec --agent <request-specifier|request-specifier-eskalerad>
286
+ --model <ur MODELL-svansraden> --ref references/specformat.md=<hash via ref-hash.mjs
287
+ på request-write-spec/references/specformat.md>`. Scriptet sätter
288
+ `underlag_sha256` tomt, en spec har inget underlag i repot — men
289
+ referens-hashen måste sättas explicit precis som för poängen, annars
290
+ tappas specformatets proveniens (se runs-kontraktet).
223
291
  **Respec över befintlig katalog invaliderar analysen:** när `spec.md`
224
292
  ersätts döps ev. `impact.md` om till `impact-superseded-<datum>.md`,
225
293
  status sätts till `spec_draft`, `approval` nollas och `granskarutslag`
@@ -228,7 +296,15 @@ A/B-körningar från `utvärdera` bor i ett eget träd och är aldrig prisposter
228
296
  den skevhet proveniens-kontrollen finns för att stoppa.
229
297
  6. **Formkontroll.** Kör `node <skillkatalog>/scripts/precheck.mjs <katalog>`
230
298
  per katalog. BRISTER i spec/granskarblock → dispatcha om specifiern EN gång
231
- enligt omdispatch-regeln; BRISTER i `state.json` är wrapperns egna filer och
299
+ enligt omdispatch-regeln. **Det förkastade utkastet får kvitto
300
+ (ADR-0099, samma regel som prissättningens `-avvisad`):** arkivera det
301
+ som `spec-avvisad-<datum>.md` innan omdispatchen, och stämpla det med en
302
+ egen runs-rad via `archive.mjs add-run --file spec-avvisad-<datum>.md
303
+ --note "<kontrollens felrader>"` (övriga flaggor som spec-radens). VARJE
304
+ dispatch får sin egen runs-rad — även den förkastade — så arkivet bär
305
+ både att ett omtag skedde och varför; en spec godkänd i andra försöket
306
+ får aldrig se ut som en som blev rätt direkt.
307
+ BRISTER i `state.json` är wrapperns egna filer och
232
308
  rättas av wrappern själv, aldrig via omdispatch. Kvarstår brister, visa dem
233
309
  och stanna. VARNING:ar visas men stoppar inget.
234
310
  7. **Svara BLUF:** en rad per spec (rubrik + ev. flaggor), sedan granskarblocket
@@ -239,8 +315,8 @@ A/B-körningar från `utvärdera` bor i ett eget träd och är aldrig prisposter
239
315
 
240
316
  ## Uppgift: `bedöm`
241
317
 
242
- Kör prissättningsbenet: påverkansanalys om den saknas, sedan klass ∥ poäng med
243
- oenighetsgrind.
318
+ Kör prissättningsbenet: påverkansanalys om den saknas, sedan poängsättning med
319
+ driftvakt.
244
320
 
245
321
  1. **Grind — obligatorisk, aldrig överhoppbar.** Bedömning kräver en granskad
246
322
  spec, och godkännandet bor i Asana:
@@ -274,207 +350,110 @@ oenighetsgrind.
274
350
  skickas med som internt underlag (samma förtroendedomän; flaggorna där är
275
351
  ofta analysens viktigaste ingång). Arkivera svaret som `impact.md`
276
352
  (inklusive dess "## Till granskaren"-block — visa blocket för användaren,
277
- aldrig till kundfält), lägg en `runs`-rad (`file: "impact.md"`,
278
- `underlag_sha256` med hash för `spec.md`). Kör precheck igen med `--impact`.
279
- 4. **Prissättning.** Dispatcha `request-classifier` och `request-scorer`
280
- **parallellt i samma meddelande** enligt promptmallarna. Ingen prislista,
281
- inget repo, inga andra posters dokument i prompterna.
282
- 5. **Kontraktskontroll.** Strippa svansraderna (`MODELL:`, `LÄSTA:`, ev.
283
- `AVVIKELSE:`) ur varje svar, skriv den rena JSON:en till en temporär fil och
284
- kör `node <skillkatalog>/scripts/contract-check.mjs <svar.json> <spec.md> <impact.md> --expect-id <katalogens id>`.
285
- BROTT → kör först
286
- `node <skillkatalog>/scripts/quote-repair.mjs <svar.json> <spec.md> <impact.md>`
287
- (deterministisk citaträttning: ett nästan-ordagrant belägg ersätts med sin
288
- entydigt närmaste källmening, allt annat lämnas orört; utan citatbrott är
289
- scriptet en no-op). Exit 0: kör kontraktskontrollen igen och anteckna
290
- `quote_repairs: <antal RÄTTAT-rader>` i runs-raden.
291
- **VARJE RÄTTAT-rad (före → efter) visas dessutom ordagrant för användaren i
292
- BLUF-svaret**, på samma sätt som en `AVVIKELSE:`-rad alltid visas. En
293
- räknare går inte att granska: rättningen byter belägg i en bedömning som
294
- redan är gjord, och den som läser svaret ska kunna se exakt vilket citat som
295
- byttes mot vilken källmening. Aldrig bara antalet. Kvarstår BROTT efter
296
- rättningen, eller gav rättningen exit 1 (orättbara citat): dispatcha om just
297
- den agenten EN gång enligt omdispatch-regeln;
298
- kvarstår brott, visa dem och stanna utan att arkivera det svaret som giltigt
299
- varv — men släng det inte: arkivera det som `<typ>-pricing-vN-avvisad.json`
300
- (utanför N-räkningen) med kontrollens felrader i en runs-rad, så även
301
- misslyckade körningar har kvitto. En `AVVIKELSE:`-rad visas alltid för
302
- användaren.
303
- 6. **Dubbelkörning (driftvakt).** Körs BARA när inget av svaren är ett
304
- stopputfall — stopproutningen i steg 7 går alltid först, en post som ändå
305
- går till människa ska inte kosta fyra extra körningar. Trigger: klassningens
306
- **utfall** är MEDIUM, LARGE eller OFFERT, ELLER poängen är ≥ 4 (poängen
307
- multipliceras direkt till pris — en hög poäng på låg klass förtjänar samma
308
- vakt). Dispatcha då `request-classifier` OCH `request-scorer` EN gång till,
309
- samma prompter, nya isolerade körningar, parallellt i samma meddelande.
310
- Kostnaden (ett extra par körningar) läggs medvetet exakt där pengarna står
311
- på spel — poängen multipliceras direkt till pris och båda skillsens eget
353
+ aldrig till kundfält), stämpla med
354
+ `node <skillkatalog>/scripts/archive.mjs add-run <katalog> --file impact.md
355
+ --skill request-assess-impact --agent request-assessor
356
+ --model <ur MODELL-svansraden>` (scriptet sätter `underlag_sha256` mot
357
+ `spec.md`). Kör precheck igen med `--impact`. Fäller precheck det nya
358
+ utkastet → omdispatcha assessorn EN gång enligt omdispatch-regeln, och ge
359
+ det förkastade utkastet kvitto precis som i speca steg 6: arkivera det som
360
+ `impact-avvisad-<datum>.md` och stämpla en egen runs-rad med kontrollens
361
+ felrader i `--note` (ADR-0099).
362
+ 4. **Prissättning.** Dispatcha `request-scorer` enligt promptmallen.
363
+ Ingen prislista, inget repo, inga andra posters dokument i prompten.
364
+ 5. **Ankarlösning och kontraktskontroll.** Strippa svansraderna (`MODELL:`,
365
+ `LÄSTA:`, ev. `AVVIKELSE:`) ur svaret. Kör
366
+ `node <skillkatalog>/scripts/check-lasta.mjs "<LÄSTA-radens innehåll>" <spec.md> <impact.md>`
367
+ (exit 1 = kontraktsbrott, se dispatch-kontraktet). Skriv sedan den rena
368
+ JSON:en till fil och kör i ordning:
369
+ `node <skillkatalog>/scripts/resolve-anchors.mjs <svar.json> <spec.md> <impact.md>`
370
+ (löser beläggsankare till ordagranna källblock; OLÖST/FLERTYDIG är ett
371
+ kontraktsbrott), sedan
372
+ `node <skillkatalog>/scripts/contract-check.mjs <svar.json> <spec.md> <impact.md> --expect-id <katalogens id>`.
373
+ BROTT från något av scripten → dispatcha om scorern EN gång enligt
374
+ omdispatch-regeln, med felraderna i prompten. Kvarstår brott: visa dem och
375
+ stanna utan att arkivera svaret som giltigt varv, men släng det inte:
376
+ arkivera som `score-pricing-vN-avvisad.json` (utanför N-räkningen) med
377
+ kontrollens felrader i en runs-rad, så även misslyckade körningar har
378
+ kvitto. En `AVVIKELSE:`-rad visas alltid för användaren.
379
+ 6. **Dubbelkörning (driftvakt).** Körs BARA när svaret inte är ett
380
+ stopputfall — stopproutningen nedan går alltid först, en post som ändå
381
+ går till människa ska inte kosta extra körningar. Trigger: poängen är ≥ 1
382
+ (ADR-0098: tröskeln täcker minst det den borttagna klassaxelns
383
+ MEDIUM/LARGE/OFFERT-villkor täckte; poängen multipliceras direkt till
384
+ pris). Dispatcha då `request-scorer` EN gång till,
385
+ samma prompt, ny isolerad körning.
386
+ Kostnaden (en extra körning) läggs medvetet exakt där pengarna står
387
+ på spel — poängen multipliceras direkt till pris och skillens eget
312
388
  acceptanstest är att två oberoende körningar ger samma resultat.
313
- - Kör kontraktskontrollen (steg 5) på båda nya svaren först, med egen
314
- omdispatch-budget (EN per agent).
389
+ - Kör hela steg 5 (ankarlösning, sedan kontraktskontroll) på det nya
390
+ svaret först, med egen omdispatch-budget (EN).
315
391
  - Jämför sedan deterministiskt:
316
- `node <skillkatalog>/scripts/compare-classifications.mjs <klass1.json> <klass2.json>`
317
392
  `node <skillkatalog>/scripts/compare-scores.mjs <poäng1.json> <poäng2.json>`
318
- - **Båda LIKA** → körning 1-paret gäller: `double_run: "bekräftad"` på dess
319
- runs-rader. Körning 2-filerna arkiveras som `...-pricing-vN-run2.json`
320
- med SAMMA N som paret och `superseded_by` satt till motsvarande körning
321
- 1-fil. `-run2`-filer räknas ALDRIG när nästa N bestäms, och guard och
393
+ - **LIKA** → körning 1 gäller: `double_run: "bekräftad"` på dess
394
+ runs-rad. Körning 2-filen arkiveras som `score-pricing-vN-run2.json`
395
+ med SAMMA N och `superseded_by` satt till körning 1-filen.
396
+ `-run2`-filer räknas ALDRIG när nästa N bestäms, och guard och
322
397
  `detaljer` läser alltid filen utan suffix.
323
- - **Någon OLIKA** → behandla posten som ESKALERA. Det beskriver routingen,
324
- aldrig artefakten: ingen fil ändras, ingen JSON skrivs om, inget
325
- ESKALERA-värde patchas in. Arkivera båda körningarna för båda axlarna
326
- (den som inte blir axelns huvudfil arkiveras som `-run2`) och stämpla
327
- runs-raderna PER AXEL, aldrig per
328
- varv. Det finns exakt en regel, och den går efter vad axelns eget
329
- jämförelsescript skrev:
330
- - **Den OENIGA axeln** (den vars script skrev OLIKA) får
331
- `double_run: "olika"` och `superseded_by: null` på bägge sina
332
- runs-rader. Körning 1 är huvudfil utan suffix och körning 2 arkiveras
333
- som `-run2`, men ingen av dem är utslagen: oenigheten är
334
- oavgjord tills en människa eller ett riktat varv avgör den, och
335
- `superseded_by` förblir därför `null` på båda.
336
- - **Den ENIGA axeln** behåller sitt vanliga utfall och sitt vanliga
337
- `superseded_by`: LIKA ger `double_run: "bekräftad"` med körning 1 som
338
- suffixfri huvudfil, LIKA_TOLERANS ger `double_run: "tolerans"` med
339
- verdiktradens utpekade körning (högsta poängen) som suffixfri
340
- huvudfil och den andra som `-run2` med `superseded_by` mot den, precis
341
- enligt LIKA_TOLERANS-punkten nedan, oavsett vilken av dem som var
342
- körning 1. Regeln "högsta poängen gäller" är densamma oavsett vilken
343
- punkt som routar posten.
344
-
345
- Arkivet namnger därmed vilken axel som var oenig: `"olika"` står bara på
346
- den axelns rader. Jämförelsescriptens verdikter lever bara i stdout och
347
- försvinner med sessionen, så utan den stämplingen kunde ett senare varv
348
- köra om fel axel och släppa igenom en oavgjord klassflip till pris.
349
- Var BÅDA axlarna OLIKA bär bägge axlarnas rader `"olika"`.
350
- Status blir `assessed`. Visa diffen (rad · körning 1 · körning 2)
351
- för granskaren. Inget `customer`-block ur någon av körningarna får gå
352
- till request-sync medan det GÄLLANDE paret har `double_run: "olika"`
353
- olyft (samma scope som `priced`-spärren, se state.json-reglerna ovan):
354
- har ett senare riktat varv landat LIKA eller LIKA_TOLERANS är spärren
355
- lyft för hela paret, även om den oeniga axelns äldre rader fortfarande
356
- bär `"olika"`. Läs upplåsningen på den omkörda axelns senaste rad,
357
- aldrig på en äldre. Välj ALDRIG en av körningarna själv och räkna
358
- ALDRIG fram ett medelvärde.
359
- **Återställningen är ett riktat nytt varv:** spärren (`double_run:
360
- "olika"`) sitter på den oeniga axelns rader, och ett nytt varv med LIKA
361
- (eller LIKA_TOLERANS) låser upp hela paret. VILKEN axel som körs om är
362
- ingen bedömning: det är den axel vars runs-rader bär `"olika"`.
363
- **Den omkörda axeln dubbelkörs ALLTID i ett riktat varv**, oavsett
364
- triggervillkoren i steg 6: spärren kan bara lyftas av ett
365
- jämförelseutslag, och en ensam körning ger inget att jämföra mot. En
366
- klassomkörning som landar SMALL med stående poäng under 4 skulle annars
367
- aldrig få något utslag och raderna förbli låsta för alltid. Hur MÅNGA
368
- axlar som körs om beror på vilket slags utslag granskaren gav:
369
- - **Viktningsutslag** (granskaren konstaterar att en körning hade rätt,
370
- utan att någon sakuppgift ändras): appendas som en ny rad i
371
- `state.json.granskarutslag` (se ovan), skriver ALDRIG över en
372
- tidigare rad, och går ALDRIG in i `impact.md`. Se
373
- Granskarutslag-punkten nedan för varför en fri text i underlaget vore
374
- fel. Underlaget är därmed oförändrat, så kör ENDAST den axel om
375
- (klass eller poäng) som var OLIKA, och bara den omkörda axelns agent
376
- dispatchas, aldrig båda. Triggerns villkor läses fortfarande mot den
377
- omkörda axelns nya svar plus den stående axelns gällande fil, aldrig
378
- mot ett nytt körningspar, men det är inte triggern som avgör om axeln
379
- dubbelkörs: i ett riktat varv dubbelkörs den alltid. Var BÅDA axlarna
380
- OLIKA finns ingen enig axel att hålla stilla: kör då BÅDA om ändå,
381
- `partial_rerun` förblir `false` på bägge nya rader. Vid enaxlig
382
- omkörning paras den stående axelns gällande fil med det nya resultatet
383
- (se steg 8) utan att skrivas om. Landar det riktade varvet
384
- LIKA/LIKA_TOLERANS lyfts spärren för hela paret, antecknat på den
385
- omkörda axelns nya runs-rad (`partial_rerun: true`, `pairs_with` mot
386
- den stående filens namn). Pekaren bor på den nya raden, den stående
387
- axelns rad skrivs aldrig om, så guard och `detaljer` läser
388
- upplåsningen via `pairs_with` på den nya raden, aldrig tvärtom.
389
- - **Sakändringsutslag**, eller ett beslut som av annat skäl måste stå i
390
- underlaget (se Granskarutslag-punkten nedan): appendas i `impact.md`,
391
- och vid en faktisk sakändring körs assessorn om (ny `impact.md`).
392
- Underlaget har då ändrats, en körning mot gammalt underlag får aldrig
393
- paras med en mot nytt, `underlag_sha256` skulle skilja och
394
- proveniens-kontrollen finns just för den skevheten, så kör BÅDA
395
- axlarna om, `partial_rerun` `false` på båda nya rader.
396
-
397
- - **Granskarutslag skrivs som citat, aldrig som prosa.** När granskarens
398
- beslut ska in i underlaget, alltså när det ändrar eller preciserar en
399
- sakuppgift i analysen, eller av annat skäl måste stå i underlaget för
400
- spårbarhet: appendas det sist i `impact.md` som ett avgränsat block
401
- enligt mallen nedan, beslutet ordagrant citerat, aldrig omformulerat av
402
- dispatchern och aldrig invävt i analysens löptext. En fritt formulerad
403
- utslagsmening läses av nästa körning som sakuppgift och styr om
404
- klassningen, det var precis felet i pilotkörningarna, därför alltid
405
- mallen, aldrig fri prosa. Kräver beslutet en faktisk sakändring i
406
- analysen: kör om assessorn (ny `impact.md`). Underlaget har i båda
407
- fallen ändrats, så `bedöm` kör om BÅDA axlarna (se riktade-varv-stycket
408
- ovan). Ett rent viktningsutslag, där granskaren bara konstaterar att en
409
- körning hade rätt utan att röra någon sakuppgift, hör ALDRIG hemma här:
410
- det appendas i stället som en rad i `state.json.granskarutslag`, se
411
- samma stycke, just för att underlaget ska förbli oförändrat och den
412
- riktade omkörningen giltig. Blocket är internt underlag med samma status som
413
- Till granskaren-blocket och följer aldrig med i kundtext.
414
-
415
- ```
416
- ## Granskarutslag (varv <N>, <YYYY-MM-DD>)
417
-
418
- > <granskarens beslut, ordagrant>
419
-
420
- Utslaget gäller endast viktningen mellan körningarna och ändrar inga
421
- sakuppgifter i analysen ovan.
422
- ```
423
-
424
- - **Klassjämförelsen LIKA men poängjämförelsen skriver LIKA_TOLERANS**
425
- (poängskillnad ≤ 0,5 med samma outcome och konfidens; klassjämförelsen
426
- har ingen tolerans, en klassflip är alltid OLIKA och routar posten som
427
- ESKALERA oavsett poängens tolerans, se föregående punkt) → paret räknas
428
- som bekräftat. Bytet gäller ENDAST poängaxelns filer: klassaxeln följer
429
- LIKA-regeln som vanligt, klass-körning 1-filen blir huvudfil utan suffix
430
- och klass-körning 2 arkiveras som `-run2` med `superseded_by`. För
431
- poängaxeln blir verdiktradens utpekade körning (högsta poängen)
432
- huvudfilen `score-pricing-vN.json`, och den andra arkiveras som `-run2`
433
- med `superseded_by` satt mot huvudfilen, oavsett vilken av dem som var
434
- körning 1. N är fortfarande gemensamt för de axlar som kördes i varvet
435
- (här: klass och poäng, båda).
436
- Huvudfilerna kan alltså komma från olika körningar, till exempel klass ur
437
- körning 1 och poäng ur körning 2. Det är avsiktligt: båda körningarna har
438
- passerat kontraktskontrollen och skillnaden ligger inom toleransen. Sätt
439
- `double_run: "tolerans"` på poängaxelns bägge runs-rader; klassaxelns
440
- runs-rader får `double_run: "bekräftad"` som vanligt. Toleransen är en
441
- medveten prisregel: högsta värdet skyddar marginalen, och ett medelvärde
442
- räknas fortfarande aldrig fram. Visa toleransraderna i BLUF-svaret.
443
- - Exit 2 från ett jämförelsescript är ett dispatcherfel (ojämförbara
398
+ - **OLIKA** → domen är människans, aldrig maskinens. Arkivera båda
399
+ körningarna (körning 1 utan suffix, körning 2 som `-run2`; på båda
400
+ raderna `double_run: "olika"` med `superseded_by: null`).
401
+ Status `assessed`. Ingen kundtext får gå till
402
+ request-sync medan spärren står (`archive.mjs sparr` är tolken).
403
+ Visa i BLUF-svaret beläggen bakom oenigheten, sida vid sida:
404
+ diffraderna (outcome, score, ankare, konfidens) har ingen
405
+ radkoppling till beläggen, `drivers[]` är en egen lista, så visa
406
+ samtliga `drivers[].citat`/`pastaende` ur båda körningarna
407
+ som stöd för hela utfallet. Det var beläggen som avgjorde domen i
408
+ varje uppmätt äkta oenighet. Hänvisa sedan till `döm <post>` och
409
+ STANNA: ingen omkörning, ingen eskalering, inget val av körning.
410
+ - **LIKA_TOLERANS** (poängskillnad ≤ 0,5 med samma outcome, oavsett
411
+ konfidens, en konfidensskillnad ensam fäller aldrig ett par inom
412
+ toleransen) → paret räknas som bekräftat. Verdiktradens utpekade
413
+ körning (högsta poängen) blir huvudfilen `score-pricing-vN.json`,
414
+ och den andra arkiveras som `-run2` med `superseded_by` satt mot
415
+ huvudfilen, oavsett vilken av dem som var körning 1. Det är
416
+ avsiktligt: båda körningarna har passerat kontraktskontrollen och
417
+ skillnaden ligger inom toleransen. Sätt `double_run: "tolerans"` på
418
+ bägge runs-raderna. Toleransen är en medveten prisregel: högsta
419
+ värdet skyddar marginalen, och ett medelvärde räknas fortfarande
420
+ aldrig fram. Visa toleransraderna i BLUF-svaret.
421
+ - Exit 2 från jämförelsescriptet är ett dispatcherfel (ojämförbara
444
422
  körningar) — visa felet och stanna, rapportera aldrig LIKA.
445
- 7. **Oenighetsgrind klass ↔ poäng.** Deterministiska regler, i ordning:
446
- - Endera svaret är ett stopputfall → hela posten routas enligt stopplistan
447
- nedan. Det andra svaret arkiveras men markeras `superseded_by` mot
448
- stopputfallets fil, och statusen blir `assessed`, aldrig `priced`.
449
- - Båda levererar (klass + poäng): flagga oenighet i BLUF-tabellen mot
450
- ankarbanden — klass TINY/SMALL med poäng ≥ 4, klass MEDIUM med poäng
451
- ≤ 0.75 eller ≥ 13, klass LARGE/OFFERT med poäng ≤ 3. Flaggan är
452
- information till granskaren — ingen automatisk åtgärd, ingen omkörning.
453
- 8. **Arkivera** godkända JSON-svar. Paret arkiveras atomärt: båda eller inget
454
- ("båda eller inget" gäller de axlar som kördes i varvet: vid riktad
455
- omkörning arkiveras den omkörda axelns fil ensam, och dess runs-rad får
456
- `partial_rerun: true` samt `pairs_with: "<den stående filens namn>"`.
457
- Pekaren bor på den nya raden, aldrig på den stående axelns äldre rad, som
458
- aldrig skrivs om, så guard och `detaljer` hittar paret genom att läsa den
459
- nya raden),
460
- och `N` i `-pricing-vN.json` är gemensamt för de axlar som kördes i
461
- varvet (nästa N = högsta befintliga för någon av filtyperna + 1, räknat
462
- bland de filtyper som kördes; vid riktad omkörning bumpar alltså bara den
463
- omkörda filtypens N; `-run2`- och `-avvisad`-filer räknas aldrig;
464
- guard-filer har en EGEN N-sekvens, skild från pricing). Uppdatera
465
- `state.json.runs` med modell, effort, referens-hash och `underlag_sha256`
466
- (hash för `spec.md` och `impact.md` som körningen såg) per fil, status →
467
- `priced` (eller `assessed` vid stopputfall).
468
- 9. **Svara BLUF:** tabell `post · klass · poäng · utfall · konfidens`, en rad
469
- per avvikelse värd att se (oenighetsflagga, ESKALERA, DELA_UPP,
470
- INPUT_SAKNAS, AVVIKELSE-rader, samt varje RÄTTAT-rad från citaträttningen
471
- enligt steg 5). JSON:en visas inte i chatten —
423
+ 7. **Arkivera** godkända JSON-svar. Hämta varvets N med
424
+ `node <skillkatalog>/scripts/archive.mjs next-n <katalog> --typ score`,
425
+ skriv filerna (`score-pricing-vN.json`, körning 2
426
+ som `-run2`, avvisade som `-avvisad`), och stämpla VARJE körning med
427
+ `archive.mjs add-run` (flaggor för fil, skill, agent, modell ur
428
+ MODELL-svansraden, effort ur agentdefinitionen, referens-hash via `--ref`
429
+ för skillens referensfil (se runs-kontraktet), double-run-utfall,
430
+ superseded-by, partial-rerun och pairs-with där de gäller). Exempel för
431
+ huvudfilen vid ett bekräftat par:
432
+ `node <skillkatalog>/scripts/archive.mjs add-run <katalog>
433
+ --file score-pricing-v1.json --skill request-score
434
+ --agent request-scorer --model <ur MODELL-svansraden>
435
+ --effort <ur agentdefinitionen> --ref poangskala.md=<hash via
436
+ ref-hash.mjs på request-score/references/poangskala.md>
437
+ --double-run bekräftad`. `--double-run` tar ENDAST de tre
438
+ literalerna `bekräftad`, `olika` eller `tolerans` (scriptet vägrar allt
439
+ annat, flaggnamnet med bindestreck, aldrig `--double_run` med understreck
440
+ som i JSON-fältet). Utelämna flaggan helt när ingen dubbelkörning gjorts.
441
+ `--superseded-by <fil>` och `--partial-rerun` (utan värde) läggs till där
442
+ de gäller, se runs-kontraktet. Stämplingsreglerna
443
+ bor i scriptet och dess tester, inte här. Sätt status via
444
+ `archive.mjs set-status <katalog> priced` (scriptet vägrar vid spärr,
445
+ stopputfall och experiment — se runs-kontraktet)
446
+ eller `assessed`.
447
+ 8. **Svara BLUF:** tabell `post · poäng · utfall · konfidens`, en rad
448
+ per avvikelse värd att se (ESKALERA, DELA_UPP,
449
+ INPUT_SAKNAS, AVVIKELSE-rader). JSON:en visas inte i chatten —
472
450
  `detaljer <post>` gör det. Skriv-tillbaka till brädan sker via request-sync
473
451
  i huvudkonversationen, bara på uttrycklig begäran — och det är den flytten
474
452
  som tar posten ✅ Spec ok → ⚖️ Poängsättning redo för granskning enligt
475
453
  syncens regler.
476
454
 
477
- **Stopputfall routas, aldrig tolkas:**
455
+ **Stopputfall routas, aldrig tolkas.** Ett stopputfall arkiveras som varvets
456
+ fil (steg 7), statusen blir `assessed`, aldrig `priced`, och posten routas:
478
457
 
479
458
  - `DELA_UPP` → föreslå ny analysrunda per del; delarna blir egna kataloger med
480
459
  `split` satt (`part`/`of`), och en del utan tak blir `OVER_SKALAN`, aldrig
@@ -524,75 +503,349 @@ missta:
524
503
  - Verben rör Offer status och kommentarer — aldrig Score, Class eller
525
504
  beskrivningsfält.
526
505
 
506
+ ## Uppgift: `döm`
507
+
508
+ Människans dom över en post vars dubbelkörning skrev OLIKA. Adressering som
509
+ `godkänn` (radnummer eller gid, aldrig fuzzy). Kräver att spärren står
510
+ (`archive.mjs sparr` exit 1), annars: visa status och stanna.
511
+
512
+ **En variantkatalog (från `utvärdera`) adresseras med sin sökväg direkt,
513
+ aldrig med radnummer eller gid.** Experimentets slug är samma sträng som ett
514
+ vanligt gid skulle vara, så gid-adressering skulle resolva till postkatalogen
515
+ på toppnivå, inte till variantkatalogen under `experiments/<slug>/`.
516
+ `archive.mjs` tar ändå en katalog som argument oavsett var den ligger, så
517
+ sökvägen fungerar identiskt.
518
+
519
+ **En dom på en katalog under `experiments/` skriver aldrig om
520
+ `experiment.json` i sig.** `archive.mjs utslag` och `archive.mjs sparr`
521
+ verkar bara på variantkatalogens egen `state.json`. Statusen i
522
+ `experiment.json` uppdateras inte av `döm` — den uppdateras av `utvärdera`,
523
+ körd igen för samma post, vars återupptagbarhetsregel omvärderar en
524
+ `"väntar på dom"`-variant och gör utfallet synligt för rapporten när den körs
525
+ (se `utvärdera`).
526
+
527
+ 1. **Visa underlaget.** Kör jämförelsescriptet på det gällande paret och visa
528
+ varje diffrad med beläggen sida vid sida (som i bedöm steg 6). Ingen
529
+ sammanfattning i stället för beläggen: domen fattas på dem.
530
+ 2. **Fråga granskaren** (AskUserQuestion) med tre vägar.
531
+ - **"Körning N gäller"** (N är 1 eller 2, vilken av de två uppmätta
532
+ körningarna som hade rätt): skriv domen via `archive.mjs utslag <katalog> --typ viktning --beslut "<ordagrant>" --beslutad-av <namn> --axel score --n <n> --galler-fil <fil>`.
533
+ (`--axel classification` finns kvar enbart för domar i äldre arkiv
534
+ med en klassaxel, före ADR-0098.)
535
+ `--n` är INTE körningsnumret i rubriken ovan: det är det AKTUELLA
536
+ varvet, avläst ur den senaste pricing-filen
537
+ `score-pricing-v<n>.json` (aldrig `next-n`s utdata, som pekar på
538
+ NÄSTA, ännu okörda varv). `--galler-fil` är den arkiverade fil
539
+ granskaren dömer till
540
+ förmån för: körning 1 → `score-pricing-v<n>.json` utan suffix,
541
+ körning 2 → `score-pricing-v<n>-run2.json`. Efter en beställd
542
+ omkörning (nästa väg) finns TRE arkiverade filer, och
543
+ `--galler-fil` kan peka på VILKEN som helst av dem: omkörningens egen
544
+ fil (version = gällande `n`), eller endera av de två ursprungliga
545
+ körningarnas filer från ett LÄGRE varv, om granskaren dömer att en av
546
+ dem hade rätt hela tiden. Scriptet vägrar bara ett HÖGRE varv än `--n`
547
+ (en dom kan aldrig gälla ett varv som inte fanns när den skrevs) och en
548
+ fil som inte faktiskt arkiverades via `add-run`. Kör `archive.mjs sparr`
549
+ efteråt: exit 0 betyder att spärren är lyft, exit 1 betyder att
550
+ något fortfarande väntar (utskriften namnger vad).
551
+ Inga filer döps om eller skrivs om.
552
+ - **"Beställ omkörning":** EN ny körning, ingen tvångsdubbling: dispatcha
553
+ scorern (ordinarie promptmall och kontraktskedja), arkivera med
554
+ `partial_rerun` och `pairs_with` mot den stående filen. Den nya
555
+ raden väntar precis som originalraden på en dom (`archive.mjs sparr`
556
+ spärrar den ensam, oavsett vad den råkar bära i `double_run`): visa
557
+ scriptdiffen mot BÅDA de stående körningarna och gå till steg 2 igen,
558
+ det är fortfarande granskaren som dömer. Vill granskaren ha två nya
559
+ mätningar beställs två.
560
+ - **"Underlaget är fel":** granskarens beslut appendas i `impact.md` som
561
+ citatblock enligt mallen nedan, assessorn körs om (ny `impact.md`),
562
+ därefter kör `bedöm` ett nytt fullt varv. En körning mot
563
+ gammalt underlag paras aldrig med en mot nytt.
564
+ 3. **Kalibreringsnotis.** Är oenigheten äkta (en fråga eller ett ankarval som
565
+ två giltiga körningar läste olika, inte en etikett): skriv `archive.mjs utslag <katalog> --typ kalibrering --beslutad-av <namn> --fraga <id> --lasning1 "<körning 1:s läsning, en mening>" --lasning2 "<körning 2:s läsning>"`.
566
+ Notisen är råmaterial till nästa instruktionsversion (mekanismen bakom
567
+ v0.2 till v0.6) och läses aldrig in i någon prompt. `archive.mjs kalibrering <arkivrot>`
568
+ listar alla.
569
+
570
+ **Granskarutslag skrivs som citat, aldrig som prosa.** När granskarens
571
+ beslut ska in i underlaget, alltså när det ändrar eller preciserar en
572
+ sakuppgift i analysen, eller av annat skäl måste stå i underlaget för
573
+ spårbarhet: appendas det sist i `impact.md` som ett avgränsat block enligt
574
+ mallen nedan, beslutet ordagrant citerat, aldrig omformulerat av
575
+ dispatchern och aldrig invävt i analysens löptext. En fritt formulerad
576
+ utslagsmening läses av nästa körning som sakuppgift och styr om
577
+ bedömningen, det var precis felet i pilotkörningarna, därför alltid mallen,
578
+ aldrig fri prosa. Kräver beslutet en faktisk sakändring i analysen: kör om
579
+ assessorn (ny `impact.md`). Underlaget har i båda fallen ändrats, så
580
+ `bedöm` kör ett nytt fullt varv (se steg 2 ovan, vägen "Underlaget är fel").
581
+ Skriv samtidigt kvittot `archive.mjs utslag <katalog> --typ sakandring --beslut "<ordagrant>" --beslutad-av <namn>`
582
+ i `state.json` (se `granskarutslag` ovan): citatet i `impact.md` är
583
+ underlaget, sakandring-raden är bara revisionsspåret. Ett rent
584
+ viktningsutslag, där granskaren bara konstaterar att en körning hade rätt
585
+ utan att röra någon sakuppgift, hör ALDRIG hemma här: det skrivs i stället
586
+ via `archive.mjs utslag --typ viktning` (se steg 2 ovan, vägen "Körning N
587
+ gäller"), just för att underlaget ska förbli oförändrat. Blocket är internt
588
+ underlag med samma status som Till granskaren-blocket och följer aldrig
589
+ med i kundtext.
590
+
591
+ ```
592
+ ## Granskarutslag (varv <N>, <YYYY-MM-DD>)
593
+
594
+ > <granskarens beslut, ordagrant>
595
+
596
+ Utslaget gäller endast viktningen mellan körningarna och ändrar inga
597
+ sakuppgifter i analysen ovan.
598
+ ```
599
+
527
600
  ## Uppgift: `detaljer`
528
601
 
529
602
  `detaljer <gid|slug|nr> [steg]` — skriv ut arkiverade filer för posten: utan
530
603
  steg en lista över vad som finns, med steg (`spec`, `granskarblock`, `analys`,
531
- `klass`, `poäng`, `state`) filens innehåll rått. För `klass`/`poäng`: senaste
604
+ `poäng`, `state`) filens innehåll rått; `klass` läser äldre arkivs
605
+ classification-filer (före ADR-0098). För `klass`/`poäng`: senaste
532
606
  `-pricing-vN.json` utan suffix (aldrig `-run2`/`-avvisad`).
533
607
 
534
608
  ## Uppgift: `utvärdera`
535
609
 
536
- A/B-utvärdering av modellvalet: kör en post genom hela flödet två varv —
537
- `baseline` med agentdefaults och ett varv med alla agenter tvingade till en
538
- kandidatmodell (default `opus`) — och arkivera all output sida vid sida under
539
- experimentytan. Uppgiften samlar underlag; människan analyserar. Ingen dom
540
- fälls över vilken modell som är bäst.
610
+ Modellutvärdering: `utvärdera <post…> <modell…>`, med minst en modell. Kör en
611
+ post genom hela flödet en gång per namngiven modell, varje varv med samtliga
612
+ tre agenter (specifiern, assessorn, scorern) tvingade till varvets
613
+ modell, så varje varv mäter en faktisk modellskillnad i stället för brus mellan
614
+ en fast produktionsmix och en enda experimentmodell.
615
+ `default` som modellvärde ger agentdefaults (dagens produktionsblandning) och
616
+ kör utan override; katalognamnet blir då `baseline/`, för alla andra värden
617
+ `<modell>/`. Arkivera all output sida vid sida under experimentytan.
618
+ Uppgiften samlar underlag; människan analyserar. Ingen dom fälls över vilken
619
+ modell som är bäst, och ingen dom simuleras: en OLIKA i något varvs
620
+ dubbelkörning väntar på `döm`, precis som i produktion.
621
+
622
+ **Underkommandon resolvas först.** Är det enda argumentet `sammanställ` eller
623
+ `rapport`, är det underkommandot `utvärdera sammanställ` respektive
624
+ `utvärdera rapport` (se avsnitten nedan). Argumentreglerna nedan gäller aldrig
625
+ de orden; de klassificeras varken som modell eller post-id.
626
+
627
+ **Flaggorna plockas bort först.** `--om`, `--hoppa-över` och `--körning
628
+ <katalog>` (flaggan plus dess värde) lyfts ur argumentlistan INNAN skanningen
629
+ nedan börjar, och räknas varken som modell eller post-id. Utan det steget
630
+ stoppar svepets egen rad, som slutar med `--körning <katalog>`, skanningen
631
+ omedelbart, noll modeller hittas, och kommandot faller på "Minst en modell
632
+ krävs" trots att modellen står där.
633
+
634
+ **Argumenttolkning.** Kvarvarande avslutande argument avgörs höger till vänster
635
+ för att hitta GRÄNSEN mot post-id-listan: ett argument räknas som modell bara
636
+ om det är ett känt agentmodellnamn (`fable`, `opus`, `sonnet`, `haiku`, …) eller
637
+ literalen `default`, allt annat läses som post-id, och skanningen stannar vid
638
+ det första argumentet som inte är ett modellnamn. Ett argument som varken är
639
+ ett känt modellnamn eller ett giltigt gid/slug är ett FEL, aldrig en gissning:
640
+ visa felet och stanna i stället för att chansa på vilken sida av gränsen det
641
+ hör hemma. De modellargument skanningen hittar bildar sedan modellistan i
642
+ DEKLARATIONSORDNING, vänster till höger.
643
+
644
+ **Minst en modell krävs.** Hittar skanningen ingen modell alls är det ett FEL,
645
+ aldrig en default. Ett kommando som kostar timmar och pengar ska säga vilka
646
+ modeller det kör; en tyst standarduppsättning gör att en körning kan starta med
647
+ en annan modell än den som avsågs, och den kostnaden syns först efteråt.
648
+
649
+ **Dubbletter vägras.** Står samma modellvärde två gånger i listan, vägra
650
+ körningen med ett felmeddelande som förklarar varför: två lika värden pekar på
651
+ samma katalognamn och mäter ingen skillnad mot varandra. Vill du köra samma
652
+ modell en gång till, gör det i en egen invokation, då blir det en ny körning
653
+ under samma modell enligt regeln i Experimentytan.
654
+
655
+ **En namngiven modell rör bara sin egen katalog.** Övriga modellers kataloger
656
+ läses inte och skrivs inte. Det är det som gör att en jämförelse kan byggas i
657
+ etapper: `utvärdera <gid> opus sonnet` idag och `utvärdera <gid> fable` en
658
+ vecka senare ger tre modeller under samma post, utan att de första två körs om.
659
+
660
+ **Omkörning frågas fram, den antas aldrig.** Namnger invokationen en modell som
661
+ redan har körningar under sig, stanna INNAN något dyrt startas och fråga om de
662
+ ska köras om. Ställ EN fråga som täcker alla kolliderande modeller, inte en per
663
+ modell. Svaret kan ges i förväg med `--om` (kör om) eller `--hoppa-över` (rör
664
+ dem inte); bär invokationen någon av dem ställs ingen fråga.
665
+
666
+ En omkörning skriver aldrig över den gamla körningen, den blir `k<N+1>`.
667
+ Frågan gäller alltså kostnaden, inte risken att förlora data.
541
668
 
542
669
  1. **Underlag.** Som `speca` steg 1: rått önskemål eller gid — vid gid hämtas
543
670
  posten läsande via request-sync i huvudkonversationen, uppgiftens ENDA
544
671
  Asana-kontakt. Skapa `experiments/<slug>/` och `experiment.json` med
545
- ticketreferens, datum och kandidatmodell.
672
+ ticketreferens, datum och `varianter` i deklarationsordning.
673
+
674
+ Anteckna samtidigt postens `permalink_url` i `experiment.json` när gid-svaret
675
+ bär det. Det kommer ur samma läsande hämtning som redan görs, så steget får
676
+ ingen ny Asana-kontakt. Saknas fältet i svaret skrivs det inte, och rapporten
677
+ visar då gid som ren text: Asanas permalänk bär ett workspace-gid som inte
678
+ finns på experimentytan, så en konstruerad URL vore en gissning.
679
+
680
+ **`experiment.json` skrivs läs-modifiera-skriv, aldrig från noll.** Saknas
681
+ filen skapas den. Finns den redan läses den in FÖRST och uppdateras sedan:
682
+ `varianter` slås ihop som UNION med bevarad deklarationsordning, de
683
+ befintliga namnen först och invokationens nya namn efter, och en befintlig
684
+ körnings `status` skrivs aldrig över av en process som inte äger just den
685
+ körningen. En headless-process med en enmodellslista rör alltså bara sin
686
+ egen modell. Utan regeln raderar `fable`-körningen en vecka senare `opus`
687
+ och `sonnet` ur filen, och eftersom det är den här filen
688
+ återupptagningsregeln läser (se Återupptagbart nedan) slutar ett återupptaget
689
+ svep känna igen färdiga körningar och betalar om för dem. Skrivningen ska
690
+ vara ATOMISK: skriv till en temporärfil i samma katalog och byt namn.
691
+ `experiment.json` är den enda filen på experimentytan som delas mellan
692
+ samtidiga processer utan den låsning `archive.mjs ny-korning` ger
693
+ körningskatalogerna, så samtidighetsdisciplinen måste stå här i stället.
694
+
546
695
  2. **Källmanifest EN gång.** Bygg manifestet som i `speca` steg 2 och
547
- återanvänd det byteidentiskt i båda varven. Anteckna manifest-hash i
696
+ återanvänd det byteidentiskt i ALLA varv. Anteckna manifest-hash i
548
697
  `experiment.json` (`ref-hash.mjs` på manifesttexten). Enda avsedda
549
698
  skillnaden mellan varven är modellen.
550
- 3. **Eskaleringsvalet görs en gång** enligt `speca`:s regler och gäller båda
551
- varven — även eskaleringsvalet är en del av det som hålls konstant.
552
- 4. **Varv `baseline`.** Kör speca-stegen (dispatch, kontraktskontroll,
553
- arkivering) och därefter bedöm-stegen (analys, klassning ∥ poäng,
554
- dubbelkörning, citaträttning, riktad omkörning) enligt ordinarie
555
- uppgifter, men mot variantkatalogen `baseline/` och utan
556
- godkännandegrind: `approval` förblir `null`, `state.json` får
557
- `"experiment": true`. Dispatcherna använder ordinarie promptmallar och
558
- agenternas defaults — ingen override. `REQUEST_ID` och `--expect-id`
559
- använder alltid ticketens gid/slug, aldrig variantkatalogens namn
560
- (`baseline`/modellnamnet).
561
- 5. **Varv `<kandidatmodell>`.** Exakt samma steg, prompter och underlag, men
562
- varje Agent-anrop får modell-override till kandidatmodellen.
563
- Agentdefinitionerna röres aldrig; effort tas ur definitionen som vanligt.
564
- Verifiera via MODELL-svansraden att overriden slog igenom och redovisa
565
- avvikelsen om den finns. Generellt för hela uppgiften: subagentdöd,
566
- kontraktsbrott (kvarstående BROTT efter citaträttning) eller
567
- MODELL-avvikelse — i vilket steg det än inträffar — sätter variantens
568
- `status` till `"ofärdig"` i `experiment.json`.
569
- 6. **DELA_UPP körs autonomt.** Ett DELA_UPP-utfall följer bedöms ordinarie
699
+ 3. **Eskaleringsvalet görs en gång** enligt `speca`:s regler och gäller alla
700
+ varv, även eskaleringsvalet är en del av det som hålls konstant.
701
+ Triggar valet: agenten blir `request-specifier-eskalerad` i stället för
702
+ `request-specifier`, likadant i alla varv. Modell-overriden i steg 4
703
+ gäller ändå den eskalerade agenten precis som de två andra: dess egen
704
+ pinnade modell, den som enligt agentdefinitionen ÄR eskaleringen, skrivs
705
+ över av varvets modell. Eskaleringsmekanismen kollapsar alltså medvetet
706
+ under override, det är avsett, inte en lucka: `utvärdera` mäter en ren
707
+ modellskillnad över alla tre rollerna och testar aldrig
708
+ eskaleringsbeslutet i sig.
709
+ 4. **Ett varv per modell i listan**, sekventiellt, i deklarationsordning.
710
+ Varje varv är EN egen headless-process, och det är det som ger mätningen
711
+ gratis. Ansvaret delas, eftersom en process aldrig kan känna sin egen
712
+ slutkostnad:
713
+
714
+ **Startaren** (huvudkonversationen, eller svepets loop) gör per modell:
715
+ allokerar körningskatalogen med `archive.mjs ny-korning`, startar
716
+ `claude -p --model sonnet --output-format json` med katalogen som explicit
717
+ argument, väntar in processen, och skriver JSON-svaret rått till
718
+ `<modell>/k<N>/korning.json`. Rapporten läser sedan `total_cost_usd`,
719
+ `usage.input_tokens`, `usage.output_tokens`,
720
+ `usage.cache_read_input_tokens`, `usage.cache_creation_input_tokens` och
721
+ `subagent_stats.spawned` ur den filen.
722
+
723
+ **Startaren tar tiden runt processen** och skriver `<modell>/k<N>/matning.json`
724
+ med `startad`, `avslutad` (båda ISO 8601) och `wall_ms` (differensen).
725
+ Filen skrivs ÄVEN när processen faller: en kraschad körning har en klocktid,
726
+ och den är ofta det intressantaste talet i tabellen. Rapporten läser
727
+ väggtiden därifrån, aldrig ur `korning.json`. Skälet är detsamma som för
728
+ kostnaden: en process kan inte känna sin egen klocktid när arbetet ligger i
729
+ bakgrundssubagenter, och svarets `duration_ms` räknar inte in väntan på dem.
730
+ `korning.json` förblir headless-svaret rått, därav den egna filen.
731
+
732
+ Startaren stämplar samtidigt körningens `state.json` med `proveniens`:
733
+
734
+ ```
735
+ node <skillkatalog>/scripts/archive.mjs proveniens <modell>/k<N> \
736
+ --modell <varvets modellvärde> --konto <vilket Claude-konto som körde> \
737
+ --underlag <sökväg till källmanifestet>
738
+ ```
739
+
740
+ Kommandot räknar själv `skill_sha256` (över `SKILL.md` plus de fyra
741
+ agentdefinitionerna) och `underlag_sha256`, läser `korning.json` och
742
+ antecknar `fakturerade_modeller` (den kanoniserade nyckelmängden ur
743
+ `modelUsage`, suffix som `[1m]` strippade — ADR-0099), och stämplar även varje
744
+ `del-N/`. Utan den stämpeln går det inte att avgöra
745
+ vad som skilde `k1` från `k2`, och en jämförelse över tid blir en
746
+ gissning. Anropet står här som ett
747
+ kommando och inte som en beskrivning med flit: ett steg som ålägger
748
+ startaren en skrivning utan att peka ut vem som utför den är en skrivning
749
+ som inte blir av, och den syns först som tomma celler långt senare.
750
+ Kör därför proveniens-stämpeln EFTER att `korning.json` skrivits, aldrig
751
+ före — annars saknar stämpeln faktureringsdatan.
752
+
753
+ **Modellverifiering görs av startaren mot faktureringen (ADR-0099),
754
+ aldrig mot svansraden ensam.** När processen är klar: jämför
755
+ `fakturerade_modeller` mot varvets begärda modell plus orkestratorns
756
+ (sonnet). En modellnyckel som varken är varvets modell eller
757
+ orkestratorns är en faktisk MODELL-avvikelse → körningen blir
758
+ `"ofärdig"`. En MODELL-svansrad som säger något annat än vad
759
+ `modelUsage` visar är en RAPPORTERINGSAVVIKELSE: den visas i rapporten
760
+ och står kvar i `runs[]` (raden bär agentens uppgift i
761
+ `model.uppgiven`), men den fäller ALDRIG ensam körningen — modeller är
762
+ opålitliga källor om sin egen identitet, och att kasta en korrekt
763
+ körning på en felskriven svansrad betalar om ett riktigt resultat.
764
+ Modellvärdet `default` kör agenternas egna defaults och får lagligt
765
+ producera flera modellnycklar: ingen mängdjämförelse görs där.
766
+
767
+ **Den inre processen** känns igen på invokationen, aldrig på gissning: bär
768
+ den `--körning`, är du den inre processen. Allokera då ingen katalog, starta
769
+ ingen ny process, och kör stegen direkt mot den anvisade katalogen. Utan det
770
+ stoppvillkoret läser den inre processen samma uppgift som startaren, startar
771
+ ett varv till och dubblar notan.
772
+
773
+ Den inre processen kör speca-stegen (dispatch, kontraktskontroll,
774
+ arkivering) och därefter bedöm-stegen (analys, poäng,
775
+ ankarlösning, dubbelkörning enligt bedöm) mot den anvisade katalogen, utan
776
+ godkännandegrind, och rör ingenting utanför den. Är modellen `default`
777
+ används ordinarie promptmallar och agenternas defaults, ingen override. Är
778
+ den ett modellnamn får varje Agent-anrop modell-override till den på ALLA
779
+ tre agenter; agentdefinitionerna röres aldrig, effort tas ur definitionen
780
+ som vanligt. Overriden verifieras av STARTAREN mot `modelUsage` (se
781
+ modellverifieringen ovan) — svansraden arkiveras men avgör aldrig ensam.
782
+ `approval` förblir `null`, `state.json`
783
+ får `"experiment": true`. `REQUEST_ID` och `--expect-id` använder alltid
784
+ ticketens gid/slug, aldrig katalogens namn.
785
+
786
+ Orkestratorn pinnas till sonnet i ALLA körningar. Dess kostnad blir då en
787
+ konstant som går att räkna bort, och `modelUsage` i JSON-svaret skiljer den
788
+ från agenternas kostnad utan extra arbete.
789
+
790
+ Subagentdöd, kontraktsbrott (kvarstående BROTT efter omdispatch) eller
791
+ en faktisk MODELL-avvikelse (obegärd nyckel i `modelUsage`, aldrig en
792
+ ensam svansradsavvikelse), i vilket steg det än inträffar, sätter
793
+ körningens `status` till `"ofärdig"` i `experiment.json`.
794
+
795
+ 5. **DELA_UPP körs autonomt.** Ett DELA_UPP-utfall följer bedöms ordinarie
570
796
  delningsregler men utan paus för granskare: delkataloger
571
- `<variant>/del-1/ … del-N/` med `split` satt, förälderns `spec.md` +
572
- `granskarblock.md` kopierade in, ny analys + klassning + poäng per del.
797
+ `<modell>/k<N>/del-1/ … del-N/` med `split` satt, förälderns `spec.md` +
798
+ `granskarblock.md` kopierade in, ny analys + poäng per del.
573
799
  En del utan tak blir `OVER_SKALAN` och delas aldrig vidare. Övriga
574
800
  stopputfall (`TILLBAKA_TILL_SPEC`, `KONCEPT`, `DIAGNOS`, `ESKALERA`,
575
801
  `INPUT_SAKNAS`) kräver människa eller kund: arkivera utfallet, avbryt det
576
- varvet och redovisa i jämförelsen — det andra varvet fortsätter oberoende.
577
- 7. **Jämförelse.** När båda varven är klara, skriv
578
- `experiments/<slug>/jamforelse.md`: delningsbeslutet per variant (delade
579
- sig / delade sig inte), tabell per post/delpost med klass, poäng,
580
- inringning, dubbelkörningsutfall, stopputfall och `quote_repairs` per
581
- variant, samt kort notis om specskillnader (rubrik, omfång, Ingår
582
- inte-avvikelser). Ingen värdering av vilken variant som är bättre —
583
- rådatan per katalog är analysunderlaget.
584
- 8. **Rapport.** BLUF i chatten: klart/ofärdigt per varv, stopputfall, och
585
- sökvägen till `experiments/<slug>/`. Ingen skrivning mot Asana.
802
+ varvet, gör det synligt i rapporten när den körs, och övriga körningar i
803
+ listan fortsätter oberoende.
804
+
805
+ **OLIKA väntar på dom.** Skriver dubbelkörningen OLIKA i ett varv:
806
+ arkivera enligt bedöms regler (spärren står), sätt körningens status till
807
+ `"väntar på dom"` i `experiment.json`, synligt i rapporten när den körs.
808
+ Domen är människans även i experimentet: `döm` körs mot körningskatalogen
809
+ när granskaren vill (adresserad via sin sökväg, se `döm`), och ingen dom
810
+ simuleras av uppgiften. Domen i sig skriver inte om `experiment.json`,
811
+ det gör `utvärdera` självt, nästa gång det körs för samma post (se
812
+ Återupptagbart i avsnittet Batch nedan för hur och när statusen går
813
+ till `"klar"` och rapporten kan visa utfallet). Övriga körningar i listan
814
+ fortsätter oberoende oavsett när, eller om, domen fälls.
815
+
816
+ 6. **Rapport.** BLUF i chatten: klart eller ofärdigt per körning, stopputfall,
817
+ och sökvägen till `experiments/<slug>/`. Nämn att `utvärdera rapport` finns
818
+ när underlaget ska läsas sida vid sida. Ingen skrivning mot Asana.
586
819
 
587
820
  ### Batch: flera poster
588
821
 
589
- `utvärdera <post1> <post2> … [kandidatmodell]` kör varje ticket i en EGEN
822
+ `utvärdera <post1> <post2> … <modell…>` kör varje ticket och modell i en EGEN
590
823
  headless-process, sekventiellt:
591
824
 
592
825
  ```
593
- claude -p "/request utvärdera <gid> <kandidatmodell>"
826
+ claude -p --model sonnet --output-format json "/request utvärdera <gid> <modell> --hoppa-över --körning <katalog>"
594
827
  ```
595
828
 
829
+ Orkestratorn är huvudloopens modell och pinnas till sonnet i headless:
830
+ agenternas modeller styrs av definition plus override och verifieras av
831
+ startaren mot `modelUsage` i `korning.json` (ADR-0099) —
832
+ aldrig av huvudloopens val, och aldrig av svansraden ensam.
833
+
834
+ **Raden bär ALLTID `--om` eller `--hoppa-över`, och väljer `--hoppa-över`.**
835
+ Det är inte en stilregel utan det som gör svepet möjligt: en `claude -p`-process
836
+ kan inte svara på en fråga, så en rad utan flagga skulle hänga eller gissa.
837
+ `--hoppa-över` är dessutom precis återupptagningens semantik, ett avbrutet svep
838
+ som startas om plockar upp där det stannade i stället för att betala om för
839
+ allt färdigt.
840
+
841
+ `--körning <katalog>` pekar ut den körningskatalog som `archive.mjs ny-korning`
842
+ redan allokerat åt den ticketen och modellen. Den inre processen arkiverar
843
+ bara dit, aldrig någon annanstans.
844
+
845
+ Svepets loop är startaren och har startarens hela ansvar per rad: den tar tiden
846
+ runt `claude -p`-anropet och skriver `matning.json`, och den kör
847
+ `archive.mjs proveniens` mot körningskatalogen när processen är klar.
848
+
596
849
  - **En ticket = ett färskt kontextfönster.** Allt tillstånd bor i arkivet på
597
850
  disk; huvudsessionen samlar bara exitstatus och en radssammanfattning per
598
851
  ticket. `/clear` mellan tickets behövs inte — processgränsen är
@@ -602,26 +855,79 @@ claude -p "/request utvärdera <gid> <kandidatmodell>"
602
855
  (steg 1), så MCP-behörigheten för läsning måste täcka headless-körning.
603
856
  - **Kör vidare vid fel.** En ticket vars gid inte går att hämta eller vars
604
857
  process kraschar noteras i sammanfattningen; resten av listan fortsätter.
605
- - **Återupptagbart:** innan ett varv startas kontrolleras arkivet —
606
- skippet styrs av variantens `status` i `experiment.json`: `"klar"` eller
607
- `"stopp"` hoppas över med en notis, `"ofärdig"` körs om från varvets
608
- början. Varven är billiga relativt risken att lappa ihop halva körningar.
609
- Ett svep över många tickets kan därmed fortsätta i en senare session utan
610
- omkörningar.
858
+ - **Återupptagbart:** innan en körning startas kontrolleras arkivet, styrt av
859
+ körningens `status` i `experiment.json`. `"klar"` och `"stopp"` hoppas
860
+ över med en notis. `"ofärdig"` är avbruten data, inget resultat värt att
861
+ skydda: den utlöser aldrig omkörningsfrågan, utan körs om automatiskt som
862
+ en ny `k<N+1>` under samma modell. Den gamla ofärdiga körningen skrivs
863
+ ändå aldrig över, den står kvar som historik över vad som gick fel.
864
+ `"väntar på dom"` OMVÄRDERAS i stället för att hoppas över, det är den
865
+ enda platsen som är aktören för den statusen: kör `archive.mjs sparr` på
866
+ körningskatalogen. Exit 0 betyder att domen är fälld: sätt körningens
867
+ status till `"klar"` och fortsätt där den stannade (rapporten kan köras
868
+ separat när alla körningar för posten är klara). Exit 1 betyder att
869
+ den fortfarande väntar: notera det och gå vidare till nästa ticket.
870
+ `döm` fäller domen men rör aldrig `experiment.json` (se `döm`), det är
871
+ bara genom att `utvärdera` körs igen för samma post som statusen
872
+ uppdateras. Omkörningsfrågan (se `utvärdera` ovan) gäller alltså bara
873
+ `"klar"`-körningar: det är resultat värda att skydda mot ett fingerfel,
874
+ en ofärdig körning har inget att skydda. Körningar är billiga relativt
875
+ risken att lappa ihop halva resultat. Ett svep över många tickets kan
876
+ därmed fortsätta i en senare session utan onödiga omkörningar.
611
877
 
612
878
  ### Sammanställning
613
879
 
614
880
  `utvärdera sammanställ` läser alla `experiments/*/` och skriver
615
- `experiments/sammanstallning.md`: tabell per ticket med klass/poäng per
616
- variant, delnings- och stopputfall, och avvikelsemarkering där varianterna
617
- skiljer sig. Halvfärdiga kataloger märks `ofullständig`, aldrig tyst
881
+ `experiments/sammanstallning.md`: tabell per ticket med en rad per modell som
882
+ bär poäng, delnings- och stopputfall, plus avvikelsemarkering där
883
+ modellerna skiljer sig. Modellens rad tas ur dess GÄLLANDE körning, den högsta
884
+ `k<N>` vars status i `experiment.json` är `"klar"`. En modell utan klar körning
885
+ representeras av sin senaste `k<N>` och märks `ofullständig` tillsammans med
886
+ den körningens status. Halvfärdiga kataloger märks likadant, aldrig tyst
618
887
  utelämnade. Bara läsning — inga agentdispatcher, inga Asana-anrop.
619
888
 
620
- ## Mekaniska kontroller: `scripts/`
621
-
622
- Sju deterministiska script (fem kontroller + `lib.mjs` med de delade
623
- byggstenarna + `ref-hash.mjs` för stabil hashning) ersätter modellkörningar
624
- där kontrollen är ren form —
889
+ ### Rapport
890
+
891
+ `utvärdera rapport [--ut <fil>]` renderar en HTML-rapport över experimentytan
892
+ med `scripts/report.mjs`. Rapporten täcker ALLTID hela ytan; något postfilter
893
+ finns inte, menyn i rapporten är där läsaren väljer post. Utan `--ut` skrivs
894
+ HTML på stdout, annars till filen. Publicera den som artefakt när den ska
895
+ läsas.
896
+
897
+ **Rapporten skrivs ALDRIG automatiskt.** Ingen körning genererar den när den
898
+ blir klar. Den kostar nästan ingenting att regenerera, så det finns ingen
899
+ anledning att skriva den på spekulation, och en fil som ingen bett om är en fil
900
+ ingen litar på.
901
+
902
+ Rapporten är ren läsning: inga agentdispatcher, inga Asana-anrop, inga
903
+ skrivningar i arkivet utöver utdatafilen.
904
+
905
+ Vad den visar: en meny över poster med ticketens titel, dess katalogslug och
906
+ vilka modeller posten har, och per vald post en kolumn per körning. Varje delpost ur
907
+ ett DELA_UPP-utfall är en egen kolumn efter sin körning (`opus / k1 / del-1`),
908
+ eftersom det är där utfallen bor när en post delat sig. Sektionerna är fältvisa,
909
+ samma fält på samma rad tvärs kolumnerna: utfall, poängens inringning med
910
+ golv, tak, steg och drivers,
911
+ specens fyra fält, samt `impact.md` och `granskarblock.md` hopfällda per
912
+ körning. Äldre körningar med klassningsfiler (före ADR-0098) får dessutom
913
+ sin Klassning-sektion renderad som förut — kalibreringshistoriken kastas inte.
914
+ Sist står kostnaden (USD, tokens, väggtid, dispatcher) och proveniensen.
915
+ En delkolumn saknar egen mätning och säger `ingår i k<N>`, aldrig omätt.
916
+ Matrisen är ojämn med flit: en post kan ha två modeller och en annan tre,
917
+ eftersom en dyrare modell läggs till bara där de billigare inte räckte.
918
+
919
+ Vad den ALDRIG gör: rangordnar modeller, rekommenderar en nivå, räknar aggregat
920
+ tvärs poster med olika modelluppsättning, eller uttalar sig om vilket utfall
921
+ som var korrekt. Bedömningen av vad som är ett acceptabelt utfall är
922
+ människans, gjord på erfarenhet av systemet. Rapporten visar spridningen.
923
+
924
+ ## Mekaniska script: `scripts/`
925
+
926
+ Nio deterministiska script bor i katalogen: de fem kontrollerna nedan,
927
+ `archive.mjs` som äger arkivets kataloger och spärrar, `report.mjs` som
928
+ renderar modellrapporten (se `utvärdera rapport`), `lib.mjs` med de delade
929
+ byggstenarna och `ref-hash.mjs` för stabil hashning. Kontrollerna ersätter
930
+ modellkörningar där kontrollen är ren form,
625
931
  billigare, snabbare och utan omdömesglidning. Varje script bär sha256 för de
626
932
  referensfiler vars regler det speglar och VARNAR när en katalogbump ändrat dem
627
933
  (kontraktsdrift ska upptäckas av en check, inte av en kund):
@@ -630,39 +936,39 @@ referensfiler vars regler det speglar och VARNAR när en katalogbump ändrat dem
630
936
  dispatcher: rubriker, exakt ett specblock, 2–5 punkter, förbjuden vokabulär,
631
937
  granskarblocksrader, state.json-fält. Skiljer på BRISTER (exit 1, stoppar)
632
938
  och VARNING (heuristik — visas, stoppar inte).
939
+ - `scripts/resolve-anchors.mjs <run.json> <spec.md> [impact.md]` — löser
940
+ beläggsankare (`belagg_ankare`/`ankare`) till ordagranna källblock, körs
941
+ FÖRE contract-check. Exit 0 = allt löst (eller inga ankare i filen), 1 =
942
+ minst ett OLÖST/FLERTYDIG ankare (kontraktsbrott, mekanisk omdispatch),
943
+ 2 = användningsfel.
633
944
  - `scripts/contract-check.mjs <run.json> <spec.md> [impact.md] [--expect-id <id>]`
634
- — kontraktskontroll av classify/score-JSON EFTER körning: enums,
945
+ — kontraktskontroll av score-JSON EFTER körning: enums,
635
946
  konfidensintervall, poängupplösning, inringningens närvaro (även per
636
947
  alternativ; under-A1-fallet med floor null och tak A1 är giltigt), belägg/
637
948
  driver-citat som ordagranna substrängar av underlaget, protokollterm-
638
949
  svartlista i kundtextfält, sluten kuvertnyckellista, request_id mot katalogen.
639
- INPUT_SAKNAS kräver saknas-lista i stället för frågerader.
640
- - `scripts/compare-classifications.mjs <a.json> <b.json>` — deterministisk
641
- dubbelkörningsdiff: utfall, basklass, varje frågas svar och konfidensens sida
642
- om 0.8-gränsen. Skriver `LIKA` eller `OLIKA` + diffrader, exit 0/1; exit 2 =
643
- ojämförbara körningar (dispatcherfel, aldrig LIKA).
644
- - `scripts/compare-scores.mjs <a.json> <b.json>` — samma för poäng: outcome,
950
+ INPUT_SAKNAS kräver saknas-lista i stället för frågerader. Ett olöst ankare
951
+ (belägg saknas trots `belagg_ankare`, eller `ankare` utan `citat`) är
952
+ dispatcherns fel, inte agentens: exit 2 med hänvisning till resolve-anchors.mjs.
953
+ - `scripts/check-lasta.mjs "<LÄSTA-innehåll>" <spec.md> <impact.md>` —
954
+ kontrollerar scorerns läs-scope: LÄSTA-raden ska bära underlagens två
955
+ sökvägar och får därutöver bara bära filer under skillens egen katalog.
956
+ Exit 0 = ok, 1 = kontraktsbrott (BROTT-rader), 2 = användningsfel.
957
+ - `scripts/compare-scores.mjs <a.json> <b.json>` — deterministisk
958
+ dubbelkörningsdiff: outcome,
645
959
  score, confidence, golv- och takankare. Aldrig prosa. Skriver `LIKA`,
646
- `LIKA_TOLERANS` (poängskillnad ≤ 0,5 med samma outcome och confidence, och
647
- ankarband som överlappar eller angränsar; exit 0, verdiktraden pekar ut
648
- körningen med högst poäng) eller `OLIKA` + diffrader; i övrigt samma
649
- exit-semantik. Båda compare-scripten kräver mode `pricing`; guard-jämförelser
650
- är en medveten utbyggnad i guard-steget.
651
- - `scripts/quote-repair.mjs <run.json> <spec.md> [impact.md]`: deterministisk
652
- citaträttning som körs FÖRE omdispatch när contract-check fällt ett citat: ett
653
- nästan-ordagrant belägg (eller citattecken-omgärdat driver-segment) ersätts med
654
- sin entydigt närmaste källmening, allt annat lämnas orört. Rättar aldrig över
655
- en polaritetsskillnad (negationsord) och skriver allt eller inget, så en
656
- halvrättad fil aldrig arkiveras. Exit 0 = inga orättbara citat kvar (rättade
657
- eller inga), 1 = orättbara kvar och filen orörd (omdispatch), 2 =
658
- användningsfel eller oläsbar input (dispatcherfel).
960
+ `LIKA_TOLERANS` (poängskillnad ≤ 0,5 med samma outcome, oavsett confidence,
961
+ och ankarband som överlappar eller angränsar; exit 0, verdiktraden pekar ut
962
+ körningen med högst poäng) eller `OLIKA` + diffrader; exit 0/1, exit 2 =
963
+ ojämförbara körningar (dispatcherfel, aldrig LIKA). Scriptet kräver mode
964
+ `pricing`; guard-jämförelser är en medveten utbyggnad i guard-steget.
659
965
 
660
966
  Kontrollerna bedömer aldrig innehåll och returnerar aldrig protokollutfall —
661
967
  en post som passerar kan fortfarande stoppas av protokollen själva, och det är
662
968
  deras jobb. Vid script-fel (exit 2 eller krasch): visa felet och stanna, kör
663
969
  aldrig vidare som om kontrollen passerat.
664
970
 
665
- ## Dispatch-kontrakt (gäller alla fyra agenterna)
971
+ ## Dispatch-kontrakt (gäller alla tre agenterna)
666
972
 
667
973
  - Prompten är självbärande: agenten ser inte den här konversationen.
668
974
  - **Promptmallar, etiketterna ordagrant:**
@@ -692,31 +998,32 @@ aldrig vidare som om kontrollen passerat.
692
998
  <granskarblock.md bytetroget>
693
999
  ```
694
1000
 
695
- `request-classifier` / `request-scorer`:
1001
+ `request-scorer` (underlag per sökväg, ADR-0099 — aldrig inklistrat):
696
1002
 
697
1003
  ```
698
1004
  REQUEST_ID: <gid eller slug>
699
1005
  MODE: <pricing|guard>
700
1006
  DELPOST: <nej | ja, del N av M>
701
1007
 
702
- SPEC:
703
- <spec.md bytetroget>
704
-
705
- PÅVERKANSANALYS:
706
- <impact.md bytetroget>
1008
+ SPEC: <absolut sökväg till spec.md>
1009
+ PÅVERKANSANALYS: <absolut sökväg till impact.md>
707
1010
  ```
708
1011
 
709
- (guard-läge lägger till `FULLPLAN:` och `TIDIGARE_KLASSNING:` /
710
- `TIDIGARE_POANG:` — guard-kommandot kommer i ett senare steg.)
1012
+ (guard-läge lägger till `FULLPLAN:` och `TIDIGARE_POANG:` —
1013
+ guard-kommandot kommer i ett senare steg.)
711
1014
 
712
1015
  - **Svansrader efter huvudinnehållet**, i denna ordning: `MODELL: <modell-id>`
713
1016
  (alla agenter), `LÄSTA: <kommaseparerade absoluta sökvägar eller "inga">`
714
- (endast classifier/scorer — deras Read är promptbegränsad, raden gör regeln
1017
+ (endast scorern — dess Read är promptbegränsad, raden gör regeln
715
1018
  granskbar), `AVVIKELSE: <text>` (endast om något i prompten bröt mot agentens
716
1019
  regler, t.ex. en prislista i underlaget). Svansraderna strippas före varje
717
1020
  maskinell kontroll och före arkivering; MODELL antecknas i runs-raden,
718
- LÄSTA verifieras ligga under agentens tillåtna katalog, AVVIKELSE visas
719
- alltid för användaren.
1021
+ AVVIKELSE visas alltid för användaren. LÄSTA kontrolleras MEKANISKT av
1022
+ `scripts/check-lasta.mjs` (ADR-0099): raden ska bära underlagens två
1023
+ utpekade sökvägar (båda obligatoriska) och får därutöver bara bära filer
1024
+ under skillens egen katalog (referensfilen) — allt annat är ett
1025
+ kontraktsbrott och behandlas som BROTT i bedöm steg 5 (omdispatch EN
1026
+ gång, sedan stopp), aldrig bara en notis.
720
1027
  - Agentens svar i övrigt är rådata enligt skillens kontrakt (prosa-dokument
721
1028
  eller JSON), ingen kommentar runt om.
722
1029
  - **Omdispatch (max EN per agent och varv):** skicka HELA ursprungsprompten
@@ -726,6 +1033,11 @@ aldrig vidare som om kontrollen passerat.
726
1033
  <felraderna från kontrollen, citerade ordagrant>
727
1034
  ```
728
1035
  En ny subagent minns inget — enbart felrader utan underlag är obrukbart.
1036
+ **Omtaget bokförs alltid (ADR-0099):** det förkastade försöket arkiveras
1037
+ med `-avvisad`-suffix (prissättning: `<typ>-pricing-vN-avvisad.json`;
1038
+ textsteg: `spec-avvisad-<datum>.md` / `impact-avvisad-<datum>.md`) och får
1039
+ en egen runs-rad med kontrollens felrader — två körningar av samma steg
1040
+ utan spår av varför är precis den lucka kvittot stänger.
729
1041
 
730
1042
  ## Använd inte när
731
1043
 
@@ -734,5 +1046,5 @@ aldrig vidare som om kontrollen passerat.
734
1046
  - Frågan gäller Asana-uppsättning ("koppla repot") — det är request-sync:s
735
1047
  uppsättningsflöde, kör den direkt.
736
1048
  - Guard-läget ("kör guarden", före första kodrad) — körs tills vidare via
737
- request-classify/request-score direkt; ett `guard`-kommando kommer i ett
1049
+ request-score direkt; ett `guard`-kommando kommer i ett
738
1050
  senare steg.