Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0e97643
docs(verify): design spec for okf verify, closing the audit loop
ncitnea Aug 28, 2026
9a08510
docs(verify): fix five defects found reviewing the spec against the code
ncitnea Aug 28, 2026
4ddf3f0
docs(verify): implementation plan, in six tasks
ncitnea Aug 28, 2026
f43f1a9
docs(verify): fix the plan against an independent audit
ncitnea Aug 28, 2026
1bb4bc9
docs(verify): rework the plan after an external review
ncitnea Aug 28, 2026
cd2b7bc
docs(verify): refuse a concept named twice, rather than collapsing it
ncitnea Aug 28, 2026
dd69b56
docs(verify): fix the plan and realign the spec after the external audit
ncitnea Aug 28, 2026
37d9b4f
docs(verify): report partial writes at every layer, not just in the core
ncitnea Aug 28, 2026
eba4b12
refactor(cli): ordered positionals and a stdin seam
ncitnea Aug 28, 2026
eea30f2
feat(core): RecordVerifications, the governed writer of verified
ncitnea Aug 28, 2026
b25553b
fix(core): make RecordVerifications' Records mean written, not prepared
ncitnea Aug 28, 2026
af43624
feat(cli): add the okf verify verb
ncitnea Aug 28, 2026
c11174c
test(cli): pin verify's partial-write reporting, defer writer constru…
ncitnea Aug 28, 2026
55e3bbc
test(verify): pin the verb's output with a golden
ncitnea Aug 28, 2026
c62539a
fix(verify): correct three inaccurate provenance/comment claims
ncitnea Aug 28, 2026
c170698
feat(agents): expose okf_verify as a write tool
ncitnea Aug 28, 2026
196b8d2
fix(agents): close okf_verify's records-swallow gap, replaces coverag…
ncitnea Aug 28, 2026
6fdb01d
docs(verify): document the verb, the tool and what a stamp does not p…
ncitnea Aug 28, 2026
847073b
docs(verify): correct stale tool counts on the Agents and MCP doc pages
ncitnea Aug 28, 2026
f10f2a9
docs(verify): fix producer-grade overclaim, worklist overclaim, and a…
ncitnea Aug 28, 2026
37d0807
docs(verify): fix seven false/imprecise claims in prose, comments and…
ncitnea Aug 28, 2026
ce683a0
fix(verify): refuse a control-bearing actor at the write gate
ncitnea Aug 29, 2026
b95664b
fix(yaml): raise an OkfException when the emitter's depth guard trips
ncitnea Aug 29, 2026
55e75ed
fix(cli): make verify's stdin form idempotent and validate flags first
ncitnea Aug 29, 2026
c63432f
test(verify): close three gaps a source mutation walked through
ncitnea Aug 29, 2026
97a2e52
docs(verify): correct the actor forms and scope three overclaims
ncitnea Aug 29, 2026
5d30257
docs(verify): correct the agent: actor form at its source
ncitnea Aug 29, 2026
354dc6d
Merge origin/dev into worktree-okf-verify
ncitnea Sep 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,40 @@ and this project adheres to
`--stale`, `--trust`, `--status`, `--type`, `--as-of` and `--json`. Backed by
the new `ConceptAudit` in the core library and exposed to agents as the
read-only `okf_audit` tool.
- **`okf verify <bundle> <id>… --by <actor>`** — the verb that answers what
`okf audit` asks about trust: it records a review (§5.2) by adding, or
from the same actor replacing, a `{by, at}` entry in each named concept's
`verified` list, so — for a `human:` actor — the concept clears audit's
trust-filtered (`--trust unverified`/`unverified,machine-confirmed`)
selection. A `process:` or `<producer>/<version>` actor is accepted symmetrically (§7) but
only moves the concept from `unverified` to `machine-confirmed`, which
that same filter still selects. Verification only moves the trust
dimension (§5.3) — it never touches
`stale_after`, so a just-reviewed concept can still appear in `okf audit`'s
*default* worklist, which selects on staleness alone. `<id>…` also accepts
a single `-`, reading concept ids from standard input, so
`okf audit … --trust unverified | cut -d' ' -f1 | okf verify … --by
human:ada -` closes the loop in one line. An empty stream on that pipeline
is "nothing to do", not an error: `verify -` writes nothing and exits 0,
matching `audit`'s own empty-worklist exit, so the loop stays idempotent
and safe under `set -e` when the bundle needs no attention. Naming no
concept at all (`okf verify <bundle>`) is still an error. An actor carrying
a control character is refused by `RecordVerifications` itself, so a `--by`
value can never forge a line in the verb's own line-oriented output; reading
an actor out of an existing bundle (`Actor.Parse`, `Trust.DeriveTier`) stays
permissive, as it must. `--dry-run` shows what would be
recorded without writing; `--at <yyyy-MM-ddTHH:mm:ssZ>` overrides the
default of "now" (a bare date, an offset, or fractional seconds are
rejected). A batch is validated (existence, §11 conformance, no duplicate id) before the
first write, but writing several files cannot be atomic — a mid-batch I/O
failure still leaves the earlier concepts stamped, and is reported as
such. Backed by the new `BundleConceptWriter.RecordVerifications` in the
core library — the single governed writer of `verified` — and exposed to
agents as the `okf_verify` tool. **A `verified` stamp is a dated
declaration, not a proof**: it cannot and does not authenticate the
signer's identity, nor confirm anyone read the concept. Credibility comes
from where the stamp lands — a diff a human reviewed — never from
inferring one out of a PR approval.
- **A new `okf-render <bundle> --out <dir>` binary** generates a
self-contained, browsable HTML site from a bundle: one page per concept
(frontmatter table + rendered body), a generated index, navigable
Expand Down Expand Up @@ -300,6 +334,27 @@ and this project adheres to
are unaffected. The same rewrite also fixes a token consumed as a flag's value
still counting as a flag: `okf audit b --type --stale` no longer sets the
stale filter.
- **`OkfCli.Run` gains a `TextReader stdin` parameter** (now
`Run(args, stdin, stdout, stderr)`), so `verify -` can read concept ids
from standard input without every other verb paying for a blocking read.
This is a breaking change to a public API signature, but it breaks no
external caller: `OKF4net.Cli` is the only project under `src/` with no
`PackageId`/`IsPackable` — it ships only as the `okf` binary, never
published as a library — and the sole call site outside `Program.cs` is
the test suite's `TestPaths.cs`, updated alongside it.
- **`--` now keeps the positionals given before it, instead of discarding
them.** The separator used to let the token right after it take the single
positional slot outright, so `okf <verb> a -- b` resolved to `b`; verbs now
keep every positional in order, `--` included, so the same invocation
resolves to `a`. This is what makes `verify <bundle> <id>…`'s multiple
positionals possible — a single "the positional" slot could never have
held more than one concept id.
- **A lone `-` is now a positional argument, not a flag.** The flag scan
previously matched any token starting with `-`, including the bare
character, so `-` was silently absorbed as a valueless, meaningless flag.
It now falls through to the positional list, which is what lets
`okf verify <bundle> -` mean "read concept ids from standard input" — the
POSIX convention — instead of being swallowed before `verify` ever sees it.
- **`okf validate` gains `--as-of <YYYY-MM-DD>`**, pinning the date its §5.5
staleness warning is evaluated against. `BundleValidator.Validate` already
accepted a clock, but the verb exposed no way to set one, so its
Expand Down Expand Up @@ -359,6 +414,22 @@ and this project adheres to

### Fixed

- **`YamlEmitter`'s nesting guard now throws `YamlEmitException`** (an
`OkfException`, like the parser's `YamlParseException`) instead of a bare
`InvalidOperationException`. The parser enforces its 1000-level cap with two
independent counters — one for block nesting, one for flow — while the
emitter has a single counter covering both, so a frontmatter mixing the two
can parse and then fail to re-emit. That exception matched no catch filter
in the library: it escaped `BundleConceptWriter`'s errors-as-data contract,
threw out of the `okf_verify` tool into its host, and killed the CLI with a
stack trace. Every existing filter already covers `OkfException`, so the
failure is now data on all three paths. Reconciling the two counters with
the one is a separate, read-path question and is left open.
- **`okf` reports an unanticipated library failure as `error: <message>`,
exit 1**, instead of a stack trace and exit 127. `OkfCli.Run` caught only
its own internal `CliOperationException`; it now also catches
`OkfException`, the library's expected-error base. Applies to all eight
verbs. An unexpected BCL exception still crashes loudly, on purpose.
- **`generated.by` is an actor again, and the engine versions moved to
`generated.engines`.** §5.2 makes that field an actor and §7 defines an actor as
exactly one of `<producer>/<version>`, `human:<id>`, `process:<id>`. It was written
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ Requires .NET SDK 10.0+. CI (ci.yml) runs build+test on Linux/Windows/macOS, `do
- **`src/OKF4net/`** — the library. One file per spec concern, following the OKF reference implementation's structure: `ConceptId` (§2), `Bundle` (§3, permissive loading — parse failures go into `Bundle.ParseErrors`, never abort), `OkfDocument`/`Frontmatter` (§4), `Links.cs`/`LinkScanner` (§6, legacy citations §13.1), `IndexGenerator` (§8), `ChangeLog` (§9), `Validate.cs`/`BundleValidator` (§11). The README has the full spec-section → type mapping table.
- `ConceptSearch` — the single shared full-text scorer (title x3, tags/description x2, body x1) used by both `OKF4net.Agents` (`okf_search`/context provider) and `OKF4net.Catalog` (`OkfBundleKnowledgeSource`, `FileMemoryStore`); do not fork a second scorer in either consumer.
- `Audit.cs` — `ConceptAudit`, the single shared corpus-level query behind both `okf audit` and the `okf_audit` tool; the two renderers are deliberately separate (the CLI's bytes are golden-locked), but the computation and the `AuditVocabulary` labels must not be forked.
- `BundleConceptWriter.RecordVerifications` — the single governed writer of the §5.2 `verified` field, behind both `okf verify` and the `okf_verify` tool; do not fork a second write path. A stamp it writes is a dated declaration, not a proof (it cannot authenticate `--by`) — see the README's `okf verify` section for the full caveat.
- `Yaml/` — the documented YAML *subset* (scalars, lists, shallow maps, block/flow, `|`/`>`); it deliberately rejects anchors/tags/multi-docs with clear errors. `Frontmatter` wraps an order-preserving `YamlMapping` with typed getters rather than a fixed DTO, so unknown producer keys survive round-trips.
- `Internal/LfLines.cs` — the single shared line splitter (splits on `\n` only, stripping a preceding `\r`). Use it anywhere `\n`-based line splitting matters; do not reintroduce private copies.
- `Internal/ReparsePoints.cs` — internal symlink/junction detection; `OKF4net.Catalog` is granted `InternalsVisibleTo` so it can reuse this seam rather than duplicating a platform-specific implementation.
- **`src/OKF4net.Cli/`** — the `okf` binary (`validate`/`audit`/`info`/`index`/`graph`/`parse`/`fmt`), published Native AOT (`PublishAot`, `InvariantGlobalization`). All logic lives in `OkfCli.Run(args, out, err)` so tests invoke it in-process without spawning a process. Carries no reference to `OKF4net.Viewer`: static-site generation (`render`) was split out into `src/OKF4net.Render/` so this CI-facing validator does not carry that vendored JavaScript.
- **`src/OKF4net.Cli/`** — the `okf` binary (`validate`/`audit`/`verify`/`info`/`index`/`graph`/`parse`/`fmt`), published Native AOT (`PublishAot`, `InvariantGlobalization`). All logic lives in `OkfCli.Run(args, stdin, out, err)` so tests invoke it in-process without spawning a process; `stdin` is read only by `verify -` (concept ids, one per line), no other verb touches it, and it rides on the parsed `CliArgs` rather than widening the dispatch delegate seven other verbs would never use. Every verb is a `VerbSpec` in the `Verbs` table — usage, flag allowlists, per-verb help, positional arity (`Variadic`, set only by `verify`) and handler in one place, so a verb cannot be declared and left unreachable. Carries no reference to `OKF4net.Viewer`: static-site generation (`render`) was split out into `src/OKF4net.Render/` so this CI-facing validator does not carry that vendored JavaScript.
- **`src/OKF4net.Attestation/`** — zero-dep §10 attested-computation orchestration, referencing only `OKF4net`. Defines the host-plugged contracts (`IParameterBinder`, `IComputationExecutor`, `IAttester`, resolved per concept's `runtime` field through `IAttestationRuntimeRegistry`) and the value types that flow between them (`BoundComputation`, `Receipt`, `AttestationVerdict`, `AttestationContext`, `AttestationOutcome`); `AttestationOrchestrator.RunAsync` drives one run end to end (resolve → bind → execute → receipt-shape check → attest → gate on verdict + `stale_after`), errors-as-data, never writing a verdict back to the bundle (§10.6). Referenced by `OKF4net.Agents` to back `okf_run_computation`.
- **`src/OKF4net.Agents/`** — Microsoft Agent Framework layer exposing OKF bundle operations as function tools (e.g. `OkfBundleTools`) plus `OkfContextProvider`, an `AIContextProvider` that auto-injects budget-bounded bundle context and captures deterministic per-day memory concepts; the only project depending on `Microsoft.Agents.AI`.
- **`src/OKF4net.Catalog/`** — knowledge-catalog model and logic, referencing only `OKF4net` (BCL otherwise; zero `PackageReference`). Depended on by `OKF4net.Catalog.Hosting`. Each manifest source carries a `role` (`SourceRole`): `Knowledge` (read-only, searched by `IKnowledgeResolver`) or `Memory` (writable, scoped by a required `tier` — `session`/`user`/`tenant`, all three backed by `FileMemoryStore`, fed by `IMemoryStore`, never searched by the resolver); any other `role` string in `catalog.json` is rejected (`CatalogDiagnosticCode.IllegalRole`).
Expand Down
Loading