Skip to content

Releases

Version 0.36.1

Security

  • The provenance gate reads a verified or generated event that spans lines, so a forged confirmation cannot hide in a multi-line flow layout. The hand-written readers in knowledge-provenance.sh and knowledge-registrar.yaml’s provenance job parsed a flow event only on one line. A verified: [ or a generated: { continued on the next line is valid YAML every parser reads as a confirmation, but the gate saw no event and let an unsigned human: actor through, where knowledge-report.sh and the Obsidian plugins trusted it. Both readers now accumulate a flow event to its closing bracket. Checks 13a and 22 cover it.
  • The provenance gate reads a concept behind a byte order mark or in CRLF line endings, so a forged confirmation cannot hide behind one either. The same two readers keyed on a bare --- first line: a leading BOM (\357\273\277) or a ---\r opener matched nothing, so the reader saw no frontmatter, read no events, and passed an unsigned human: event that every YAML parser strips the mark or the carriage return and reads. The readers now strip both before the opener, under LC_ALL=C so a gawk in a UTF-8 locale reads the three BOM bytes as bytes, not as one character the strip would miss. Conventions already strips a BOM in the shell, and silently strips CRLF, so the gate was the only guard against the CRLF form. Check 22 covers a BOM-prefixed and a CRLF forgery.
  • The unattended provenance check follows a renamed concept, so a person’s text cannot be rewritten under a new name. knowledge-provenance.sh --unattended read a rename as a delete and an add and compared each path with its copy at HEAD, so a concept a person authored, renamed and rewritten in one change had no HEAD copy at its new path and passed. The check now pairs a rename by git’s own detection and compares the bodies. Verified against a rename-plus-rewrite and a rename-only control.
  • The pen refuses a provenance or event key in any case, and a top-level event field. create and set denied verified, status and the rest only in lower case at the top level, so a set carrying Verified: or a top-level by: human: was written in, where the scheduled run’s own backstop grep then refused the whole run. The pen now matches those keys case-insensitively and refuses a top-level by, at and revision. Check 19 covers it.
  • The pen protects a curator’s send-back and will not glue a protected heading onto the line before it. A resolve or delete could remove a process:ktl-curator note, the form a send-back takes when the curator could not sign in, and an edit ending exactly at ## Open questions or the lokf:related marker merged that heading into the text. The pen now keeps such a note, and checks after each edit that a protected section is still there. Check 19 covers each.

Added

  • Check 22 holds the gate’s event reader to a real YAML parser. It builds a human event in every layout a person might write (block, single-line and multi-line flow, a sequence, a mapping, an offset timestamp, an empty list, behind a byte order mark, and in CRLF line endings) and asserts the gate flags an unsigned one exactly when a parser sees one. So a layout one reader skips and the other reads cannot return as a way past the gate.

Fixed

  • The report script reads every timestamp and event layout a YAML parser does. knowledge-report.sh dropped a +00:00 offset, so an edited concept read confirmed by a person and a confirmed one read edited since; dropped a multi-line verified list, so a confirmation read nobody has checked; counted an empty verified: [ ] as automation; and missed a concept behind a byte order mark. norm() now converts any offset across the day, month, year and leap years, and the reader accumulates a flow list or mapping and strips a BOM — byte-for-byte under LC_ALL=C, so a gawk in a UTF-8 locale reads the mark as bytes, not as a two-byte character it would leave in place. Check 20 covers each.
  • The report script counts an edited-since concept once, and reads a CRLF index.md, a successor-less retirement and a subfolder sidecar. A concept edited after its confirmation whose source then moved was listed both on the work list and under a source moved after that confirmation; it now sits once on the work list, since the edit already overtook the confirmation. base_iri is read through a carriage return and a byte order mark, a retirement whose newest deprecation line names no successor reads as plain retired, and changes reads a subfolder sidecar from the work-tree top. Checks 20 and 20a cover each.
  • The pen keeps a null value, writes atomically, scrubs a log line and a question, and clears a ./-led or #fragment index link on delete. A ~, NULL or empty value no longer flips to null. A write that fails partway leaves the bundle unchanged, each file staged beside its target and put in place only once all are written. A log line and a question are scrubbed by Unicode category, as the hand-off is. And delete now takes a link written with a ./ lead or a #fragment out of a list of links, or refuses a sentence that holds it, rather than leaving it to dangle. Check 19 covers each.
  • ktl-prose skips an indented code block, reads a prose line that opens with an inline HTML tag, keeps an inline tag and a hard line break, reads a marker only where it opens a block, and notes a change of a fifth either way. An indented code block is code, so no style rule reads it. A prose line that opens with an inline tag is read with the tag masked, not skipped whole. A changed inline tag or a dropped hard line break is now reported, and a number that begins a wrapped line is checked as a fact, not a list number. The growth and shrink notes fire at a fifth, up or down, with no word floor. Check 18 covers each. (A rewording that swaps two facts from the same set is still passed by the token comparison and left to the reviewer, since the same comparison must pass a legitimate reordering of clauses.)
  • The registrar scopes rule 14 to the pull request’s merge-base, the feedback script rejects a . path segment, and both read login characters the same in every locale. The validate job passed base.sha, where provenance uses the merge-base, so a commit the base branch gained after the pull request opened could read as the pull request’s; both now use the merge-base. knowledge-feedback.sh --concept rejected .. but not playbooks/./draft.md, which the report then never matched. Both scripts’ login checks now set globasciiranges, a no-op where the shell lacks it. Check 12a covers each.
  • Contract check 15 reads the pinned skill path from the commit the pin records, not only from the tag ref. It used to skip when the tag was not on the clone, which on the scheduled, tag-less checkout was always; it now resolves the recorded commit and reads the path from it, and the tag-agreement half says whether that commit is a real object when the tag is absent. A fixture stages an untagged commit and reads the path from it.
  • The layout tests no longer flake on a SIGPIPE race, isolate their git config, and leave no temporary files behind. A large sed piped into grep -q, which exits on its first match, could take SIGPIPE and fail the check under pipefail; the sections are captured first. The fixtures run under an isolated git config, so a global commit.gpgsign=true no longer signs them, and the extracted workflow steps write under the test’s own working directory.