Squashed 'shared/' changes from 35220f7..aa9eaa9

aa9eaa9 docs(plan): V1-etterspill — §12 mangler rader for `by`/`at`, presedens målt begge veier
54e0ec7 spec(ingest): V1 — `generated` til O2-formen, ratifisert 2026-08-02
ddaae5d chore(release): publiseringsklar for open/ — README for standalone rot + MIT + policy-filer
f98b287 docs(plan): V1 RATIFISERT — og :275 er en andre tabellrad, ikke prosa
d6bced7 docs(plan): SS11 ankrer ikke SS8 — funnet var reelt, men ikke raden som ble bestilt
3174475 docs(plan): §7.2 — feilanker-failuremoden var ikke hypotetisk, den inntraff
a2b57d2 docs(plan): V1 — «de 5 linjene» var ikke homogene; :214 er ikke en literal
d63e45d docs(plan): okf-versjonssjekken utført — hypotesen falsifisert på to stale premisser
ef31dda docs(plan): V1 §4.2 — pin + id + sitering avgjort, og ratifiseringsgaten funnet

git-subtree-dir: shared
git-subtree-split: aa9eaa9df06463a8cf00bd28fd133b1f20d7b888
This commit is contained in:
Kjell Tore Guttormsen 2026-08-09 10:15:28 +02:00
commit 89e3ad8efe
11 changed files with 773 additions and 56 deletions

59
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,59 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment:
* Demonstrating empathy and kindness
* Being respectful of differing opinions and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing for mistakes
* Focusing on what is best for the community
Examples of unacceptable behavior:
* Trolling, insulting or derogatory comments
* Public or private harassment
* Publishing others' private information without permission
* Other conduct which could reasonably be considered inappropriate
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hello@fromaitochitta.com.
All complaints will be reviewed and investigated promptly and fairly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html

66
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,66 @@
# Contributing to portfolio-optimiser-commons
Thank you for your interest. Please read this first — the workflow here is deliberately
narrower than most repositories, and knowing that up front saves you wasted effort.
## Code of Conduct
Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
## Pull requests are not accepted
The pull-request tab is **switched off** on this forge, across every repository in the
organisation. That is a published position, not an oversight: this project is solo-maintained,
and an enabled-but-permanently-empty PR queue would promise a review capacity that does not
exist.
Use **issues** instead. A well-argued issue carries the same information as a patch and costs
you less to write.
## What belongs here, and what does not
This repository is the framework-neutral core. Before opening an issue, check which side of the
boundary your point falls on:
| Your point is about | Raise it in |
|---|---|
| The normative specs, the example bundles, the golden fixtures | **here** |
| Behaviour of the MAF implementation | [`portfolio-optimiser`](https://git.fromaitochitta.com/open/portfolio-optimiser) |
| Behaviour of the Claude Agent SDK implementation | [`portfolio-optimiser-claude`](https://git.fromaitochitta.com/open/portfolio-optimiser-claude) |
A change that is true of only one of the two stacks does not belong here, however correct it
is — that is the whole point of the shared core. See the Non-goals in the [README](README.md).
## Reporting an issue
Useful issues on a specification repository look different from bug reports on code. The most
valuable ones name a specific place in the text:
- **Quote the section and the sentence**, not just a line number. Line numbers here go stale
quickly; a section heading plus the wording you are reading survives an edit above it.
- Say which of the two things you are claiming: that the specification is **internally
inconsistent**, or that it is **inconsistent with an implementation**. They have different
remedies, and conflating them is the most common way a report stalls.
- For a fixture, state the input, the output you expected, and the output you got.
## If you are maintaining a consuming repository
Sync is **pull-only**, and all edits land here first:
```sh
git subtree pull --prefix=shared commons main --squash
```
**Never run `git subtree push` from a consuming repository.** The reason, and what it cost the
one time it happened, is documented in the [README](README.md).
## Conventions
Commits follow [Conventional Commits](https://www.conventionalcommits.org/)
(`type(scope): description`). Changes to normative text are ratified before they land; the
reasoning behind each ruling is recorded in [`docs/plan/`](docs/plan/), including for the
rulings that were later reversed.
## Questions?
Open an issue.

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Kjell Tore Guttormsen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

117
README.md
View file

@ -1,25 +1,43 @@
# shared/ — framework-neutral core # portfolio-optimiser-commons
This directory holds the parts of the project that are **independent of any AI agent Framework-neutral shared core of the portfolio-optimiser method: the normative specs, example bundles and golden fixtures vendored by both reference implementations.
framework** and are meant to be **shared, unchanged, between both reference
implementations**:
- **this repository** — the method built on Microsoft Agent Framework (MAF); [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
- **a sibling repository** (built later, in sequence) — the same method on the
**Claude Agents SDK**.
Sharing one identical core is what makes the two implementations a *fair comparison*: This repository is the **source of truth** for everything in the portfolio-optimiser method
both consume the same concept, the same example data, and the same expected outcomes, that is **independent of any AI agent framework**. It holds no runnable code — only
so the only thing that differs is the agent framework itself. normative specifications, example data, and expected outcomes.
## Contents (growing) Two reference implementations consume it, unchanged, as a `git subtree` at `shared/`:
- [`CONCEPT.md`](CONCEPT.md) — the business concept, written for a non-specialist - [`portfolio-optimiser`](https://git.fromaitochitta.com/open/portfolio-optimiser) — the
(e.g. a business developer at another company). method on **Microsoft Agent Framework (MAF)**;
- [`portfolio-optimiser-claude`](https://git.fromaitochitta.com/open/portfolio-optimiser-claude)
— the same method on the **Claude Agent SDK**.
Sharing one identical core is what makes the two implementations a *fair comparison*: both
consume the same concept, the same example data, and the same expected outcomes, so the only
thing that differs is the agent framework itself. The second implementation is built from the
specifications alone, without reverse-engineering the reference code.
## Contents
- [`method-spec.md`](method-spec.md) — the **normative method specification**, framework-neutral
(the prose never names a concrete agent toolkit — enforced by a guard test): the 8-step loop,
the verdict JSON contract, the inbox/outbox folder contract, the promotion-gate semantics, the
IR projection + golden suite as the only ground truth, and the budget/provenance requirements.
- [`ingest-spec.md`](ingest-spec.md) — the **normative ingest specification**, framework-neutral
(same guard rule): the deterministic ingest step that materializes real data sources as OKF
bundles BEFORE the loop — the polymorphic manifest schema (file/CSV, SQL, HTTP as extension
point), the credential-reference rule, the verdict-layer reservation, the ingest provenance
frontmatter with an explicit timestamp, the index-generation requirement, and the
golden-extraction format.
- [`CONCEPT.md`](CONCEPT.md) — the business concept, written for a non-specialist (e.g. a
business developer at another company). Written in Norwegian.
- [`examples/bygg-energi-mikro/`](examples/bygg-energi-mikro/) — the first example knowledge - [`examples/bygg-energi-mikro/`](examples/bygg-energi-mikro/) — the first example knowledge
bundle (OKF / LLM-wiki): one office building, one LED-retrofit measure, with a seed expert bundle (OKF / LLM-wiki): one office building, one LED-retrofit measure, with a seed expert
verdict encoding the realization gap and a golden-suite of expected validator outcomes. A verdict encoding the realization gap and a golden-suite of expected validator outcomes. A small
small **dev fixture** for exercising the agentic loop; a realistic full-scale example comes later. **dev fixture** for exercising the agentic loop; a realistic full-scale example comes later.
- [`examples/nav-golden-hierarchy/`](examples/nav-golden-hierarchy/) and - [`examples/nav-golden-hierarchy/`](examples/nav-golden-hierarchy/) and
[`examples/nav-golden-escape/`](examples/nav-golden-escape/) — the **nav-golden** fixture class: [`examples/nav-golden-escape/`](examples/nav-golden-escape/) — the **nav-golden** fixture class:
`bundle/` in, `expected-read-context.md` out, exercising the navigation contract (method-spec §3 `bundle/` in, `expected-read-context.md` out, exercising the navigation contract (method-spec §3
@ -33,45 +51,52 @@ so the only thing that differs is the agent framework itself.
framework-neutral Agent Skill: a `SKILL.md` persona prompt (energy-advisor / M&V role + the framework-neutral Agent Skill: a `SKILL.md` persona prompt (energy-advisor / M&V role + the
realization-gap methodology the validator cannot compute) and a canonical realization-gap methodology the validator cannot compute) and a canonical
`references/example-verdict.json`. Both reference implementations instantiate the reviewer from `references/example-verdict.json`. Both reference implementations instantiate the reviewer from
this one artifact; `shared/` stays pure data (each stack reads the JSON with its own loader). this one artifact; this repository stays pure data (each stack reads the JSON with its own loader).
- [`method-spec.md`](method-spec.md) — the **normative method specification**, framework-neutral - [`docs/plan/`](docs/plan/) — the decision record: how each ruling in the specifications above was
(the prose never names a concrete agent toolkit — enforced by a guard test): the 8-step loop, arrived at, including the ones that were later reversed. Working documents, not normative, and
the verdict JSON contract, the inbox/outbox folder contract, the promotion-gate semantics, the written in a mix of Norwegian and English.
IR projection + golden suite as the only ground truth, and the budget/provenance requirements.
The sibling implementation is built from this spec alone, without reverse-engineering the
reference code.
- [`ingest-spec.md`](ingest-spec.md) — the **normative ingest specification**, framework-neutral
(same guard rule as the method spec): the deterministic ingest step that materializes real
data sources as OKF bundles BEFORE the loop — the polymorphic manifest schema (file/CSV, SQL,
HTTP as extension point), the credential-reference rule, the verdict-layer reservation, the
ingest provenance frontmatter with an explicit timestamp, the index-generation requirement,
and the golden-extraction format.
## Rules ## Vendoring this repository
- **Nothing in here may import or depend on a specific agent framework.** If it does, This repository is **vendored, not installed** — there is no package to add. Each consuming
it does not belong in `shared/`. repository carries it as a `git subtree` under `shared/`, so the specs and fixtures are present in
- **Repo layout (decision R1, realized 2026-07-03):** the shared core lives in its own a normal checkout with no extra tooling.
repository, [`portfolio-optimiser-commons`](https://git.fromaitochitta.com/ktg/portfolio-optimiser-commons)
— the **source of truth**. Each implementation repo consumes it as a **git subtree**
at this unchanged `shared/` path (so tests and the `PORTFOLIO_SHARED_ROOT` default
resolver are unaffected). Do not edit commons content anywhere else without syncing.
## Subtree sync (pull-only — run from the consuming repo's root) Register the remote once, from the consuming repository's root:
The remote is registered as `commons` ```sh
(`ssh://git@git.fromaitochitta.com/ktg/portfolio-optimiser-commons.git`). git remote add commons https://git.fromaitochitta.com/open/portfolio-optimiser-commons.git
git subtree add --prefix=shared commons main --squash
```
**All edits land in commons first** (clone it, commit, push there), then each Then pull updates with:
consuming repo pulls them in:
```sh ```sh
git subtree pull --prefix=shared commons main --squash git subtree pull --prefix=shared commons main --squash
``` ```
**Never run `git subtree push` from a consuming repo.** Observed 2026-07-03: because **Sync is pull-only. All edits land here first** — commit and push in this repository, then pull
this repo's history contains commits that create/delete the `shared/` prefix, the them into each consumer.
push re-split leaked the consumer's *entire* history into commons (cleaned up by
force-push the same day). Pull-only keeps commons the clean source of truth.
See the target picture for the full architecture: `docs/plan/2026-06-26-maalbilde-agentic-loop.md`. **Never run `git subtree push` from a consuming repository.** Observed 2026-07-03: because a
consumer's history contains commits that create and delete the `shared/` prefix, the push re-split
leaked the consumer's *entire* history into this repository (cleaned up by force-push the same
day). Pull-only keeps this repository the clean source of truth.
## Non-goals
- **Not a runnable system.** No pipeline, no CLI, no package. The specifications describe
behaviour; the two implementation repositories provide it.
- **No framework dependency.** Nothing here may import or depend on a specific agent framework.
If it does, it does not belong in this repository — that is what "framework-neutral" buys, and a
guard test in each consumer enforces it for the two normative specs.
- **Not a general-purpose knowledge-format standard.** The bundle layout follows the upstream Open
Knowledge Format where it applies; this repository does not seek to replace or extend it beyond
what the method needs.
- **Not a home for implementation decisions.** Anything true of only one of the two stacks belongs
in that stack's repository, not here.
- **No inbound patches through this forge.** See [CONTRIBUTING.md](CONTRIBUTING.md).
## License
[MIT](LICENSE) © 2026 Kjell Tore Guttormsen

62
SECURITY.md Normal file
View file

@ -0,0 +1,62 @@
# Security Policy
## Reporting a Vulnerability
If you discover a security issue, please report it responsibly.
**Please do NOT report security issues through public issues.**
### How to Report
Email: hello@fromaitochitta.com
Include:
- Description of the issue
- Steps to reproduce
- Potential impact
- Any suggested fixes (optional)
### What to Expect
- Acknowledgment within 48 hours
- Regular updates on progress
- Credit in the fix announcement (if desired)
## What the attack surface here actually is
This repository ships **no executable code** — no package, no pipeline, no CLI. It contains
normative specifications, example knowledge bundles, and golden fixtures. There is no dependency
tree to keep patched and nothing here that runs on your machine.
That narrows the realistic reports to three kinds, and all three are worth sending:
1. **A specification that mandates unsafe behaviour.** The specs are binding on the
implementations that consume them, so a weak rule propagates. The ingest specification in
particular governs a boundary where untrusted external data enters the system: its
credential-reference rule (manifests carry *references* to credentials, never the credentials
themselves) and its verdict-layer reservation exist for this reason. A gap in that text is a
real vulnerability report even though no code changes.
2. **A secret or personal data in the repository or its history.** The example bundles are
synthetic. If you find something that is not, report it — including in the git history, which
is public in full.
3. **A fixture that would make a consuming gate pass when it should fail.** The golden suites are
the only ground truth the implementations check themselves against. A fixture that silently
sanctions unsafe behaviour weakens every consumer at once.
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| latest | :white_check_mark: |
| < latest| :x: |
Consumers vendor this repository as a `git subtree`, so a fix here reaches them only when they
pull. If a report leads to a change in normative text, both reference implementations are
notified — but their pull is their own action, on their own schedule.
## Scope Note
The portfolio-optimiser method is a **technical framework**. Deploying organizations own their
own data protection, risk, and compliance assessments (DPIA/ROS). The specifications describe
technical prerequisites (local-only operation, provenance, no silent egress) but make no
compliance guarantees.

View file

@ -406,6 +406,23 @@ hvorfor: det finnes et ANDRE anker vi ikke siterte, og det er normativt.**
> Et åpenbart tomt treff hadde vært tryggere. **Regel, samme klasse som `git log -S`-regelen > Et åpenbart tomt treff hadde vært tryggere. **Regel, samme klasse som `git log -S`-regelen
> under: sitér SEKSJON + ORDRETT TEKST når mottakeren står på en annen ref — eller skriv > under: sitér SEKSJON + ORDRETT TEKST når mottakeren står på en annen ref — eller skriv
> hvilken ref numrene gjelder.** > hvilken ref numrene gjelder.**
>
> **⚠️ Failure-moden er ikke lenger hypotetisk — den INNTRAFF (målt 2026-08-01).**
> `portfolio-optimiser` stilte MCP-spørsmålet **på nytt** fem dager etter at det var avgjort
> (`20260731T193214Z`), med S2.2 ført som blokkert på oss — nøyaktig utfallet avsnittet over
> beskrev som «den mest sannsynlige konklusjonen». Kjennelsen var korrekt, allerede levert
> (`20260726T190922Z`) og allerede ført her i §7.2; **det som ikke overlevde pull-grensen var
> ankeret.** Svar sendt `20260801T175201Z` med begge refs oppgitt eksplisitt.
>
> To ting generaliserer, og de er verdt mer enn korreksjonen:
>
> 1. **Et feil linjeanker svikter STILLE.** Kostnaden er ikke at mottakeren blir forvirret —
> den er at mottakeren *rimelig* konkluderer at kjennelsen din hviler på løs grunn, og
> behandler et avgjort spørsmål som åpent igjen. Ingen av partene ser feilen; begge ser en
> uenighet som ikke finnes.
> 2. **Et spørsmål som kommer TILBAKE er et signal om VÅR formidling, ikke om deres hukommelse.**
> Riktig første grep er ikke «det sa vi allerede», men å lese hva den forrige meldingen
> faktisk bar (`~/.claude/coord/<dem>/archive/`). Feilen lå der.
`:29-31` sier at MCP-veien ikke krever spec-endring. `http`-punktet sier **normativt hvor den `:29-31` sier at MCP-veien ikke krever spec-endring. `http`-punktet sier **normativt hvor den
hører hjemme** — som en utvidelse av `http`-familien, med **MUST** på de samme kontraktene. hører hjemme** — som en utvidelse av `http`-familien, med **MUST** på de samme kontraktene.

View file

@ -199,6 +199,71 @@ skal bære. O2 fastslår formen (`process:<id>`, som v0.2 §7 eksplisitt tillate
navngir prosessen specen definerer. Selve id-en er en redaksjonell avgjørelse som tas når navngir prosessen specen definerer. Selve id-en er en redaksjonell avgjørelse som tas når
kontraktslinjene skrives, og bør avklares med `llm-ingestion-okf` i samme runde som pinnen. kontraktslinjene skrives, og bør avklares med `llm-ingestion-okf` i samme runde som pinnen.
### 4.2 Pinnen, id-en og siteringen — avgjort 2026-07-31 (økt 4)
`llm-ingestion-okf` svarte samme dag. Tre ting falt på plass, og ett premiss i §4.1 viste seg
for svakt formulert. Grunnlaget over står ordrett uendret; dette er status, ikke omskriving.
**Pinnen foreligger: `2504011`** — «feat(okf-v0.2): D5 — the v0.2 golden fixture, with
`okf_version` in root frontmatter», pushet til `open/llm-ingestion-okf`. Det er en PIN, sagt
eksplisitt som sådan. `6f42c10`/`ed08ac1` var siterte refs; skillet holdt.
**Deres v0.2-fikstur var aldri rammet, og det er målt, ikke antatt.** Den bar O2-formen fra
`c90171d` (07-27), vedtatt uavhengig av oss. Vår varsling traff et annet sett: de fire
DEFAULT-profil-fasitene (`ingest-golden-{file,sql,http}`, alle `:8`), som er VÅRT lag å endre.
**`<fast id>` = `process:okf-ingest`** (operatøren, 2026-07-31). Okfs eget forslag. De foreslo
først `process:llm-ingestion-okf` og argumenterte samtidig mot den — riktig, og strengere enn
de kunne se herfra:
| Kilde | Ordrett | Frossen siden |
|---|---|---|
| `ingest-spec.md:8-9` | «The prose is framework-neutral by rule: it never names a concrete agent toolkit or vendor stack, and a guard test keeps it that way» | `7aa53fc` (07-03) |
| `ingest-spec.md:7-8` | «implemented **from this spec alone** — without reverse-engineering any existing implementation» | `7aa53fc` |
| `ingest-spec.md:282` (§11-seam «Spec integrity») | «this spec goes missing, **names a concrete agent toolkit**, or stops documenting a contract field» | `7aa53fc` |
**Presisjonsforbehold, så raden ikke føres for sterkt:** `llm-ingestion-okf` er en
ingest-implementasjon, ikke strengt tatt en «agent toolkit» — `:282` treffer derfor ikke
ordrett. Det er `:7-8` som treffer uten tolkningsrom: å normere produsentens repo-navn ville
tvunget enhver annen konform implementasjon til å skrive det navnet i sin egen output. Samme
klasse som `:29` tvang O1 ut på, bare svakere. **Utelukkelsen holder, men på `:7-8`, ikke `:282`.**
**Siteringen er IKKE normativ — formen er usitert.** Okf spurte om anførselstegnene i
`by: "process:<fast id>"` var normative eller illustrative. **Spørsmålet er avgjort av frossen
tekst — fjerde gang** (etter D-B, `:29`-vs-O1 og `:158`):
- `method-spec.md:90` (frossen `7d2b46c`, 07-03): «Frontmatter is the leading `---`-delimited
block, **parsed line-oriented as `key: value` strings**».
- Vi parser altså ikke YAML. Verdien ER den rå teksten etter `key: `. Det finnes ingen
transparent sitering i formatet: et anførselstegn er **et tegn i verdien**, ikke syntaks som
en parser fjerner. Normert sitat ⇒ predikatet måtte matchet anførselstegnene som datainnhold.
- Målt bekreftelse: v0.3.2s port sammenligner mot **strengen** `"true"` (§3.1 `:100`), ikke mot
en boolean — nøyaktig fordi parsingen er line-oriented.
- Oppstrøms er selv usitert **med kolon i verdien**: `by: human:jsmith@acme` (§3s empiri).
Kanonisk form, vedtatt: `generated: { by: process:okf-ingest, at: <ingested_at> }`
**⛔ KORREKSJON av §4.1: pin var ikke den siste gaten.** §4.1 skrev «Ingen frossen tekst endres
før `llm-ingestion-okf` er pinnet til en commit». Det er en nødvendig, ikke tilstrekkelig
betingelse, og formuleringen ville — lest alene — hjemlet å skrive de 5 linjene nå. Den er
korrigert av avstemt tekst i søsterunderlaget:
> `2026-07-25-amendment-underlag.md:495-496` — «vi forbereder underlaget, **operatøren
> ratifiserer**, og **frossen tekst endres ikke uten den ratifiseringen**»
Køens rad 8 er B1/D4 — **V1 står ennå ikke i køen**, slik §8 alltid har sagt («V1 er punkt
nummer 8 *hvis den ratifiseres*»). Pin + id lukket gaten for at V1 kan gå I KØ; ratifiseringen
er en separat, operatør-eid handling, og amendment-pakken er på bevisst hold. **`ingest-spec.md`
står uendret på `bfa5a9b`; de 5 linjene bærer fortsatt literal `generated: true`.**
**B1 er ikke presedens for det motsatte:** `8a7d430` rørte `README.md` («katalog, ikke
kontrakt») og to planfiler — null normative filer. Commit-meldingen sier det selv om V1: «Ingen
frossen tekst er rørt.»
**Varslet til okf er sendt** (07-31, som svar på pinnen): id + siteringsform vedtatt, og et
eksplisitt **ikke regenerer ennå** — regenerering mot ikke-ratifisert tekst ville pekt fasiten
deres på en spec som ikke finnes. Varslingsplikten ved faktisk tekstendring står fortsatt live.
## 5. Opsjonene, med målt kostnad ## 5. Opsjonene, med målt kostnad
Kostnad er talt som **kontraktslinjer som må skrives om** av de 7 (`:34`, `:70`, `:82`, `:152`, Kostnad er talt som **kontraktslinjer som må skrives om** av de 7 (`:34`, `:70`, `:82`, `:152`,
@ -629,3 +694,88 @@ line-oriented-krav, og `ingest_manifest` som stempelets andre halvdel. Ingen ops
| …altså ÉN commit bak, ikke to | `git rev-list --count 7aa53fc..HEAD -- ingest-spec.md` | **1** (`bfa5a9b`) | | …altså ÉN commit bak, ikke to | `git rev-list --count 7aa53fc..HEAD -- ingest-spec.md` | **1** (`bfa5a9b`) |
| MCP-ankeret finnes i den pinnede kopien | `git show 7aa53fc:ingest-spec.md \| grep -n "An MCP-based"` | `:101` — S2.2/S2.4-ugatingen henger ikke på en pull | | MCP-ankeret finnes i den pinnede kopien | `git show 7aa53fc:ingest-spec.md \| grep -n "An MCP-based"` | `:101` — S2.2/S2.4-ugatingen henger ikke på en pull |
| `:112-114` hos konsumenten er IKKE tomt | `git show 7aa53fc:ingest-spec.md \| sed -n '112,114p'` | felt-tabellen: `id` / `title` / `query` (`okf_type`/`max_rows` er `:115-116`) | | `:112-114` hos konsumenten er IKKE tomt | `git show 7aa53fc:ingest-spec.md \| sed -n '112,114p'` | felt-tabellen: `id` / `title` / `query` (`okf_type`/`max_rows` er `:115-116`) |
**Tilført 2026-07-31 (økt 4 — pin, id, sitering, ratifiseringsgaten):**
| Påstand | Sjekk | Resultat |
|---|---|---|
| Frontmatter parses som STRENGER, ikke YAML | `method-spec.md:90` | «parsed line-oriented as `key: value` **strings**» — derav er sitering datainnhold, ikke syntaks |
| …og har vært frossen hele veien | `git log -1 -S 'parsed line-oriented as' -- method-spec.md` | `7d2b46c` (2026-07-03) — eldste spec-commit |
| Prosaen er framework-nøytral ved regel | `ingest-spec.md:8-9` | «never names a concrete agent toolkit or vendor stack, and a guard test keeps it that way» |
| …håndhevet som §11-seam | `ingest-spec.md:282` | «Spec integrity \| this spec … names a concrete agent toolkit …» |
| …men `:282` treffer ikke okf ordrett | lesning: okf er ingest-impl., ikke «agent toolkit» | **utelukkelsen hviler på `:7-8`**, ikke `:282` — ført som forbehold, ikke som treff |
| Commons har fortsatt INGEN aktørkonvensjon | `grep -n "human:\|process:\|by: " ingest-spec.md method-spec.md CONCEPT.md \| wc -l` | **0** (uendret fra 07-27) |
| Spec-en kaller laget «ingest», prosessen «materialization» | `grep -io 'materializ[a-z]*' ingest-spec.md \| wc -l` + `:1`, `:18`, `:28` | 27 forekomster; tittel + §1 bruker «Ingest» som lagets navn → `okf-ingest` |
| `ingest-spec.md` er URØRT | `git log --oneline -2 -- ingest-spec.md` | `bfa5a9b`, forrige `7aa53fc` — ingen commit i økt 3 eller 4 |
| De 5 linjene er urørte — men bærer IKKE samme form | `grep -n '\`generated' ingest-spec.md` | **4 av 5** bærer `generated: true` ordrett (`:34`, `:70`, `:82`, `:275`). `:214` er §7-feltradstabellens rad («\`generated\` … Literally \`true\` — the machine-generated marker») og bærer ikke literalen. Se raden under |
| …og `:214` er derfor IKKE en strengerstatning | O2-formen (`generated: { by: …, at: … }`) vs. radens «Literally `true`» | raden **beskriver feltets verdi**. Under O2 er verdien et objekt med `by`/`at`, så raden må skrives om (evt. splittes), ikke søk-og-erstattes. **Egen redigering, samme amendment** |
| Frossen tekst krever RATIFISERING, ikke bare pin | `2026-07-25-amendment-underlag.md:495-496` | «operatøren ratifiserer, og frossen tekst endres ikke uten den ratifiseringen» |
| V1 står ikke i køen | samme fil §9, rad 8 | rad 8 = **B1/D4**, ikke V1 — uendret fra 07-27 |
| B1 rørte ingen normativ fil | `git show 8a7d430 --name-only` | `README.md` + 2 planfiler; **0** normative filer |
| Pinnen er en pin, ikke en ref | okf-melding 07-31, `2504011` | sagt eksplisitt som pin; skillet fra `6f42c10`/`ed08ac1` holdt |
| Deres v0.2-fikstur bar O2-formen allerede | okfs måling, `c90171d` (07-27) | **ført som DERES**, ikke reprodusert her |
**Korreksjon 2026-07-31 (økt 6) — «de 5 linjene» er ikke homogene.** Raden «De 5 linjene bærer
fortsatt literalen» påsto at alle fem bar `generated: true` ordrett. Det er feil, og planen
motsa seg selv: §5.1 fører `:214` korrekt opp som «Literally `true`»-raden, og
verifiseringstabellens egen `grep -n '\`generated'`-rad lister `:214` blant de 7 uten å skille
form. Målt nå: `grep -n 'generated: true' ingest-spec.md` gir **4** treff (`:34`, `:70`, `:82`,
`:275`) — ikke 5.
Feilen var arvet ordrett inn i `STATE.md`s NESTE-blokk («skriv om de 5 kontraktslinjene … fra
literal `generated: true`»). Konsekvensen er ikke kosmetisk: en økt som utfører V1 mekanisk
etter den formuleringen finner 4 av 5 treff og står igjen med to like sannsynlige feiltolkninger
— (a) drift i frossen tekst, eller (b) `:214` hoppes over, som etterlater **ærlighetsmarkørens
§7-halvdel** (§3s ærlighetsmarkør-rad: «§1 `:34`, §7 `:214`») ukonvertert mens §1-halvdelen er
O2. Tellingen «5 av 7» (§4.1, §5) står uendret — det var formen, ikke antallet, som var feil ført.
*Ingen normativ fil rørt av denne korreksjonen; `ingest-spec.md` står fortsatt på `bfa5a9b`.*
---
## 10. RATIFISERT 2026-08-02 — og en andre tabellrad som økt 6 ikke fanget
**Operatøren ratifiserte V1 2026-08-02**, ordrett: *«Jeg kan ta okf-kostnaden nå, men vi må
starte i en ny sesjon.»* Utførelsen ligger dermed hos neste økt, ikke hos den som mottok
vedtaket.
**Begge gater er oppløst, og den andre falt av seg selv.** okf-gaten var lukket fra før (pin
`2504011`, økt 4). Ratifiseringsgaten er nå gitt. Den tredje betingelsen som har ligget i
STATE — at V1 skulle vente på §9-amendment-pakken — var aldri en gate i egen rett: den var
**batching** mot at endringen utløser `llm-ingestion-okf`s regenerering av fire DEFAULT-fasiter.
Når operatøren tar den kostnaden nå, har batchingen ingenting å batche mot. V1 er frikoblet fra
pakken, og S2.3 (`{type: "doc"}`, spurt `20260802T191837Z`) endrer ikke utfallet.
### Ankere re-målt 2026-08-02 (vår egen ferskvare-regel)
| Sted | Seksjon | Ordrett i dag | Behandling |
|---|---|---|---|
| `:34` | §1 Scope | «such (`generated: true` plus a manifest reference, §7) everywhere it is presented.» | prosa — mekanisk |
| `:70` | §3 Layer separation | «the ingest stamp (`generated: true` plus an `ingest_manifest` reference, §7) and MUST NOT» | prosa — mekanisk |
| `:82` | §3 Layer separation | «ownership stamp — `generated: true` together with an `ingest_manifest` reference — while» | prosa — mekanisk |
| `:214` | §7 Provenance | «\| `generated` \| Literally `true` — the machine-generated marker (§1 honesty rule). \|» | feltrad — skriv om/splitt |
| `:275` | §11 Load-bearing | «\| Stamp integrity (curated writers) \| … the complete ownership stamp (`generated: true` with `ingest_manifest`) stops being rejected … \|» | **rød-betingelse** |
### Korreksjonen: det er TO tabellrader, ikke én
Økt 6 korrigerte «de 5 linjene» fra homogene til 4 + 1 og pekte ut `:214`. Re-målingen viser at
korreksjonen selv var ufullstendig: **`:275` er også en tabellrad, og den står i §11s
load-bearing-tabell.** Det er ikke prosa som beskriver stempelet — det er en **rød-betingelse i
konformanskontrakten**. Å endre den endrer hva en konformant implementasjon må bevise, og er
derfor en sterkere handling enn å redigere §1- og §3-prosaen.
De «fire mekaniske» er i praksis **tre** (`:34`, `:70`, `:82`). `:214` og `:275` krever hver sin
vurdering. `:152` og `:309` overlever (feltnavn, ikke literal).
Dette er andre gang en verifiseringsrad i denne planen påsto homogenitet som ikke fantes. Regelen
står: **sjekk hva linjene FAKTISK bærer — og hvilken tabell de står i — før noe føres som
mekanisk.**
### Varslingsplikt, utløst av utførelsen
Endringen utløser den lovede meldingen til `llm-ingestion-okf` — den setter i gang deres
regenerering av de fire DEFAULT-fasitene. Den sendes i **samme økt** som tekstendringen, ikke
senere. `portfolio-optimiser-claude` varsles samtidig; de vet ennå ikke at id-en er
`process:okf-ingest`.
*`ingest-spec.md` er fortsatt urørt på `bfa5a9b` i det dette skrives.*

View file

@ -0,0 +1,93 @@
# Google OKF v0.2 — sjekken er utført, og hypotesen holdt ikke
**Dato:** 2026-07-31 (økt 5) · **Status:** LUKKET, ingen melding sendt · **Marker:** `okf-second-brain-convention`
STATE bar siden 07-27 en uverifisert observasjon som NESTE STEG: *«catalog bumpet 0.1→0.2 for å
ikke være forvekslbar med Google OKF v0.1 — er Google nå på 0.2, kan avklaringen ha kollapset.»*
Sjekken er nå gjort. **Avklaringen har ikke kollapset, og spørsmålet var feilstilt.** Tre av
premissene i formuleringen viste seg å avvike fra ground truth.
## 1. Google er på v0.2 — men det visste vi allerede
Verifisert mot primærkilde: Google Cloud Blog, *«Open Knowledge format v0.2 tackles agentic
trust»*, publisert **2026-07-25**.
Men søket var strengt tatt overflødig. Svaret lå i vår egen arkiverte innboks, fem dager gammelt:
`llm-ingestion-okf`, `20260726T114345Z`, første linje i brødteksten — ordrett **«OKF v0.2 er ute
(2026-07-25).»** Hele V1-sporet er *bygget på* v0.2 (`generated`-feltets form etter v0.2; se
`2026-07-26-v1-generated-felt-okf-v0.2.md`, og filnavnet sier det selv).
**Dette er en STATE-defekt, ikke et funn.** Observasjonen ble ført som «uverifisert» i fire økter
mens den samtidig var bærende premiss for arbeidet i nabosporet. Premiss-verifiseringsregelen ble
anvendt på output, ikke på STATEs egen påstandsliste. Billigste sjekk som fantes var `grep` i eget
arkiv — ikke WebSearch.
## 2. Catalog er ikke på 0.2. De er på 0.3.
| Påstand i STATE | Ground truth |
|---|---|
| catalog er på 0.2 | **0.3**`1ca27f6`, 2026-07-31 (i dag) |
| bumpet skjedde «for å ikke være forvekslbar» | primærgrunnen var **§3-gulvet** |
`6a72b26` (2026-07-25), commit-subjekt ordrett: `feat(okf): enforce §3 okf_version shape, bump
convention 0.1 -> 0.2`. Og specens egen header, `spec.md:12-14`:
> 0.2 had tightened the §3 floor: `okf_version` enforced on shape. Distinct from — and
> deliberately no longer numerically confusable with — upstream Google OKF v0.1, which this
> convention targets and does not version.
Ikke-forvekslbarheten er ført som **bevisst sidegevinst**, ikke som årsak. STATE byttet om primær
og sekundær og bygget et neste steg på den omvendingen. (Jf. driftsmodellen: *før en rad ikke
sterkere enn den bærer* — her førte vi vår egen rad for sterkt.)
## 3. Hvorfor avklaringen ikke kan kollapse: det er to akser
Dette er **akse-forveksling nr. 13**, og denne gangen var det vår.
- **Akse A — catalogs konvensjonsversjon:** 0.1 → 0.2 → 0.3. Beskriver catalogs *eget* dokument.
- **Akse B — `okf_version`-verdien:** hvilken upstream Google-versjon en bundle targeter.
Catalog sier eksplisitt at konvensjonen *«targets and does not version»* upstream (`spec.md:13-14`),
og i §12 (`:245-246`): *«Its value set is owned by Google.»* Gaten er tilsvarende renset for
akse-lekkasje (`:70-72`): den *«asserts **nothing** about which upstream versions exist ... a bundle
targeting a newer upstream version passes.»*
At Google flyttet seg på akse B kan derfor ikke kollapse en avklaring som lever på akse A.
Tallsammenfallet som hypotesen fryktet inntreffer uansett ikke: catalog 0.3 vs. Google 0.2.
## 4. Det ene som faktisk står igjen — og det er ikke vårt
`spec.md` sier to steder at upstream-versjonen bundelen targeter er «currently `0.1`» (`:63`,
`:246`), mens `:67` i samme dokument siterer upstreams kanoniske eksempel `okf_version: "0.2"`
(`okf/SPEC.md:773`).
Det er **ikke en defekt**, og skal ikke meldes som en. Catalog har foregrepet situasjonen i egen
tekst, §12 `:246-247`: *«When Google bumps OKF, each plugin re-checks conformance.»* Google har nå
bumpet. Re-sjekken er dermed utløst — men den er **catalogs å utløse, på catalogs akse**, og
plugin-eiernes å utføre. Vi er ikke respondent.
Per driftsmodellen: navngi aksen, pek på rett respondent, ikke lever en verdi vi ikke eier.
## Konklusjon
- Sjekken STATE hjemlet: **utført**. Hypotesen: **falsifisert**.
- **Ingen melding skal sendes** på det opprinnelige grunnlaget — grunnlaget fantes ikke.
- Det som *kan* sendes er noe annet og mindre: en `--fyi` til `catalog` om at Google er på 0.2 og
at deres egen §12-re-sjekk dermed er utløst. **Fortsatt gated på operatør-go**, og lavt prioritert
— catalog eier både aksen og triggeren, og `1ca27f6` (i dag) viser at de følger upstream tett.
- Sporet `okf-second-brain-convention` er dermed **lukket fra vår side**.
## Verifiseringslogg
| Påstand | Kilde |
|---|---|
| Google OKF v0.2, publisert 2026-07-25 | Google Cloud Blog, `okf-v0-2-adds-trust-signals` (WebFetch) |
| v0.2 var kjent for oss 2026-07-26 | `coord/.../archive/20260726T114345Z-3155211798-from-llm-ingestion-okf.md` |
| catalog er på 0.3 per 2026-07-31 | `catalog@1ca27f6`; `spec.md:7` |
| 0.2-bumpens primærgrunn = §3-gulvet | `catalog@6a72b26` commit-subjekt; `spec.md:12` |
| konvensjonen versjonerer ikke upstream | `spec.md:13-14`, `:245-246` |
| gaten godtar nyere upstream-versjon | `spec.md:70-72` |
| re-sjekk-plikten er plugin-eiernes | `spec.md:246-247` |
Catalog-ankrene er lest read-only i `~/repos/ktg-plugin-marketplace/catalog` @ `1ca27f6`. Ingenting
skrevet i det repoet.

View file

@ -0,0 +1,83 @@
# Funn-notat — §11 ankrer ikke §8 (og heller ikke §10)
**Status:** FUNN, registrert. **Ikke et underlag, ikke et forslag, ikke bestilt.**
Køplassering er operatørens. Commons forbereder underlaget, operatøren ratifiserer — og vi
bestiller ikke vår egen kø, heller ikke for funn vi selv gjør.
**Foranledning:** `portfolio-optimiser` meldte 2026-08-01 (`20260801T175832Z`) at `method-spec.md`
§11 mangler en rad for deres portefølje-brede budsjettsøm (S3.4/F10: globalt token-tak håndhevet
før kall, wave-admission med reservasjon, oppstartsnekt). Undersøkelsen av den forespørselen ga
to atskilte resultater, og bare det ene er vårt.
---
## 1. Forespørselen: avvist på akse
§1 (Scope and conformance) definerer metoden ordrett som «a swarm of agents generates candidate
cost-saving measures for **one project at a time**». §8 (Budget and stop criteria) er følgelig
den **per-run** termineringskontrakten.
Globalt tak på tvers av prosjekter, wave-admission med reservasjon og oppstartsnekt for et
prosjekt som ikke kan finansieres er **orkestrering over metoden**, ikke en søm i den. Deres
S3.4/F10 er riktig plassert hos dem, og at de bærer den som
`tests/test_portfolio_budget_loadbearing.py` (6 målte røde mutasjoner) er sømmen dokumentert der
den hører hjemme.
Konsekvensen av å legge raden inn likevel er konkret og var avgjørende: §11 er en MUST-tabell.
En konformant implementasjon som kjører ett prosjekt uten portefølje-orkestrering ville blitt
**ikke-konform på en søm spec-ens egen scope-klausul ikke governerer**.
Svar sendt `20260802T190344Z`.
## 2. Det undersøkelsen faktisk fant, og det er vårt
§11 har **tolv rader**. Ingen av dem ankrer **§8**:
- fail-closed når `usage` mangler i et svar (MÅ feile, aldri stille slutte å telle),
- det strukturerte stop-eventet med breached kind + limit + observed value,
- cap-objektenes nekt av ikke-positive verdier.
**§10** (Startup contracts) har heller ingen rad.
Samtidig sier §1 punkt 3 ordrett:
> proves **every** load-bearing seam with a test that FAILS when that seam is detached (§11).
Enten er §11-tabellen enumereringen av «every» — og da mangler §8 og §10 — eller så er den det
ikke, og da har «every» ingen enumerering i spec-en. **Spenningen er intern i vår egen frosne
tekst.** Den er vår å løse, ikke konsumentens.
## 3. Verifisering (målt, ikke antatt)
```
$ sed -n '421,435p' method-spec.md | grep -ciE 'budget|token|meter|usage|cap|startup|max_rounds'
1
```
Det ene treffet er en **substring-falsk-positiv**: «es**cap**ing» i navigasjons-raden. Reelt
antall §11-rader som nevner budsjett, måler eller oppstart er **null**.
```
$ sed -n '423,434p' method-spec.md | grep -c '^|'
12
$ sed -n '24p' method-spec.md
3. proves every load-bearing seam with a test that FAILS when that seam is detached (§11).
```
## 4. Åpent spørsmål stilt til `portfolio-optimiser`
Av de 6 målte røde mutasjonene i `test_portfolio_budget_loadbearing.py` — hvor mange treffer
**per-run-målerens** søm (usage mangler → feil; cap krysses → strukturert stop), og hvor mange
treffer portefølje-admissionen? Den første halvdelen er in-scope for §8 og kunne vært
referansetest-kolonnen i en rad vi faktisk kan skrive. Den andre halvdelen forblir deres.
Ubesvart per 2026-08-02. Ingen purring — de sa selv at det ikke blokkerer noe hos dem.
## 5. Hva som IKKE er gjort her
- Ingen rad er skrevet.
- Ingen ordlyd er foreslått.
- `method-spec.md` er ikke rørt.
En §8-rad ville vært en endring i frossen, subtree-konsumert tekst og krever operatørens
ratifisering på lik linje med V1.

View file

@ -0,0 +1,138 @@
# V1-etterspill — krever `generated.by` / `generated.at` egne rader i §12?
> **Status: UNDERLAG, ikke ratifisert. Ingen frossen tekst er endret på dette punktet.**
> Funnet under utførelsen av V1 (`54e0ec7`, 2026-08-09). V1 selv er ratifisert og utført;
> dette er en spenning utførelsen *avdekket*, ikke en del av vedtaket.
>
> Beslektet: `2026-07-26-v1-generated-felt-okf-v0.2.md` (V1-vedtaket),
> `2026-08-02-ss11-mangler-rad-for-ss8.md` (samme klasse: intern spenning i frossen tekst).
---
## 1. Funnet
O2 gjør `generated` om fra en literal til en **inline mapping med to navngitte undernøkler**:
```
generated: { by: process:okf-ingest, at: <ingested_at> }
```
§12s kryssjekk-tabell bærer fortsatt **én rad** for `generated` (`| generated | provenance
frontmatter | §3, §7 |`). Spørsmålet er om `by` og `at` skal ha egne rader.
To setninger i frossen tekst gjør dette til mer enn kosmetikk:
> **§12, ingressen** — «Every field of the machine-readable contracts, mapped to its normative
> section (completeness is enforced by the spec-integrity test)»
> **§11, søm «Spec integrity»** — «this spec goes missing, names a concrete agent toolkit, or
> **stops documenting a contract field**»
§12 er altså ikke en bekvemmelighetstabell. Den står under en **load-bearing søm**.
## 2. Presedensen i vår egen tekst — målt begge veier
Dette er poenget som avgjør, og det peker ikke én vei før man skiller aksene.
**Presedens FOR egne rader — `source`:**
`source` er et strukturert kontraktsfelt med navngitte undernøkler. §12 gir det **både** en
toppnivå-rad **og** en rad per undernøkkel:
| Rad i §12 | Hva den er |
|---|---|
| `source` | toppnivå-feltet, «polymorphic on `source.type`» |
| `type` | undernøkkel (diskriminator) |
| `id` | undernøkkel (felles) |
| `root` | undernøkkel, kun `type: "file"` |
| `connection_ref` | undernøkkel, kun `type: "sql"` |
| `base_url` | undernøkkel, kun `type: "http"` |
| `credential_ref` | undernøkkel, kun `type: "http"`, valgfri |
Merk at undernøklene er definert i **prosa** i §4 (punktlisten), ikke i §4s tabell — men de får
likevel egne rader i §12. Tabell-plassering i §4 avgjør altså ikke §12-plikten.
**Presedens MOT egne rader — `ingest_manifest`:**
`ingest_manifest` har intern struktur (`{stem}@{hash16}`, §5) og får **nøyaktig én** rad. Struktur
inne i en verdi utløser altså ikke automatisk rader.
**Aksen som skiller dem:**
| Felt | Intern struktur er… | Egne rader? |
|---|---|---|
| `source` | **navngitte nøkler i en mapping** | ja (4 undernøkler + felles) |
| `ingest_manifest` | et **strengformat** med posisjonelle deler | nei |
| `generated` (etter O2) | **navngitte nøkler i en mapping** | *åpent — men faller på `source`-siden* |
`generated: { by, at }` er en mapping med navngitte nøkler. På den målte aksen ligner den
`source`, ikke `ingest_manifest`.
## 3. Hvorfor V1-vedtaket ikke fanget dette
`2026-07-26-v1-generated-felt-okf-v0.2.md:161` sier: «`:152` og `:309` navngir bare nøkkelen og
overlever.»
**Den påstanden er sann om den eksisterende raden** — raden heter fortsatt `generated`, ligger
fortsatt i provenance-frontmatter, og peker fortsatt på §3/§7. Ingenting ved raden ble usant.
**Den er taus om de to NYE nøklene.** Kostnaden ble talt som «kontraktslinjer som må skrives
om» (§5) — en *omskrivings*-akse. Rader som må **tilføyes** er en annen akse, og den ble aldri
stilt. Dette er ikke en feil i ratifiseringen; det er et hull i dens scope-formulering. Samme
klasse som «de 5 linjene var ikke homogene» og «`:214` er ikke en literal»: kostnadstellingen var
riktig på sin egen akse og blind for en nabo-akse.
## 4. Er sømmen rød i dag? Nei — og det er grunnen til at dette ikke haster
§11-sømmens ordlyd er «**stops documenting** a contract field». §7s omskrevne feltrad
**dokumenterer begge undernøklene** ordrett — den navngir `by`, fastslår at det er en
`process:`-aktør, navngir `at`, og binder den til `ingested_at`. Specen har altså ikke sluttet å
dokumentere noe.
Eksponeringen er mot **§12s egen ingress** («every field … mapped to its normative section»), som
er en fullstendighets-påstand om tabellen. Det er en svakere binding enn sømmens ordlyd.
**Konsekvens:** ingen kjent implementasjon går rød av dagens tilstand. Dette er en intern
spenning, ikke en defekt i drift.
## 5. Opsjoner (ingen anbefaling — operatøren ratifiserer)
| | Hva | Kostnad | Hva den koster i konformans |
|---|---|---|---|
| **O-A** | Tilføy to rader i §12 (`by`, `at` → §7) | 2 linjer, ren prosa | Utvider hva §12 påstår fullstendighet over. Ingen fixture-endring, ingen konsument-kostnad. |
| **O-B** | La §12 stå, men **snevre ingressen** til «every top-level field» | 1 linje | Gjør dagens tilstand eksplisitt konform. Men svekker en påstand `source`-radene allerede motsier. |
| **O-C** | La alt stå | 0 | Spenningen består, udokumentert. |
**O-B har en målt selvmotsigelse:** `root`/`connection_ref`/`base_url`/`credential_ref` er *ikke*
toppnivå-felter og står allerede i tabellen. En «top-level»-innsnevring ville gjort fire
eksisterende rader uhjemlede. Det er ikke et argument mot O-B, men det må løses samtidig.
## 6. Et separat, mindre funn fra samme utførelse
`generated.at` gjentar verdien av `ingested_at`, som er sitt **eget felt i samme
frontmatter-prefiks** (§5s sju nøkler; §7s tabell). Etter O2 bærer et stemplet dokument altså
samme tidsstempel to steder.
Dette er **en følge av den ratifiserte formen**, ikke en feil i utførelsen — v0.2s `generated`
tar `at` som påkrevd del av mappingen, og §1s premiss («der `at` finnes, bindes den til
`ingested_at`») er innfridd nøyaktig som vedtatt. Ført her fordi det er den slags redundans som
senere leses som drift hvis ingen skrev ned at den var tilsiktet.
**Ikke oppe til vurdering her.** En eventuell konsolidering ville rørt §5s ordnede prefiks, som er
en helt annen og dyrere sak.
## 7. Ankere re-målt (2026-08-09, etter `54e0ec7`)
Utførelsen flyttet tre av våre egne ankere. Ført ordrett, ikke som linjenumre:
| Sted | Seksjon | Status |
|---|---|---|
| Honesty rule | §1 | omskrevet — «`generated.by` naming the ingest actor» |
| Ingest owns only its own files | §3 | omskrevet — «`generated.by` equal to the ingest actor» |
| No other writer may forge the stamp | §3 | omskrevet — samme gjengivelse |
| Feltraden for `generated` | §7 | omskrevet, definerer begge undernøkler |
| Load-bearing «Stamp integrity (curated writers)» | §11 | omskrevet — aktør-spesifikt predikat |
| Frontmatter-prefikset (sju nøkler) | §5 | **uendret** — navngir bare nøkkelen |
| Kryssjekk-raden for `generated` | §12 | **uendret** — dette dokumentets tema |
`generated: true` finnes ikke lenger i specen (verifisert med `grep`).

View file

@ -31,7 +31,8 @@ spec, the golden suite, or agent behaviour.
connector) does not require any change to this spec, and NOT implementing it does not break connector) does not require any change to this spec, and NOT implementing it does not break
conformance. conformance.
- **Honesty rule (unwaivable, method spec §1):** a machine-generated bundle is labelled as - **Honesty rule (unwaivable, method spec §1):** a machine-generated bundle is labelled as
such (`generated: true` plus a manifest reference, §7) everywhere it is presented. such (`generated.by` naming the ingest actor, plus a manifest reference, §7) everywhere it is
presented.
- **Boundary:** the deploying organisation owns processing purposes and impact assessments; - **Boundary:** the deploying organisation owns processing purposes and impact assessments;
ingest provides only the technical prerequisites (local-only default, provenance, no silent ingest provides only the technical prerequisites (local-only default, provenance, no silent
egress). egress).
@ -67,9 +68,10 @@ approved knowledge into. Two rules keep ingest and the learning loop apart:
self-contamination the gate exists to prevent. This MUST be enforced fail-fast at manifest self-contamination the gate exists to prevent. This MUST be enforced fail-fast at manifest
validation (before any source call) and proven by a load-bearing test (§11). validation (before any source call) and proven by a load-bearing test (§11).
- **Ingest owns only its own files.** Re-materialization replaces EXACTLY the files carrying - **Ingest owns only its own files.** Re-materialization replaces EXACTLY the files carrying
the ingest stamp (`generated: true` plus an `ingest_manifest` reference, §7) and MUST NOT the ingest stamp (`generated.by` equal to the ingest actor plus an `ingest_manifest`
touch curated or promoted files. If a generated filename collides with an existing file that reference, §7) and MUST NOT touch curated or promoted files. If a generated filename
does NOT carry the stamp, materialization MUST fail — never overwrite curated content. collides with an existing file that does NOT carry the stamp, materialization MUST fail —
never overwrite curated content.
Index updating is idempotent and preserves curated links (§6). The stamp is unforgeable Index updating is idempotent and preserves curated links (§6). The stamp is unforgeable
against **accident**, not against **will**: an operator who hand-copies a generated file — against **accident**, not against **will**: an operator who hand-copies a generated file —
stamp and all — into curated content makes it indistinguishable from ingest-owned content, stamp and all — into curated content makes it indistinguishable from ingest-owned content,
@ -79,10 +81,11 @@ approved knowledge into. Two rules keep ingest and the learning loop apart:
- **No other writer may forge the stamp.** The stamp is the sole mark distinguishing - **No other writer may forge the stamp.** The stamp is the sole mark distinguishing
ingest-owned files from curated ones, so any authoring primitive that materializes a concept ingest-owned files from curated ones, so any authoring primitive that materializes a concept
file from **caller-supplied** frontmatter MUST reject a frontmatter carrying the *complete* file from **caller-supplied** frontmatter MUST reject a frontmatter carrying the *complete*
ownership stamp — `generated: true` together with an `ingest_manifest` reference — while ownership stamp — `generated.by` equal to the ingest actor together with an `ingest_manifest`
permitting either field alone (curated content may legitimately carry a single provenance reference — while permitting either field alone (curated content may legitimately carry a
field). The check is on the complete stamp, never on the individual field names, so a single provenance field). The check is on the complete stamp, never on the individual field
legitimate verbatim round-trip is preserved; it is a **validation, never a repair**. names, so a legitimate verbatim round-trip is preserved; it is a **validation, never a
repair**.
## 4. The ingest manifest (the contract) ## 4. The ingest manifest (the contract)
@ -211,7 +214,7 @@ that are never mixed — the same discipline as the two falsifiers.
| `source_query` | The query that fetched the content (whitespace-collapsed, §5). | | `source_query` | The query that fetched the content (whitespace-collapsed, §5). |
| `ingested_at` | The explicit timestamp argument, verbatim (§5). | | `ingested_at` | The explicit timestamp argument, verbatim (§5). |
| `ingest_manifest` | The manifest reference `{stem}@{hash16}` (§5). | | `ingest_manifest` | The manifest reference `{stem}@{hash16}` (§5). |
| `generated` | Literally `true` — the machine-generated marker (§1 honesty rule). | | `generated` | The inline mapping `{ by: process:okf-ingest, at: <ingested_at> }`. `by` is the fixed ingest actor this spec defines — a `process:` actor, never a producer's name (§1 framework-neutrality); it is what marks the file machine-generated (§1 honesty rule), since the key's mere presence does not (curated content may carry a `human:` actor). `at` repeats the `ingested_at` value verbatim. Quoting is NOT normative: frontmatter is parsed line-oriented (method spec §3), so a quote character would be part of the value. |
- OKF consumers preserve unknown frontmatter fields, so this layer rides through navigation - OKF consumers preserve unknown frontmatter fields, so this layer rides through navigation
and context rendering unchanged. and context rendering unchanged.
@ -272,7 +275,7 @@ spec §11 regime):
| Seam | The test MUST fail when… | | Seam | The test MUST fail when… |
|---|---| |---|---|
| Provenance stamping | a generated file no longer carries the §7 layer | | Provenance stamping | a generated file no longer carries the §7 layer |
| Stamp integrity (curated writers) | a caller-supplied frontmatter carrying the complete ownership stamp (`generated: true` with `ingest_manifest`) stops being rejected by the verbatim authoring path (§3) | | Stamp integrity (curated writers) | a caller-supplied frontmatter carrying the complete ownership stamp (`generated.by` equal to the ingest actor, with `ingest_manifest`) stops being rejected by the verbatim authoring path (§3) |
| Navigability | the generated bundle stops being consumable by the UNCHANGED bundle-navigation code, index links included | | Navigability | the generated bundle stops being consumable by the UNCHANGED bundle-navigation code, index links included |
| Verdict reservation | a manifest mapping to `type: verdict` (or the reserved filename namespace) stops being rejected | | Verdict reservation | a manifest mapping to `type: verdict` (or the reserved filename namespace) stops being rejected |
| Title link-safety | a `title` containing `[` or `]` stops being rejected fail-fast at manifest load (§4) | | Title link-safety | a `title` containing `[` or `]` stops being rejected fail-fast at manifest load (§4) |