Commit graph

3 commits

Author SHA1 Message Date
30bcdd3544 docs(mandate): how a domain expert commissions a run — and one honesty fix the run itself exposed
`docs/bestille-en-kjoring.md` is the commissioning half of the expert-facing pair
(`ekspert-svar.md` is the judging half): the mandate file field by field, how to
run it, and — separated deliberately — what a commission does NOT do. It directs
what is evaluated, never what is approved.

Registered in _LIVE_DOCS, so it cannot silently fall behind the code.

The example output in it is COPIED FROM A REAL RUN, not composed, and running
that run is what found the defect fixed here: three approaches against the same
cost line each validated at 30000 NOK, and the settlement printed
"Validated total: 90000 NOK". Commissioned approaches are ALTERNATIVES — they
usually attack the same line — so summing them reports money the project cannot
realise. A domain expert reading that total would reasonably believe the run
found 90k.

The settlement now reports how many approaches held and which one the run
carries: a selection, not an arithmetic claim. That also removes the last money
addition from this module, which is the right place for it not to be.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ULCqjLF61rehj5cZmdUoR3
2026-08-05 16:31:27 +02:00
51739455ae docs(hitl): paste-ready expert answers, and the HITL chain walked end to end
The operator is not a domain expert, so the domain content is mine to own --
and the one thing the loop asks a human for is exactly the thing no example
existed for. docs/ekspert-svar.md is written for whoever has to deliver the
verdict: the two forms a judgement can take (a --rationale string during the
run, a JSON file in the inbox for later runs), where each field comes from, and
four complete paste-ready answers.

Every command and every verdict in it was RUN from a fresh clone before it was
written. The `hitl pending` line quoted is verbatim output. The rejection
answers close the gap STATE has carried since the demo shipped: the README
shows the VALIDATOR refusing a number, but nothing showed an EXPERT refusing a
proposal whose numbers are fine -- the only judgement in the whole loop that a
machine cannot make. Two rejection shapes are given, because "not feasible
here" and "right measure, wrong cost base" teach the system different things.

Everything is marked AI-authored and not verified professional judgement.

Also corrects the --outbox-dir help text, which claimed sharing a folder with
--verdict-dir "re-ingests raw agent output past the Step-8 promotion gate".
Measured, by pointing both at one folder and running twice: it does not. The
outbox artefacts are named {run_id}-*.json and carry none of the verdict keys,
so the tolerant inbox loader skips them and the run is unaffected. The hazard is
real but latent -- a future verdict-shaped artefact in the outbox -- so the
warning stays and says what is actually true. This also answers STATE's open
question about enforcing the distinction in the CLI: no. There is no reachable
contamination to refuse, and a guard for an unreachable case is the kind of
error handling this repo declines to write.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118noV9rCfrdREH26XqZB5z
2026-08-05 10:58:43 +02:00
1515a474d6 test(docs): gate constants cited in live docs against the code (kø-(h))
docs/extending.md claimed SEMANTIC_WEIGHT_DEFAULT = 0.5 long after the code
lowered it to 0.25. It was found by accident while editing the neighbouring
line; nothing in the suite would ever have caught it. This is that gate.

Both bounds were MEASURED, not assumed:

- SCREAMING_CASE discriminates exactly. Across every numeric `name = value`
  code span in docs/ it selects the 2 real module constants and rejects all
  10 kwargs/locals (max_attempts=3, concurrency=3, realiseringsgrad=0.79).
  Ordinary prose stays freely editable, so the gate has no reason to be
  switched off.
- Dated documents are observations, not contract. A spike finding or a July
  review records what was true when measured; rewriting it to track the code
  would falsify the record.

Measuring also rewrote the ambiguity rule: SEMANTIC_WEIGHT_DEFAULT is bound
in both semretrieval and run (a re-export), so a "same name in two modules"
check would have been RED on today's code. Only DIVERGENT values are refused.

Fail-closed throughout, per write_concept_file / read_spend: an unknown
constant name is an error rather than a skip, and a document that is neither
listed live nor recognisably archived goes RED asking to be classified —
otherwise a new guide would be silently unguarded.

Load-bearing MEASURED against the whole 638-test suite:
- drift the DOC (the original defect) -> only this gate goes red; the other
  637 stay green, so it covers ground nothing else did
- drift the CODE -> this gate and the semretrieval weight gate both go red
- make an unknown name tolerant -> red
- drop the only citing doc from the live list -> red (twice: coverage and
  classification)
- add a new unclassified guide -> red
- (control) remove this gate entirely, code still drifted -> the adjacent
  semretrieval gate still goes red, so nothing is masked in either direction

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D9AAyWtMqr4HjftKaegTtS
2026-08-03 22:22:43 +02:00