Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
98 changes: 50 additions & 48 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,43 @@ All notable changes to this project are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [0.6.0] - 2026-08-05

### Added
- **Index gaps can be reported instead of written** ([#15](https://github.com/MartinForReal/okf-enforcer/issues/15)).
Setting **Incomplete index.md** to *Report in the vault scan* makes a vault
scan warn where a folder has no `index.md` and where an existing one doesn't
list a note
anywhere in the file — and write nothing. A note counts as listed under
whatever heading, in whatever order, and in whatever grouping its author
chose, so a listing kept by hand doesn't read as incomplete merely for not
looking generated. Both findings are warnings: §8 makes an index optional and
§11 forbids failing a bundle for a missing one.

This comes from the closing comment on
[#8](https://github.com/MartinForReal/okf-enforcer/issues/8) — a vault that
writes its own indexes for readability can't use generation, because
generation writes a shape the vault didn't choose, but still wants to be told
when a listing has fallen behind.

- **The note you have open is listed in the report pane.** Opening a note now
puts its warnings and errors in a section of their own at the top of the
pane, listed open rather than behind a click. Opening a note has always
re-validated it, but the verdict went to the status bar alone — a count, with
the detail in a tooltip — while the pane went on showing whatever the last
vault scan had found, every row collapsed. Now the note in the editor is in
front of you whether or not it happened to be failing when that scan ran, and
whether or not a scan has ever run. A note with nothing wrong says so rather
than leaving the section blank, and a rescan or a **Fix all** re-reads the
section from the same pass, so it can't sit there contradicting the list
below it. An `index.md` carries its folder's §8 gap findings there too: a
scan files those against the index's path, but only reaches them by walking
the folder tree, so opening one would otherwise make it the single file the
plugin under-reports — clean in the editor, flagged in the list below. The
status bar counts them for the same reason. The active note is deliberately
kept apart from the scan results rather than merged into them: those count
the vault, and one note's verdict arriving between scans would leave the
summary chips describing a vault nobody scanned.

### Changed
- **The settings tab asks 18 questions instead of 29**
Expand Down Expand Up @@ -46,53 +82,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
open-time check is now stated rather than implied. It is what the report
pane's active-note section reads, so gating it would only make that section
go stale behind the tab.

### Removed
- **Three settings that did nothing.** `warnBrokenLinks` had no read sites at
all — it was in the settings type and the defaults, and nowhere else.
`checkReservedFiles` and `promptVersionBumpOnMigrate` had been gone from the
source for some time but lived on in every vault's `data.json`, because
loading merged saved data over the defaults wholesale and wrote unknown keys
straight back out. Loading now keeps only fields that still exist, so a
dropped setting ages out of the vault instead of persisting forever.

### Added
- **Index gaps can be reported instead of written** ([#15](https://github.com/MartinForReal/okf-enforcer/issues/15)).
Setting **Incomplete index.md** to *Report in the vault scan* makes a vault
scan warn where a folder has no `index.md` and where an existing one doesn't
list a note
anywhere in the file — and write nothing. A note counts as listed under
whatever heading, in whatever order, and in whatever grouping its author
chose, so a listing kept by hand doesn't read as incomplete merely for not
looking generated. Both findings are warnings: §8 makes an index optional and
§11 forbids failing a bundle for a missing one.

This comes from the closing comment on
[#8](https://github.com/MartinForReal/okf-enforcer/issues/8) — a vault that
writes its own indexes for readability can't use generation, because
generation writes a shape the vault didn't choose, but still wants to be told
when a listing has fallen behind.

- **The note you have open is listed in the report pane.** Opening a note now
puts its warnings and errors in a section of their own at the top of the
pane, listed open rather than behind a click. Opening a note has always
re-validated it, but the verdict went to the status bar alone — a count, with
the detail in a tooltip — while the pane went on showing whatever the last
vault scan had found, every row collapsed. Now the note in the editor is in
front of you whether or not it happened to be failing when that scan ran, and
whether or not a scan has ever run. A note with nothing wrong says so rather
than leaving the section blank, and a rescan or a **Fix all** re-reads the
section from the same pass, so it can't sit there contradicting the list
below it. An `index.md` carries its folder's §8 gap findings there too: a
scan files those against the index's path, but only reaches them by walking
the folder tree, so opening one would otherwise make it the single file the
plugin under-reports — clean in the editor, flagged in the list below. The
status bar counts them for the same reason. The active note is deliberately
kept apart from the scan results rather than merged into them: those count
the vault, and one note's verdict arriving between scans would leave the
summary chips describing a vault nobody scanned.

### Changed
- The report pane groups findings by the folder they sit in. A row used to be a
bare file name, which said nothing about which of two same-named notes had
failed and nothing at all about an index finding — those name `index.md`.
Expand All @@ -108,6 +97,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
It was always shown and silently did nothing otherwise, which a gap report —
which names the `index.md` a folder hasn't got — would hit every time. It is
also left off the active-note section, which describes a note already open.
- The default **Actor for `generated.by`** is now `okf-enforcer/0.6`, tracking
the minor line as it has since 0.3.0. This is a default: if you have ever
saved settings, your existing actor is kept as written.

### Removed
- **Three settings that did nothing.** `warnBrokenLinks` had no read sites at
all — it was in the settings type and the defaults, and nowhere else.
`checkReservedFiles` and `promptVersionBumpOnMigrate` had been gone from the
source for some time but lived on in every vault's `data.json`, because
loading merged saved data over the defaults wholesale and wrote unknown keys
straight back out. Loading now keeps only fields that still exist, so a
dropped setting ages out of the vault instead of persisting forever.

### Internal
- The listing a folder's contents call for, and the write of that listing, are
Expand Down Expand Up @@ -558,6 +559,7 @@ Initial release.
- Batched, non-blocking scan/fix queue with an inline progress bar for large vaults.
- Settings for automation toggles, batch size, warning rules, and excluded folders.

[0.6.0]: https://github.com/MartinForReal/okf-enforcer/releases/tag/0.6.0
[0.5.0]: https://github.com/MartinForReal/okf-enforcer/releases/tag/0.5.0
[0.4.1]: https://github.com/MartinForReal/okf-enforcer/releases/tag/0.4.1
[0.4.0]: https://github.com/MartinForReal/okf-enforcer/releases/tag/0.4.0
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Clicking the status-bar item auto-fixes the active note and, if a required field
Configure under **Settings → OKF Enforcer**:

- **Default type for auto-fix** — value inserted into `type` when fixing notes that lack it.
- **Default actor for `generated.by`** — the actor recorded when auto-fix adds a `generated` block (e.g. `okf-enforcer/0.5` or `human:<id>`). It goes into an inline YAML mapping, so it cannot contain a comma.
- **Default actor for `generated.by`** — the actor recorded when auto-fix adds a `generated` block (e.g. `okf-enforcer/0.6` or `human:<id>`). It goes into an inline YAML mapping, so it cannot contain a comma.
- **On save** — what an edit to the active note triggers: **Do nothing**, **Check the note** (validate it and update the status bar), or **Check and fix** (also insert the missing `type`, `title`, and `generated`). Whichever this is set to, a note is always validated when you *open* it — that verdict is what the status bar and the report pane's active-note section show.
- **Automation** — **Scan vault on startup** and **Auto-migrate to latest OKF on fix**. The latter is on by default and lets ordinary auto-fix apply the v0.1 → v0.2 migrations; turn it off to keep them behind the explicit command, since a migration rewrites what you wrote.
- **Incomplete index.md** — what to do about a folder whose §8 listing is missing or out of date:
Expand Down
8 changes: 4 additions & 4 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T/;
var WARNABLE_FIELDS = ["title", "description", "generated", "tags"];
var DEFAULT_SETTINGS = {
defaultType: "Concept",
defaultActor: "okf-enforcer/0.5",
defaultActor: "okf-enforcer/0.6",
// `tags` left out: §4.1 recommends the other three, and the spec never asks
// for tags.
warnMissingFields: ["title", "description", "generated"],
Expand Down Expand Up @@ -1090,7 +1090,7 @@ function applyFixes(path, content, issues, settings, includeMigrations = false)
);
if (fixes.size === 0) return { content, applied };
const nowIso = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
const actor = settings.defaultActor || "okf-enforcer/0.5";
const actor = settings.defaultActor || "okf-enforcer/0.6";
const title = basename(path);
const split = splitFrontmatter(content);
if (!split.hasFm) {
Expand Down Expand Up @@ -2430,10 +2430,10 @@ var OkfSettingTab = class extends import_obsidian3.PluginSettingTab {
},
{
name: "Default actor for `generated.by`",
desc: "Actor written when auto-fix adds a `generated` block (\xA77). Use `<producer>/<version>` (e.g. `okf-enforcer/0.5`) or `human:<id>`. Avoid commas \u2014 the block is written as inline YAML.",
desc: "Actor written when auto-fix adds a `generated` block (\xA77). Use `<producer>/<version>` (e.g. `okf-enforcer/0.6`) or `human:<id>`. Avoid commas \u2014 the block is written as inline YAML.",
control: (row) => row.addText(
(t) => t.setValue(s.defaultActor).onChange((v) => {
s.defaultActor = v.trim() || "okf-enforcer/0.5";
s.defaultActor = v.trim() || "okf-enforcer/0.6";
save();
})
)
Expand Down
4 changes: 2 additions & 2 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1306,11 +1306,11 @@ class OkfSettingTab extends PluginSettingTab {
},
{
name: "Default actor for `generated.by`",
desc: "Actor written when auto-fix adds a `generated` block (§7). Use `<producer>/<version>` (e.g. `okf-enforcer/0.5`) or `human:<id>`. Avoid commas — the block is written as inline YAML.",
desc: "Actor written when auto-fix adds a `generated` block (§7). Use `<producer>/<version>` (e.g. `okf-enforcer/0.6`) or `human:<id>`. Avoid commas — the block is written as inline YAML.",
control: (row) =>
row.addText((t) =>
t.setValue(s.defaultActor).onChange((v) => {
s.defaultActor = v.trim() || "okf-enforcer/0.5";
s.defaultActor = v.trim() || "okf-enforcer/0.6";
save();
})
),
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "okf-enforcer",
"name": "OKF Enforcer",
"version": "0.5.0",
"version": "0.6.0",
"minAppVersion": "1.7.2",
"description": "Validate and enforce the Open Knowledge Format (OKF v0.2): required type frontmatter, provenance/trust/lifecycle families, Attested Computation concepts, index.md/log.md structure, quick-fixes, v0.1→v0.2 migration, and a vault-wide report.",
"author": "MartinForReal",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "okf-enforcer",
"version": "0.5.0",
"version": "0.6.0",
"description": "Validate and enforce the Open Knowledge Format (OKF v0.2) in Obsidian.",
"main": "main.js",
"scripts": {
Expand Down
6 changes: 3 additions & 3 deletions validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export interface OkfSettings extends PortentSettings {
defaultType: string;
/**
* Actor written to `generated.by` when auto-fix creates a `generated` block
* (§5.2, §7). Follows the actor convention — e.g. `okf-enforcer/0.5` for the
* (§5.2, §7). Follows the actor convention — e.g. `okf-enforcer/0.6` for the
* plugin, or `human:<id>` if a person wants edits attributed to them.
*/
defaultActor: string;
Expand Down Expand Up @@ -139,7 +139,7 @@ export const WARNABLE_FIELDS = ["title", "description", "generated", "tags"] as

export const DEFAULT_SETTINGS: OkfSettings = {
defaultType: "Concept",
defaultActor: "okf-enforcer/0.5",
defaultActor: "okf-enforcer/0.6",
// `tags` left out: §4.1 recommends the other three, and the spec never asks
// for tags.
warnMissingFields: ["title", "description", "generated"],
Expand Down Expand Up @@ -1608,7 +1608,7 @@ export function applyFixes(
if (fixes.size === 0) return { content, applied };

const nowIso = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
const actor = settings.defaultActor || "okf-enforcer/0.5";
const actor = settings.defaultActor || "okf-enforcer/0.6";
const title = basename(path);
const split = splitFrontmatter(content);

Expand Down
3 changes: 2 additions & 1 deletion versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"0.3.0": "1.7.2",
"0.4.0": "1.7.2",
"0.4.1": "1.7.2",
"0.5.0": "1.7.2"
"0.5.0": "1.7.2",
"0.6.0": "1.7.2"
}
Loading