Documentation
¶
Overview ¶
Package ruleset is the typed model of a distilled ruleset: a set of Rules, each an imperative with a severity, a level, a rationale, a ✗/✓ example pair, and an optional ↦ source anchor. Render emits the canonical text form and Parse reads it back; the two round-trip. Parse handles the canonical form Render emits, not every hand-authored variation a distilled Markdown file may contain.
Index ¶
Constants ¶
const FormatVersion = 4
FormatVersion is the canonical-form major version this package writes and is the highest it can read.
Bump it only when the grammar itself changes -- not to record metadata identity.Hash already establishes, such as tool identity or scoring. A hash pins which bytes produced what, and a format version that accumulates the same facts becomes a second manifest.
**That prohibition read "not to record provenance" until version 4, and the wording was wider than its own reason.** The ground it gives is that identity.Hash covers the fact already, which is true of tool identity and untrue of a verification event: a hash establishes which bytes exist and cannot say who read them and agreed. Version 4 records exactly that, so the sentence was narrowed to what it argues for rather than bent. The "second manifest" warning stands and is still the right fear.
It is 4. Version 1 was the version reader itself, which changed no grammar; version 2 adds the ⚖ warrant marker; version 3 adds the Limitations: header and the ⊨ check marker, batched into one bump because each is a grammar change and shipping them apart would migrate every stored ruleset twice; version 4 adds the frontmatter block's verified key.
**Version 4 is a bump rather than a tolerated unknown key, and the alternative is worse.** An unmodelled verified: already parses without error and is then dropped by Render, so leaving the version at 3 would let an older tool round-trip a verified ruleset and lose a human's judgement with no error at all. That is the silent loss the block was introduced to convert into a loud refusal -- see readFrontmatter -- so a key a reader must model to preserve is a grammar change by this constant's own test.
A document is only *written* at a version when it uses something that version introduced -- see formatOf -- so every ruleset written before still renders byte-identically, which is the property the reader was shipped early to protect.
Variables ¶
This section is empty.
Functions ¶
func Render ¶
Render emits rs in the canonical text form. It is deterministic: the same Ruleset always renders byte-identically.
A Format of 0 renders as version 1, so a Ruleset built in Go without setting it is a valid v1 ruleset rather than a malformed one. Parse returns 1 for an undeclared file, so the two agree on what a version-less ruleset is.
Types ¶
type Rule ¶
type Rule struct {
Section string
Severity Severity
Level Level
Statement string
Rationale string
Bad string // the ✗ counter-example
Good string // the ✓ preferred form
SourceAnchor string // the ↦ source quote or section this rule derives from
// Warrant is the ⚖ record of a decision, for a rule no source can anchor. Its zero
// value means the rule was never adjudicated, which is the ordinary case.
Warrant Warrant
// Checks are the ⊨ predicates that decide whether this rule fires, and they exist so a
// rule can be known-answer tested against its own examples.
//
// A rule already ships both answers -- Bad is the case it must flag and Good the case
// it must not -- and carried no way to run itself against them, so nothing could tell a
// rule that discriminates from one that would fire on ordinary work. See Sound, which
// is the check these make possible; a rule with no checks is untested rather than
// unsound, and that is a different claim.
//
// Empty for every rule written before version 3, and Render emits nothing for it, so an
// existing document is untouched.
Checks []judge.Check
}
Rule is one atomic, mechanically applicable constraint.
type Ruleset ¶
type Ruleset struct {
Source string
Scope string
// Limitations is what this ruleset does not cover, and it is the counterpart to Scope
// rather than a second phrasing of it.
//
// A capability statement that will not say what it does not cover is an advertisement:
// rules distilled from one book and presented without that book's bounds read as rules
// for the whole subject. Scope alone cannot carry this, because a scope naming only what
// is included is exactly the shape being objected to.
//
// Empty is the ordinary case for every ruleset written before version 3, and Render
// omits the header entirely when it is empty -- so an existing document is untouched
// and does not suddenly declare a version it does not need.
Limitations string
// Format is the canonical-form major version this ruleset is written in. A file that
// declares none is 1, so the zero value reads correctly for every ruleset written before
// versioning existed -- unlike finding.Action, whose zero value had to mean "nobody
// judged", a missing format genuinely *is* version 1.
Format int
// Verified is the independent verification events attesting to this ruleset: who
// confirmed it, and when. It is OKF §5.2's list rather than a single trust tier, and
// deriving a tier from it belongs to a consumer -- see the verification package, which
// leaves the fold out for the same reason.
//
// **The events attest to the rules, not to the bytes.** identity.Hash pins bytes and a
// proof packet binds a ruleset to its source; neither can say a person read the rules
// and agreed, which is what this carries and why it is not derivable from content.
// The corollary is that an event outlives the text it attested to: nothing here
// re-checks it when a rule changes, so a consumer comparing an event against a later
// revision is reading a claim about an earlier one.
//
// Empty is the ordinary case for every ruleset written before version 4, and Render
// emits nothing for it, so an existing document is untouched.
Verified []verification.Event
Rules []Rule
}
Ruleset is a distilled set of Rules derived from one source.
type Severity ¶
type Severity string
Severity is how strictly a Rule is enforced.
Severity is how strictly a Rule is enforced.
type Unsound ¶ added in v0.29.0
type Unsound struct {
// Section identifies the rule, matching Rule.Section.
Section string
// Reason says which half of the known-answer pair failed.
Reason string
}
Unsound is one rule whose own examples do not exercise its checks.
func Sound ¶ added in v0.29.0
Sound reports the rules whose checks do not discriminate between their own examples.
A rule ships the two answers already: Bad is the case it must flag and Good the case it must not. Checks make those runnable, and this is the control that runs them -- every check must pass on Bad, and they must not all pass on Good. gnosis validates its pattern table this way and it caught a pattern whose own positive example did not match on the first run, which is the failure a rule set cannot find by reading itself.
**Soundness before completeness.** A rule that fires on ordinary work gets the tool switched off, so the negative case is the one that matters most and the one an author will not write unprompted.
**Deliberately not called from Parse, which is the plan's own correction.** Running predicates over a document while reading it would make a content defect present as an unparseable file: a rule whose regex is valid but whose example stopped matching would make the whole ruleset unreadable, and unreadable by the very tools that would report it. Parse reads bytes; this judges content; a caller runs both. That keeps gnosis's argument -- a callable check on the artifact rather than a unit test somebody has to remember to run -- without putting evaluation inside a parser.
A rule carrying no checks is **not** reported. It is untested, which is a different claim from unsound and belongs to whatever gate decides that rules must carry checks at all.
Requires: nothing; rs may hold no rules. Ensures: the result is in rule order, holds one entry per failing rule, and is empty
when every rule with checks discriminates; it is pure.
type Warrant ¶ added in v0.26.0
type Warrant struct {
// By is who decided, as one whitespace-free token: an address or a handle. The
// canonical form is positional, so a name with a space in it cannot be represented.
By string
// At is when, as a 2006-01-02 date.
//
// A string rather than a time.Time, which is the weaker choice by every rule except the
// one that governs here: parsing and re-formatting would silently rewrite 2026-8-27 as
// 2026-08-27, and byte-identical round-tripping is what the inert-render property and
// canonizer's drift check both rest on. Validity is enforced where the text is read --
// see Valid, and parseWarrant, which refuses a date it cannot parse.
At string
// Rationale is why, and it is required. A warrant is the only record of a decision that
// carries no other evidence, so a half-recorded one is worse than none: it looks like
// provenance while establishing nothing.
Rationale string
}
Warrant records who decided a rule, when, and why, for a rule no source can anchor.
**An adjudicated artifact is sourced differently, not unsourced.** When two rules conflict and a person picks one, the decision is knowledge present in neither source, so it can carry no source anchor and fails an anchor-requiring provenance check by construction -- while being the highest-value thing a review produces. gnosis states it most sharply: *"a decision that weighed two published positions names both, even though the decision appears in neither."* Three repositories derived that independently before it was written down once; a check that protects evidence must not reject the one artifact that cannot carry any.
The shape is deliberately smaller than the governance models that want it. No tiers, no co-signers, no reversal links: those belong to a consumer's authority model, and putting them in a shared kernel exports one consumer's governance to every other. The kernel carries the datum; the consumer keeps the decision about what to do with it -- the same split the manifest's test-prompts hash and skilllens' category names already use.
func (Warrant) Present ¶ added in v0.26.0
Present reports whether a warrant was recorded at all.
Distinct from Valid on purpose. Absent means the rule was never adjudicated, which is the ordinary case and no kind of defect; invalid means somebody recorded a decision badly.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package conflict finds decidable inconsistencies between the rules of a ruleset.
|
Package conflict finds decidable inconsistencies between the rules of a ruleset. |
|
Package distill generates the per-source distillation prompts: for each Markdown source under a tree it fills a template with links to the source and to the rules file it should produce, and writes a *_prompt.md beside the output directory.
|
Package distill generates the per-source distillation prompts: for each Markdown source under a tree it fills a template with links to the source and to the rules file it should produce, and writes a *_prompt.md beside the output directory. |
|
Package synthesize assembles distilled rulesets into a single synthesis prompt: it replaces a template's {{RULESETS}} marker with one <ruleset> block per input.
|
Package synthesize assembles distilled rulesets into a single synthesis prompt: it replaces a template's {{RULESETS}} marker with one <ruleset> block per input. |