# Changelog
## Unreleased
## 0.2.0.0 — 2026-08-07
### Added
- **Generated bundles target OKF v0.2.** The bundle root's `index.md` declares
`okf_version: "0.2"` and every concept records its producer in the v0.2
`generated` family (`generated.by: process:shikumi-okf`), which is what
`okf validate --strict` asks for since okf-core 0.5. `okf validate --strict
--profile profile/shikumi.dhall --profile-enforce` passes on the shipped
example bundle.
- `GenerateOptions`, `defaultGenerateOptions`, `defaultGeneratedBy`, and
`okfVersion02` in `Shikumi.Okf.Generate`. Build options by overriding
`defaultGenerateOptions` rather than as a record literal, so a field added in a
later release leaves the call site compiling. `generated = Nothing` writes no
provenance at all — this generator will not claim authorship on a caller's
behalf — and `okfVersion = Nothing` preserves whatever declaration the
destination already carries rather than walking a hand-migrated bundle back.
- `profile/shikumi.dhall` is now shipped as a Cabal `data-files` entry, so
installing this package also installs the profile its bundles are meant to
satisfy.
### Changed
- **BREAKING** Upgraded `okf-core` from `^>=0.3.0.0` to `^>=0.5.0.0`, the release
that implements OKF v0.2.
- **BREAKING** `generateBundle`, `writeProgramBundle`, `programConcept`, and
`appConcept` take a `GenerateOptions` where they took a `Maybe Text`
timestamp. Pass `defaultGenerateOptions` for the previous call shape; move a
timestamp you were passing into
`defaultGenerateOptions {generated = Just (Generated actor (Just t))}`.
The parameter could not simply be reinterpreted. It wrote the v0.1 `timestamp`
key, which OKF v0.2 supersedes with `generated`, and a bundle that declares
v0.2 while still carrying `timestamp` is reported by okf-core 0.5 as retaining
a superseded key. Generation still reads no clock: `generated.at` remains
caller-supplied and absent by default, so regenerating an unchanged manifest is
still byte-identical and the regenerate-and-diff CI check still works.
- **BREAKING** `profile/shikumi.dhall` targets OKF v0.2. It sets
`okfVersion = "0.2"` and `requireBundleVersion = Some "0.2"`, so a bundle that
declares no version — or an older one — is now a profile deviation. It replaces
the `timestamp` rule with a `generated` object rule constraining `by` (required,
`actor` format) and `at` (optional, RFC 3339 UTC). Because `allowUnknownFields`
is `False`, a stray `timestamp` is now reported as an undeclared key.
The descriptor needs `okf` `>=0.5` to load: `requireBundleVersion` and
`objectFields` do not exist in the 0.3 schema.
- **`profile/shikumi.dhall` imports the okf schema from a pinned URL** —
`https://raw.githubusercontent.com/shinzui/okf/v0.5.0.0/okf-core/dhall/package.dhall`
with a `sha256:` integrity hash — instead of the relative path
`../../../okf/okf-core/dhall/package.dhall` into a sibling checkout.
The relative path resolved against whatever happened to be in a developer's
working tree. That is how this descriptor silently stopped type-checking when
okf's schema moved ahead of the pinned `okf-core` release, and it could never
have worked for anyone installing this package from Hackage, where no sibling
checkout exists. The hash covers the fully resolved, normalized expression, so
it pins every transitive `defaults/*` and `mk/*` file too, and a moved tag
fails the load rather than changing the schema underneath the profile. Dhall
serves a hashed import from `~/.cache/dhall` once resolved, so only the first
load on a machine touches the network.
- The committed `example/out` bundle was regenerated: the root index gained its
version declaration and each concept gained `generated`.
### Fixed
- The test suite parses one Markdown document on the main thread before tasty
forks. `cmark-gfm`'s `commonmarkToNode` calls
`cmark_gfm_core_extensions_ensure_registered` inside `unsafePerformIO` on every
call, whatever extension list it is given, and that C function is not
thread-safe: two threads reaching it at once make `cmark_register_node_flag`
print `flag initialization error` and `abort()` the process. okf-core 0.5 made
this reachable by enabling footnotes and routing all three of its parse sites
through one options list, so validating a bundle now parses far more Markdown
than it used to, and this suite runs with `-N`. The result was a reproducible
SIGABRT partway through the run — not a test failure, so it reported as an
empty log rather than as a diagnosis.
This is a workaround for a defect in the `cmark-gfm` bindings
(`mori://kivikakk/cmark-gfm-hs`), not in okf or shikumi, and it protects only
this test suite. A consumer that reads OKF bundles from several threads can hit
the same abort; the durable fix is to make the registration thread-safe
upstream.
- The test suite now checks the real `profile/shikumi.dhall` instead of a Haskell
paraphrase of it. A new `Profile` group loads the descriptor (located through
`Paths_shikumi_okf.getDataFileName`, so it does not depend on the directory
`cabal` was invoked from), compiles it, and validates the generated bundle
against it under `PermissiveConformance` — the same mode
`okf validate --profile --profile-enforce` uses. A descriptor that stops
type-checking, stops compiling, or stops describing what the generator emits is
now a red test; previously it could rot unnoticed across releases, which is
exactly what had happened. The hermetic `Conformance` group it replaces asserted
the same conventions against an in-process copy and is gone.
- **Breaking for profile consumers.** The profile now checks what frontmatter
values *contain*, not only that keys are present. `type`, `title`,
`description`, and `resource` are declared `Cardinality.Scalar`, so a
list-valued `title` is a violation. `timestamp` is declared as a recommended
scalar with the `Rfc3339Utc` format, so a value like `yesterday` is a violation;
cardinality and format are checked in every validation mode, so declaring it
*recommended* buys the format check without demanding the key be present.
- **Breaking for profile consumers.** `allowUnknownFields = False` closes the
top-level key set. This cannot reject a generated document — a closed set still
always admits the six core OKF keys, which are exactly what the generator emits
— but a hand-added stray key in a generated bundle is now reported.
- **Breaking for profile consumers.** `resource` moved from the profile-wide
`recommended` list into each type's own `required` list and carries
`UriWithScheme "shikumi"`, so it is now required on both document kinds and its
value must parse as an absolute `shikumi://` URI. `tags` is recommended as a
`List` on `Shikumi Program` only.
- **Consequence for consumers.** `okf validate --strict` now reports a
missing-recommended `timestamp` on bundles generated without one. That is
correct for a strict authoring run: `timestamp` is optional by design, because
`generateBundle` takes it as an explicit argument and omitting it is what makes
regeneration byte-identical. Ordinary (non-`--strict`) validation is unaffected,
and the committed `example/out` bundle still validates and regenerates
byte-identically.
- Moved the `okf-core` bound from `^>=0.1.0.0` to `^>=0.3.0.0`, the newest release
on Hackage. No source changes: the producer API this package uses (`Okf.Bundle`,
`Okf.ConceptId`, `Okf.Document`, `Okf.Index`) is unchanged across both major
bumps, and the breaking changes in `0.2`/`0.3` are confined to the profile
compilation and validation API this package does not call.
- **Breaking for profile consumers.** Migrated `profile/shikumi.dhall` to the
`0.3.0.0` profile schema; reading it now requires `okf` `>=0.3`. The schema made
`frontmatter.required`/`recommended` `List FieldRule` instead of `List Text`,
added `description`, `allowUnknownFields`, and `idField` to `Profile`, and added
`description`, `frontmatter`, and `idPrefix` to `TypeRule`. The descriptor now
imports okf's published `dhall/package.dhall` entry point and uses
record-completion defaults (`::`) with the `mk.FieldRule` constructors, so later
additive, defaulted schema fields will not break it again.
- The migrated profile keeps its previous meaning exactly — closed types, the same
two required and two recommended keys, open frontmatter, no `idField`, and
default `Any` cardinality with no `format` — and now also documents each key and
concept type in prose, which the old schema had no field for. Checked with `okf`
`0.3.0.0` against the committed `example/out` bundle: `validate` and
`--profile-enforce` both exit 0 and regeneration stays byte-identical.
## 0.1.0.1 - 2026-07-05
### Changed
- Refreshed the internal `shikumi` bound for local builds against the `0.3`
series now that `okf-core` is available on Hackage.
## 0.1.0.0 - 2026-06-28
### Added
- Initial package scaffold (EP-31, Milestone 1): `Shikumi.Okf.Types` defining
`SomeProgram`, `ProgramDoc`, `ProgramManifest`, and `AppInfo`.
- Program rendering and bundle generation (Milestones 2–3): `Shikumi.Okf.Render`
(`renderProgramBody`) and `Shikumi.Okf.Generate` (`generateBundle`,
`writeProgramBundle`, and the per-concept builders), producing one `Shikumi App`
concept linking to one `Shikumi Program` concept per program.
- Shared OKF profile `profile/shikumi.dhall`, a worked `shikumi-okf-example`
executable, and the committed `example/out` bundle (Milestone 4). Verified with
the standalone `okf` CLI: `validate`, `--profile-enforce`, and `graph --json`.
- Model-call instructions in rendered bodies (Milestone 5): each `Predict` node's
signature instruction now appears under its model call, via the new core accessor
`Shikumi.Program.nodeInstructionsIndexed`.