Commit graph

14 commits

Author SHA1 Message Date
28a420ab97 feat(3): flaten sier sant om seg selv, og to gater måler at den fortsetter å gjøre det
Fase 3 (AAA+ på publisert flate). Tre av planens premisser falt på måling og er
rettet FØR handling, ikke etterpå:

* GOVERNANCE-raden hadde feil tiltak. Planen sa «skriv den»; org-ops D11 sier én
  kanonisk fil som hvert repo LENKER, og filen er nå publisert (målt: HTTP 200 på
  open/repo-standard). Å skrive vår egen ville gjort oss til kopi nr. 12 av en
  fil D11-bølgen holder på å rydde vekk. README lenker den, i samme form som
  repo-mailbox bruker, og bus-faktor 1 står uttalt i den kanoniske teksten.
* Release-objektet for v1.0.0 FINNES allerede på open/ (id 155, CHANGELOG-kropp,
  siden rendrer) — det som mangler er vedlegg, ikke objektet.
* WARN RELEASE-STALE fyrer ikke, og kan ikke: regelen sammenligner utgivelse mot
  tagg og er strukturelt blind for repo med null utgivelser (org-ops hovedbok
  #18). Gaten var OK/20 sjekker FØR arbeidet startet, så den kan ikke tjene som
  verifikasjon for denne fasen. Bevisene er Forgejo-APIet, filinnholdet og
  ren-klon-kjøringen.

A5-defekten rettet: env.template:21 sa at credential resolves via
DefaultAzureCredential. Den har aldri gjort det — backends.py:149 konstruerer
ManagedIdentityCredential eller AzureCliCredential, og Learns MAF-veiledning
navngir den spesifikke credentialen NETTOPP for å unngå probing. En operatør som
kopierte templaten ble fortalt at feil identitet ville bli brukt.

To load-bearing gater (Iron Law: begge røde før fiksen, 2 failed / 7 passed):

1. env.template navngir de credentials backends.py faktisk konstruerer, og ingen
   linje utgir DefaultAzureCredential for å være mekanismen. LINJEFORANKRET, ikke
   delstreng: backends.py NAVNGIR klassen fire ganger i kommentarene som
   begrunner hvorfor den ikke brukes, så en fil-bred substring-gate ville vært
   rød på nøyaktig den prosaen den beskytter (repoets 08-09-klasse, fjerde gang).
2. README-ens wheel-filnavn bærer versjonen bygget stempler på fila. Uten den
   ville en versjonsbump stille etterlatt en publisert install-kommando som peker
   på en fil som ikke finnes.

Hver positiv assert er paret med en KONTROLL på at det søkes etter noe som
finnes — en ekstraktor som stille finner null lager en gate som bare kan bli
grønn.

MUTASJONER MÅLT MOT HELE SUITEN, begge røde på riktig test og på INGEN annen:
gjeninnfør den usanne credential-påstanden (2 røde, 844 grønne) · la
wheel-filnavnet drifte til 1.0.0 (1 rød, 845 grønne). Restaurert fra scratchpad
+ shasum -c mellom hver. Bumpen selv var den andre mutasjonen: pyproject 1.0.0 →
1.1.0 gjorde README-gaten rød alene, før README ble rettet.

SECURITY.md: varslingsfrist (minst én minor-release og aldri under 30 dager
mellom kunngjøring og fjerning, med sikkerhetskritisk fjerning som uttalt
unntak). Støttetabellen er bevisst VERSJONSFRI — et release-nummer skrevet der
ville drevet ved neste tagg, altså samme defektklasse som gate 2 fanger.

CLAUDE.md beholdt på flaten med en engelsk innramming øverst (operatørvalg): den
sier hva fila er for en fremmed. Innholdet er repoets sterkeste bevis på at hver
beslutning er målt; å fjerne det ville fjernet bevis, ikke friksjon.

Versjon 1.1.0 — synket i pyproject, __init__, test_smoke og README-kommandoen.
1.0.0-treet kan ikke produsere en kjørbar wheel (force-include kom etter taggen,
målt: git show v1.0.0:pyproject.toml har den ikke), så en wheel hengt på den
utgivelsen ville vært nøyaktig den usanne påstanden denne fasen finnes for å
fjerne. Operatøren valgte bumpen framfor et vedlegg som ikke virker.

846 passed / 4 skipped (fra 837). ruff + format + mypy rene.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ckyg3Pc6k7FRuR6fDGQLJ
2026-08-14 06:57:25 +02:00
d71a4e7b4e docs: stempler v1.0.0 — [Unreleased] blir [1.0.0] - 2026-08-12
Datoen er LEST med `git log -1 --format=%cs` på Y, ikke skrevet på forhånd og
ikke tatt fra veggklokka. Re-leses på denne commiten før taggen settes (runbookens
§5 punkt 8): faller midnatt mellom Y og Z, står gårsdagens dato i commiten som
faktisk tagges. Denne commiten er Z.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWeYxduEnFQeynXbrtEA6o
2026-08-12 20:16:54 +02:00
c4b0e08cc5 docs(plan): tirsdagen lukket i PLANEN — den instruerte om arbeid som var gjort
Planen er dokumentet operatøren FØLGER onsdag under tidspress, og etter
persona-pullen instruerte tir-11-raden fortsatt om en betinget subtree pull med
abortsti og 18:00-frist — arbeid som er utført og pushet. Samme drift-klasse økt
4 felte, så samme mottiltak: én grep-pass FØR redigering
(`persona|kontorbygg|tilsvarende anlegg|I4|18:00` over `docs/plan/` +
CHANGELOG), amendering med attribusjon (§6-mønsteret), aldri omskriving.

Grep-passen fant FIRE steder, ikke ett — som er hele grunnen til å kjøre den:
- tir-11-raden: betinget pull-instruks → **TOM, gå rett på onsdag**, med
  utfallet og de fire målingene som lukket den
- frys-blokkas X-note: «lander tirsdagens persona-pull, flytter X seg» →
  pullen ER landet (`d0e8bb0`); X leses fortsatt av `git rev-parse HEAD` etter
  grønn prøve, aldri skrevet ned her
- P4 pkt. 1s fersk-klon-måling: sto på `c9787cf`, altså to commits bak etter
  pullen. HOLDBARHETEN sagt eksplisitt i stedet for underforstått — delta er
  prosa i `shared/` + regenerert fasit, `pyproject.toml`/`uv.lock` MÅLT urørt,
  så målingen står; onsdagens generalprøve ×2 er bekreftelsen
- P3s I4-abortsti (i `<details>`): stemplet HISTORISK, med den ene målingen
  verdt å bære videre — den harde reset-formen blokkeres av hooken, `--keep`
  slipper igjennom

CHANGELOG: én Changed-linje for persona-formuleringen, slik at onsdagens
`[Unreleased]` → `[1.0.0]`-stempel ikke beskriver en artefakt-tekst som har
endret seg siden. Beslutningen tas her, ikke på en enveis-dag.

Tabell-integritet verifisert (pipe-telling; ons-12-radens seks er tre escaped
`\|` i grep-kommandoen, urørt). `test_doc_constant_sync_loadbearing` grønn.
Kalenderen: man 10. er nå SEKS økter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017og6HMcP1WQcABRDogUMfx
2026-08-10 20:56:19 +02:00
a41272def5 chore(release): 1.0.0 version sync + the six undocumented feat commits, tag deliberately withheld
Version 1.0.0 across the four sites that carry it — pyproject.toml, __init__.py,
uv.lock, test_smoke.py. Measured that these are the only four: README carries no
version badge, and CHANGELOG's `## [0.1.0]` is history rather than a bump site.

The heading stays `[Unreleased]`. STATE authorises the CHANGELOG CONTENT now and
holds the TAG until after Wednesday's freeze, so stamping `## [1.0.0] - <date>`
today would be a future-dated claim about an event that has not happened — and
one to rewrite if the dress rehearsal fails or the freeze slips. `pyproject` at
1.0.0 with `[Unreleased]` populated is the release-prep state, not an
inconsistency; nothing machine-reads the CHANGELOG (measured). The global
versjonssync rule is read as CONTENT, not heading. Tag day is then one atomic
move: rename the heading, stamp the date, tag.

The re-lock was the hazard, and it was gated rather than assumed. Bumping the
version stales `uv.lock`, and the next `uv run` would have re-locked it
invisibly against a RANGE dependency (`agent-framework-core>=1.9.0,<2`) — while
the two ExperimentalWarning lines are pinned byte-for-byte in the stderr golden,
and STATE's own okf note records that a bare sync is enough for a guard to stop
guarding with no local diff. So: bump, then `uv lock` EXPLICITLY, then diff
before any test ran. The diff is the single `portfolio-optimiser` version line;
agent-framework-core, llm-ingestion-okf (v0.3.2) and llm-ingestion-guard
(v0.3.4) are untouched, and uv.lock was re-checked AFTER the suite to confirm no
silent re-lock.

CHANGELOG prose for the six feat commits `[Unreleased]` did not cover — it
carried only Step 5 and the scripted registry. Console entry points and the
golden transcript are Added; the Step-7 inbox, the anchored walkthrough, the
stderr damping and the derived provenance sentence are Changed, scoped as the
OFFLINE SIMULATION rather than framework runtime, since they change what the
walkthrough exercises and not the library's behaviour. The content gate is
Security, and carries its opt-in qualifier: `materialize` stays ungated by
design and `materialize_gated` is asked for by name — an entry claiming "ingest
now scans content before writing" without that clause would overclaim, and it
sits next to the sentence read on stage Thursday. A Notes line names the two
open boundaries (ingest stamp spec divergence, D7 mirroring) so 1.0.0 reads as a
stable surface rather than a finished programme.

Measured, not asserted: 810 passed / 4 skipped unchanged · ruff + mypy clean (31
source files) · no `0.1.0` remaining outside .venv/shared · and the demo RUN, not
just tested — stdout byte-identical to tests/golden/demo-transcript.stdout, exit
0, 61 stdout / 4 stderr lines, matching dress rehearsal nr. 0. The version string
appears nowhere in either golden (0 hits), so the bump could not move the fasit.

Two STATE premises corrected by measurement: 24 commits since v0.1.0, not 23;
and eight feat commits exist since the tag, of which six were undocumented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ue1AnPZYsC9Tk7e5Tyv8Fv
2026-08-10 04:46:39 +02:00
688ee24973 feat(sim): the demo script is keyed on the project the prompt names, so a new project is data
The scripted proposer answered one hard-coded pair of proposals. A second project meant a second
hand-written selector, written under demo-week time pressure -- the risk the week plan names
explicitly (§4, risk 2). It is now a registry: `ScriptedCandidate` entries selected by
`scripted_proposer`, plus `project_id` as an argument to `simulate_learning_loop`.

The open decision was WHAT identifies the candidate in the prompt blob; the plan flagged it as
unverified, so it was measured. Two prompt shapes reach the selector: the debate prompt carries the
whole bundle context, the generation prompt carries `Project: {id} - {name}` plus -- as its context
-- the debate output, which is the selector's own earlier reply. So the cost code and the measure
name are present in the generation prompt only because the script put them there; keying on them
would key the script on its own output. The project id is the one identifier both shapes carry and
the framework stamps.

Validation, never repair: no match, or more than one, raises `ScriptedCandidateError`. A default
reply would answer an unregistered project with another project's numbers, which on screen is
indistinguishable from a correct run; an ambiguous blob is a data problem that must surface at the
rehearsal rather than be decided by registry order.

Load-bearing MEASURED against the whole suite, five mutations all red plus a green control: detach
the project keying - one global flip key - fall back on an unknown project - first-match on an
ambiguous prompt - detach the `project_id` argument. The flip-key test was rewritten mid-measurement
because its first form asserted on the FIRST registry entry, where "the matched candidate's key" and
"candidates[0]'s key" coincide -- it could not separate the two implementations, and proved nothing.

766 passed / 4 skipped. Simulation still exits 0, still prints eight labelled steps, still
byte-identical across two runs.

[skip-docs] README is deliberately untouched: O4 defers the README rewrite to 14-15 August, after
the demo has produced the evidence for the level-2 claim. CLAUDE.md carries the invariant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XoHJCKBTjFKcjsfEQyGbzh
2026-08-06 16:43:29 +02:00
d6f3359fae feat(step5): the falsification that informed the next hypothesis now leaves the loop
generate_via_llm consumed each validator Rejection internally (`last`), fed it into the
next attempt's prompt, and dropped it. So Step 5 was real but unobservable: a caller could
see THAT a proposal validated, never that it validated on attempt 2 after the deterministic
validator falsified attempt 1. It was the one step of the eight with no output to show.

The seam is a typed return value -- GenerationResult(outcome, refinements) -- rather than an
out-parameter or a callback: a returned value cannot be silently lost by a caller that forgets
to pass a collector, and mypy forces every call site to acknowledge it.

refinements carries ONLY rejections that were actually fed back. When the attempt budget runs
out the final rejection IS outcome; counting it here would be double-counting, and the bounded
control test goes red on the collect-everything implementation that gets this wrong.

The loop's bound is untouched: max_attempts and meter.tick_round stand, and `last` still drives
the prompt alone, so prompt growth is unchanged. run.py accumulates across _evaluate calls, so
_evaluate_mandate is untouched; RunResult.refinements defaults (the coverage precedent) and is
concatenated across approaches rather than keyed per approach -- stated as an honesty limit.

The simulation now shows it: the scripted proposer overclaims 250000, which the validator
falsifies against P90 = 90000, and the corrected 30000 validates. Only the overclaim is
scripted -- the rejection is computed. scripted_factory takes a per-role reply selector so this
needs no second scripted client body.

README records the two accuracy changes only (Step 5 is now inspectable; the simulation trace
shows the correction). The level-2 publishing claim stays deferred until after the demo (O4).

Load-bearing MEASURED against the full suite with a control, four mutations all red:
detach the returned history (4 tests) - collect-everything (control only) - detach the run
wiring (2 tests) - revert the simulation's proposer to a constant (the demo-protection test).
Control: 759 passed / 4 skipped; ruff, format and mypy clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017CcWFcREUi6YPjEpN3ACDP
2026-08-06 15:12:06 +02:00
520e74128e docs(release): describe what v0.1.0 actually is, not what it was 53 commits ago
STATE said the release text was already written and only needed dating. Measured:
CHANGELOG.md was last touched at 9e149c6, 53 commits back, so [Unreleased]
described the repo as of S3.1 — and claimed 512 passing tests where the suite
measures 755.

For a FIRST tag there is no predecessor, so the section is not "what changed" but
"what this version is". A description that stops at S3.1 does not under-report a
delta; it misrepresents the artefact being tagged, on a public mirror.

Audited the existing bullets for claims that had gone FALSE rather than merely
stale — the class a test-count catch is only a sample of. Four checked, all still
true at HEAD: numpy confined to semretrieval.py; value_report deliberately not
wired into costsim; the simulation module and knowledge-base recipe present; the
two run modes still two.

Added, grouped by seam rather than by commit: S4.0 cost-baseline anchoring, S2.7,
S3.2 per-candidate verdict keying, S3.3 wave concurrency, S3.4 global token cap,
S2.2/S2.4 ingest transports, --scripted-replies, --mandate, --mcp-config, the
per-approach outbox, and external-call provenance. New Fixed section for the
seven correctness fixes, with a lead-in saying plainly that none of them ever
shipped. Notes gained the deployer-owns-DPIA scope boundary and the pull-only
subtree rule.

The test-suite bullet now records TWO cases where "every seam is load-bearing"
did not hold until measured, not one: the S3.1 CLI-level gap, and four of five
BudgetExceeded raise sites free to report any `observed`.

No code change. Suite measured green at 755 passed / 4 skipped after the edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVekyKcvT4ah6jnCT8R8fe
2026-08-06 09:15:36 +02:00
9e149c6847 docs(s31): close the review's honesty gap — narrow semantic claims to the shipped mechanism 2026-07-25 13:00:13 +02:00
921a8daf71 docs(s31): --semantic-retrieval CLI surface + Embedder/Retriever extension points 2026-07-25 06:31:44 +02:00
0343b42d88 docs(s54): --report CLI surface + truthful costsim kost_mot_verdi seam note 2026-07-24 01:38:10 +02:00
c0d3ba4459 docs(s53): README two-mode CLI matrix + honesty-scoped learning-loop claims + CHANGELOG catch-up
README: the stale one-line CLI mention replaced by the two-mode flag matrix (single-project vs
--portfolio), runnable 'uv run python -m portfolio_optimiser.run ...' examples, the --outbox-dir
!= --verdict-dir self-contamination warning (documented, not enforced), and the --decision/
--rationale inert-in-portfolio note. Honesty scoping: the prior-verdict fold (the learning step)
is stated to happen ONLY on the --bundle-dir path; a --docs-dir-only run is single-shot (no fold).
CHANGELOG [Unreleased]/Added: S5.3 CLI-parity entry (six flags + portfolio mode + load_dimension +
recipe doc) plus catch-up for the shipped-but-undocumented S4.1 (preflight), S4.2 (--live-dry-run),
S5.1 (hitl CLI), S5.2 (notify); stale test count 237 -> 431. extending.md verified accurate (B11
notifier note stands verbatim — main() auto-wires no notifier; no CLI section to sync), left
unchanged.

SC4 honesty grep clean (each hit in bundle-path context, none on a fold-less path):
  grep -rniE 'learning loop|learns from|self-improv' README.md docs/extending.md CHANGELOG.md
  README:11 (system-level) :56 (wiki substrate) :67 (8-step bundle loop);
  CHANGELOG:13 (gated ExpeL fold) :17 (offline simulation). Full suite 431 passed (no code touched).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNNiJRk1sSwxgVLS5AobT1
2026-07-23 21:51:00 +02:00
254e3da1d8 chore(release): MIT license + CONTRIBUTING/SECURITY/CODE_OF_CONDUCT + README badges (S12) 2026-07-05 08:10:09 +02:00
ae01127510 docs(truth): S1 truth maintenance — CHANGELOG, stack line, MCP claim, conflict semantics, 90% cut-list
Findings 4-7 from the 2026-07-02 status analysis, per the session plan (S1):
- CHANGELOG rewritten truthfully (was: 'Plan phase - no framework code yet')
- README stack line names the split GA packages, not the agent-framework meta-package
- CLAUDE.md: MCP downgraded to extension point (in-process FunctionTool is the default seam)
- Verdict conflict semantics documented as chosen (store first-write-wins per id,
  disk/wiki last-write-wins per file; full B10 taxonomy deliberately deferred)
- docs/extending.md: explicit 90%-principle cut-list (B10, B11, U12, U14, concurrent fan-out)
- .gitignore covers .trekexecute-progress-* (docs/.DS_Store was already untracked/ignored -
  the plan's git rm --cached assumption was stale; no-op)

No code behavior changed (docstring only in verdicts.py). Suite 152/4 green, mypy clean,
ruff format --check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaQCFnfsh3tfq1VfzdJpoi
2026-07-03 00:34:56 +02:00
ec9ac74976 feat: initial scaffold (Python framework on Microsoft Agent Framework)
Plan-fase: repo-skjelett, dokumentasjon (research + inkrementell plan),
Python/uv-oppsett, MAF-avhengighet. Ingen rammeverkskode ennå.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H9FyyENxebxVThjrn9et8C
2026-06-23 22:01:22 +02:00