feat(project-brain): define OKF schema in SKILL.md + shared conversion script - #205
Merged
Conversation
Resolves the design-pass questions #195 flagged as open: type: enum per directory role, ADR status remapped to draft/stable/deprecated, wikilink migration folded into scope, whole-brain-as-one-bundle, generated:/verified: with conservative non-fabricated provenance, and the shared-conversion-script approach for the mechanical parts of the migration. Also adds two CONTEXT.md glossary entries (OKF bundle, OKF concept). Refs: AB#196
…n script Per docs/adr/adopt-okf-for-project-brain-markdown.md: - SKILL.md documents the type: enum, per-type frontmatter shape, the [[wikilink]] -> markdown-link convention, and links the ADR - new scripts/convert-to-okf.ps1: the shared mechanical conversion (#197-204 all run this) — wikilink rewrite, type:/stale_after: insertion, verified: [] insertion (adr/research), generated.at provenance from git log --diff-filter=A (omitted, never guessed, when git history has none); idempotent - Pester tests covering both wikilink forms, git-log-present/absent provenance, and idempotency Closes #196 Refs: AB#196
…es [#f205-6]
SKILL.md's frontmatter-shape table documented generated: { by, at }
unconditionally; a backfilled file may legitimately carry { at } only
when original authorship can't be attributed. Clarified in SKILL.md
and the ADR so a conformance check against either doc doesn't flag
every migrated file.
Refs: AB#196
…rgets [#f205-2, #f205-3] Convert-Wikilinks double-appended .md onto targets already ending in .md and folded #anchor fragments into the filename before appending .md, both breaking the resulting link. It also ran over the raw whole-file text, so it could rewrite wikilink-looking text inside inline code, fenced code, or frontmatter. Added Format-WikilinkTarget to strip an existing .md suffix and re-append a #fragment after .md instead of before. Split the body on code spans/fences before transforming (prose only), and reordered ConvertTo-OkfFile to run the transform on the frontmatter-split body so frontmatter is never touched. 7 new tests, 17/17 green. Refs: AB#196
stale_after was only inserted when absent, so a later STATUS.md edit to updated: was never reflected on rerun -- the old stale_after value stayed in place, understating or overstating staleness. Now always recomputed from the current updated: value and replaced in place when present. 2 new tests (recompute-on-change, no-op when updated: is unchanged), 19/19 green. Refs: AB#196
…ute [#f205-1] ConvertTo-OkfFile passed the absolute file path into Get-OkfType via a dead-alias variable, so its role-directory patterns (research/, adr/, templates/, ...) matched any ancestor segment outside the brain repo -- a brain checked out under a parent directory sharing a role name would mistype or suppress conversion of the whole tree. Now computes the path relative to the git root (Find-GitRoot) once and passes that through. 1 new test (a fixture nested under an adr-named ancestor, file actually in reports/), 20/20 green. Refs: AB#196
… omitting provenance [#f205-5] Get-GitAddedDate redirected stderr to $null and never checked $LASTEXITCODE, so a genuinely broken git log call (corrupt repo, bad pathspec) was indistinguishable from the legitimate 'no history for this file' case -- both silently omitted generated.at. Now distinguishes an unborn HEAD (a real empty repo, no commits yet -- the legitimate no-history case, still returns $null) from any other git failure (throws with repo + file context) via git rev-parse --is-inside-work-tree / --verify -q HEAD rather than parsing error text. 1 new test, 21/21 green. Refs: AB#196
…d CRLF [#f205-7, #f205-8] Get-FrontMatter's regex required a newline after the closing --- fence, so a file whose fence was the last line with no trailing newline fell through to being treated as body -- a second frontmatter block got prepended on rerun, the exact duplicate the script's idempotency docstring claims doesn't happen. Separately, the frontmatter rebuild always rejoined with a bare LF regardless of the file's actual line endings, so a CRLF file's frontmatter flipped to LF on every run while the body stayed CRLF -- mixed endings, and changed:$true forever instead of a true no-op. Fixed both: the closing-fence newline is now optional in the regex, and the rebuild detects and preserves the file's dominant line-ending style. 2 new tests, 23/23 green. Refs: AB#196
…ates/ exclusion [#f205-9] Closes 3 real coverage gaps against the script's documented behavior: a -WhatIf no-op assertion (SupportsShouldProcess was advertised but untested), a generated.by-absence assertion alongside the existing at:-presence test for backfilled files, and a templates/ exclusion test -- confirmed against the actual code that templates/ only excludes type-derived fields, not wikilink rewriting, and named the test to match that real behavior rather than an assumed one. 26/26 green. Refs: AB#196
…inks and delimiter run-length matching [#f205-2, #f205-3] Cycle-1's fixes for these findings were incomplete, caught on a cycle-2 re-review: - Format-WikilinkTarget still corrupted a bare local-heading link ([[#Heading]] -> [](/.md#Heading), empty label, malformed path). A target with no path segment before # isn't a cross-file link at all (OKF's link syntax only covers file references), so it's now left as a plain #fragment link instead of getting a .md path. - The code/frontmatter skip only recognized a literal triple-backtick fence and single-backtick span, missing tilde fences, longer fences wrapping a shorter example, and double-backtick spans. Replaced with run-length-aware matching (backreference to the opening delimiter's exact run length) via manual Matches + StringBuilder reconstruction, since multiple capture groups broke regex.Split's even/odd interleaving. 5 new tests (bare heading x2, tilde fence, 4-backtick-wrapping-3, double-backtick span), 31/31 green. Known pre-existing gap flagged, not fixed: an unclosed fence with no closing delimiter before EOF falls through as prose (same in the original code, unlikely in well-formed brain files). Refs: AB#196
…at into an incomplete block [#f205-12, #f205-13] f205-5's fix distinguished unborn-HEAD from a real git-log failure, but treated ANY failure of the verify-HEAD check as the legitimate unborn case -- a narrower version of the original silent-swallow bug survived inside its own fix. Now requires both symbolic-ref -q HEAD to succeed and verify -q HEAD to fail before treating it as unborn; anything else (corrupt HEAD content, a valid HEAD pointing at a corrupt branch ref) falls through to the existing throw. Separately, a file with an existing generated: block containing only by: (no at:) never got at: backfilled -- the insertion logic only handled the no-block-at-all case. Now detects an existing generated: mapping (block or inline form) missing at: and adds it in place. 5 new tests (corrupt HEAD content, corrupt branch-target ref, block-style and inline-style at: backfill, existing legitimate- unborn-HEAD case reconfirmed unregressed), 35/35 green. Refs: AB#196
…ets, split fragment at first # [#f205-16, #f205-17, #f205-18] Three more bugs in Format-WikilinkTarget found on a third independent review pass: - A wikilink fragment with spaces ([[a/b#Some Heading]], [[#My Heading]]) produced an unencoded space in the link destination, breaking CommonMark link parsing. Fragments are now slugified (lowercase, non-alphanumeric runs to a single hyphen, trimmed) to match how real Markdown renderers generate heading anchors -- a punctuation-only or empty fragment slugifies to nothing and is dropped rather than left as a dangling #. - A non-markdown asset target ([[image.png]], [[report.pdf]]) got .md wrongly appended after only a literal .md suffix was being stripped. Now any target already ending in a file extension is left untouched (no .md appended), while .md targets still have their existing suffix stripped and cleanly re-added -- not double-appended. - The fragment-split regex split at the LAST # in the target, so a nested-heading link ([[file#H1#H2]]) mis-split at the wrong point. Now splits at the first #, keeping the rest of the fragment intact. Necessarily updated two pre-existing tests whose expected output encoded the same fragment-casing bug (#Background -> #background, matching real GitHub anchor generation). 7 new tests, 42/42 green. Known accepted limitation, not fixed: the asset-extension check is a generic "ends in a dot-suffix" heuristic, so a multi-dot page name with no real extension would misclassify as an asset -- real brain filenames don't use multi-dot names, and a hardcoded extension allowlist would be speculative complexity beyond what this finding asked for. Refs: AB#196
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Defines the OKF v0.2 schema for
project-brainmarkdown perdocs/adr/adopt-okf-for-project-brain-markdown.md, and builds the shared conversion scriptthe eight migration tickets (#197-204) all run instead of hand-formatting the same transform.
What changed
ai-agents/skills/project-brain/SKILL.md: documents thetype:enum, the frontmattershape per type, the
[[wikilink]]→ markdown-link convention, and links the ADR.ai-agents/skills/project-brain/scripts/convert-to-okf.ps1(new): rewrites both wikilinkforms, inserts
type:/stale_after:frontmatter, adds an emptyverified: []onadr/research files, and derives
generated.atfrom the file's own git add-commit,omitting it entirely when git history has none rather than guessing today's date.
Idempotent.
tests/convert-to-okf.Tests.ps1(new): covers both wikilink forms, the git-log-presentand git-log-absent provenance cases, and idempotency.
The two registered brain repos'
templates/{core.md,STATUS.md,adr.md}and rootindex.md(
okf_version: "0.2") are updated separately, committed directly in their own repos perproject-brain's update contract (no PR flow there):E:\Personal Projects\brain:fcd96f1E:\HollardInsuranceRetail\brain:465a8b3Verify
Closes #196.