Module: OKF::Pro::Guards
- Defined in:
- lib/okf/pro/guards.rb
Overview
The trust rules. Both are PreToolUse, so they deny the write rather than
complain after it, and both scope through Target first: verified: and
the journal calendar are bundle vocabulary, and a guard that fired on
them anywhere — the README quoting the frontmatter format, a scratch
file under .tmp/ — was a false block that trains people to switch the
guard off.
Constant Summary collapse
- ATTESTATION =
The block-style spelling, and the fast path. It is NOT the whole rule: YAML frontmatter may be a flow mapping —
{type: Briefing, verified: 2026-08-01}— which the okf reader parses as a real attestation and this pattern never sees. A gate that reads a narrower grammar than the parser it defends is a gate with a door cut into it, so the flow spelling gets its own pattern below. Patterns rather than a YAML parse, because the added text of an Edit is a FRAGMENT — it need not be valid YAML, or even contain the fences — and a parser that failed on a fragment would decline to see the very attestation it was called to catch. /^[[:blank:]]*verified[[:blank:]]*:/.freeze
- FLOW_ATTESTATION =
verifiedas a key ANYWHERE in a flow mapping — after{, after a comma, at any nesting. Matched against the added text only when it actually contains a flow mapping, so prose that happens to say "verified:" in a sentence does not trip it. /[{,][[:blank:]]*['"]?verified['"]?[[:blank:]]*:/.freeze
- JOURNAL_ENTRY =
%r{\Ajournal/(\d{4}-\d{2}-\d{2})\.md\z}.freeze
Class Method Summary collapse
-
.attests?(text) ⇒ Boolean
Every spelling of the attestation the okf reader would accept.
-
.guard_verified(event) ⇒ Object
verified:is the owner's signature, and an agent that can type it unchecked can forge it. -
.journal_guard(event, today: Date.today) ⇒ Object
A past day is a record.
Class Method Details
.attests?(text) ⇒ Boolean
Every spelling of the attestation the okf reader would accept. The test is deliberately generous: this gate ASKS, so a false positive costs one prompt and a miss costs a forged signature.
37 38 39 40 |
# File 'lib/okf/pro/guards.rb', line 37 def attests?(text) text = text.to_s ATTESTATION.match?(text) || FLOW_ATTESTATION.match?(text) end |
.guard_verified(event) ⇒ Object
verified: is the owner's signature, and an agent that can type it
unchecked can forge it. Everything downstream — the To-read line, the
briefing's standing, the audit — rests on that block meaning a person
actually read the source. This is the most load-bearing gate in the repo.
It asks rather than denies, because the invariant was never who holds the pen — it is who decided. The owner reviews with the agent and the agent promotes the change; this gate turns that write into an explicit owner approval, and the approval IS the attestation. Where nobody can approve — an unattended session — "ask" has no approver and the write is refused, which is the fail-closed floor the old outright denial had.
53 54 55 56 57 58 59 60 |
# File 'lib/okf/pro/guards.rb', line 53 def guard_verified(event) return [] if Target.for(event).nil? return [] unless attests?(event.added_text) { "ask" => "This edit writes 'verified:' — owner attestation. The agent is the scribe; " \ "your approval is the attestation. Approve ONLY if you have actually reviewed " \ "this content yourself. If you have not, deny — unverified is the truth." } end |
.journal_guard(event, today: Date.today) ⇒ Object
A past day is a record. Editing it does not correct history, it destroys
the one artefact that says what was known at the time — that stays a
flat refusal. Creating a missing past day is different, and it is the
owner's call, not the agent's: Rule 2's fallback is reconstructing
yesterday's missing entry, declared as reconstructed — but "the file
does not exist" alone would let an agent fabricate any date in the
past as quietly as filing a note, and the same guard would then defend
the forgery as history. So creation asks, exactly like verified::
interactive, the owner approves the reconstruction; unattended, no
approver, fail closed.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/okf/pro/guards.rb', line 72 def journal_guard(event, today: Date.today) target = Target.for(event) return [] if target.nil? match = target.rel.match(JOURNAL_ENTRY) return [] unless match return [] unless match[1] < today.to_s unless target.exist?(target.rel) return { "ask" => "This creates journal/#{match[1]}.md — a PAST day that has no entry. " \ "Approve ONLY if this is a declared reconstruction of a day you " \ "actually worked (Rule 2's fallback). A fabricated record is worse " \ "than a gap: this guard will defend whatever you approve as history." } end [ "BLOCKED — journal/#{match[1]}.md is a past day. Records are append-only; " \ "corrections go in today's entry, pointing back." ] end |