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
95 changes: 77 additions & 18 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ them, so look for them first.
Every unit of content in a graded section of a skill is disposed of in
`grounding/<tier>/<skill>.md`. Nothing enters a skill unclassified.

A matrix disposes of ONE file. `SKILL.md` answers to
`grounding/<tier>/<skill>.md`, and every Markdown file under `references/`
answers to a matrix mirroring its path, such as
`grounding/standards/simplified-technical-english/references/examples.md`. The
row space is what forces that. `Our anchor` names a heading, two files in one
skill can carry the same heading, and a shared space let a row claim an
occurrence in the file nobody wrote it for while every cell still matched. The
file identity sits in the matrix's own path, where a filesystem holds it rather
than a cell, so no column moved and no digest changed. A graded file with no
matrix is refused, and so is a file under `grounding/` that grades no file any
skill ships. `references/` holds
Markdown, because the walk reads Markdown alone and nothing can grade a file it
cannot read. ADR-0030 records the decision.

Two things follow from identity being a PATH. The stray scan walks the whole
grounding tree and derives the skill from the path, rather than walking out from
each catalogue entry: a matrix whose skill was deleted or renamed sits under a
directory the catalogue cannot name, so starting from the catalogue never
visited the one case the check exists for. And a matrix is asked for with
`lstat` and refused unless it is a plain file, because following a link lets two
graded files share one audit record, or lets the check read a record from
outside the tree. Neither is visible to the other: the link sits at exactly the
pathname the scan holds.

- A **`G` row** claims the authority of the source. Its rule cell names the rule.
- An **`E` row** is our own editorial guidance. Its rule cell is empty.
- An **`N` row** is narrative. It orients the reader and asserts no rule, so it
Expand All @@ -51,19 +75,38 @@ entered the STE skill unclassified while `ground --check` reported clean. Any
change that narrows what the checker sees reopens that hole, whatever it widens
elsewhere.

A table and a fenced block are units. Neither fits in a matrix cell, so each
carries a designator such as `[table 8f3a2b1c]`, whose digest names the block
CONTENTS. An ordinal named a position instead, so a table could be rewritten
whole while the matrix stayed clean. Exempting these was the first attempt at
this fix, and it was the same defect renamed. A rule written as a table is
still a rule.
A table, a fenced block and a blockquote are units. None of them fits in a
matrix cell, so each carries a designator such as `[table 8f3a2b1c]`, whose
digest names the block CONTENTS. An ordinal named a position instead, so a table
could be rewritten whole while the matrix stayed clean. Exempting these was the
first attempt at this fix, and it was the same defect renamed. A rule written as
a table is still a rule.

There are no exempt headings and no exempt sections. A heading is a unit, so is
anything above the first heading, and `Source`, `Boundary` and `Notice` grade
like any other section. Each of those was a hiding place: an instruction under
a heading called `Source` was disposed of by nothing. Front matter is the one
thing outside the check, because it is metadata for the harness.

That exemption belongs to `SKILL.md` and to no other file. The harness parses a
skill's front matter and never shows it to a writer, which is the whole warrant,
and no harness reads a reference file's prefix. A closed `---` block there was
removed from the units and reported by nothing, so a rule written there shipped
visible to the reader and invisible to the check. `checkSkill` takes the file it
is grading as `subject`, with no default, because a caller that does not say
which file it grades may not be handed the exemption. A block in any other file
is refused by name.

State what that block renders as carefully, because it depends on the lines.
`test/gfm-render.test.js` puts five shapes through the parser, by ADR-0028's
rule: a mapping gives a thematic break and a setext heading, a list gives a
list, a fenced block gives code, and a table gives a table. An earlier draft of
this paragraph named the first render as the reason, in four documents at once,
which the parser refutes for the other four shapes. The property that holds
across all of them is the one the refusal rests on, and it is the one to state:
a reader sees the block's contents, and the walk reads no unit from any line of
it.

Each row claims one occurrence. A skill that repeats a sentence needs a row for
each time it says it.

Expand Down Expand Up @@ -254,9 +297,23 @@ The checker reads Markdown a line at a time, and it models no container. So it
states the forms it reads and refuses every line outside them. Those forms are
a blank line, any construct at column 0, a line that continues the paragraph
above it while carrying prose, and an indented code block that stands on its
own. A blockquote, an empty marker and an empty heading are the exceptions at
column 0, because the checker does not read those either. Anything outside the
forms fails as `unmodelled-construct`, with the line and what to write instead.
own. An empty marker and an empty heading are the exceptions at column 0,
because the checker does not read those either. Anything outside the forms
fails as `unmodelled-construct`, with the line and what to write instead.

A blockquote was a third exception until the walk was given a reading of one.
It is a block now, from its first marker at column 0 to the first line without
one, named by a digest of what it holds. The refusal was never about the
marker: the walk merged the quote with its contents, so `> - one gasket`
reached a row as a paragraph carrying its own markers. A reading a reader agrees
with removes the exception, and that is ADR-0016 applied forwards rather than
a rule naming the shape. A line directly under a quote is refused instead,
because a reader continues the quote over a line that carries prose and ends it
at one that interrupts a paragraph, and which of those depends on the block open
INSIDE the quote. The remedy is the blank line every shipped file already has.
An indented marker stays refused, as an indented table does. ADR-0031 records
the decision, and `test/gfm-render.test.js` pins the over-refusal beside the
render that measures it.

A continuation line states what it may BEGIN with, and that is the third form
read the same way round as the rest. It carries a letter, a digit or ordinary
Expand Down Expand Up @@ -357,9 +414,9 @@ line that matters: no matrix reaches an installed tree.

### A file in a skill directory that nothing governs

The matrix disposes of `SKILL.md` and opens no other file, so a second file
beside it installs ungraded on every pathway. A `SOURCE.md` shipped that way
for four releases, carrying numbered procedures at whoever read it.
The matrix used to dispose of `SKILL.md` and to open no other file, so a second
file beside it installed ungraded on every pathway. A `SOURCE.md` shipped that
way for four releases, carrying numbered procedures at whoever read it.

So a skill directory ships `SKILL.md`, `LICENSE`, `agents/`, and `references/`,
and `ground --check` refuses anything else by name. The source record moved to
Expand All @@ -378,13 +435,15 @@ plain file. `copyFile` resolves a link, so a link called `LICENSE` ships the
bytes on the other end of it and the allowlist would have passed it. This is
the disposition a study already gives a link inside it.

`references/` is the one entry whose governance is owed. `SKILL.md` routes a
`references/` was the one entry whose governance was owed. `SKILL.md` routes a
writer into it, so it is context and not an audit record, and the answer to
ungraded context is to grade it rather than to evict it. Until issue #99 lands,
every run prints how many files under `references/` no row disposes of. That
count is a note, like `audit-coverage` beside it. Do not promote it to an
error, and do not remove it to quiet the output. ADR-0025 records both
decisions.
ungraded context is to grade it rather than to evict it. ADR-0025 settled that
and printed a count in the meantime, because nothing could grade those files
while the walk refused a blockquote. Issue #99 landed both halves. A matrix now
disposes of each file under `references/`, and the count is an error naming the
matrix to write. Read that as the note being answered rather than removed: what
replaced it refuses more than it counted. ADR-0030 records the decision, and it
amends ADR-0025.

### Impurity in `src/`

Expand Down
45 changes: 45 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,51 @@ and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Added

- A grounding matrix disposes of one file, and `ground --check` reads every file
a skill ships to a writer. `SKILL.md` keeps `grounding/<tier>/<skill>.md`, and
a Markdown file under `references/` answers to a matrix that mirrors its path,
such as
`grounding/standards/simplified-technical-english/references/examples.md`. The
two STE reference files installed on every pathway with no row disposing of a
line in either, and one of them mapped real `Rule N.N` identifiers to topic
labels with no `G` row anywhere. They carry 127 rows between them now, twelve
of them `G` rows, every one `unaudited` and `unquoted`. A row space is per file
because `Our anchor` names a heading, and two files in one skill can carry the
same heading. A graded file with no matrix is an error naming the matrix to
write, and so is a file under `grounding/` that grades no file any skill
ships. That scan walks the grounding tree and derives the skill from the path,
because a matrix whose skill was deleted or renamed sits under a directory the
catalogue cannot name. A matrix is asked for with `lstat` and refused unless
it is a plain file, because following a link there lets two graded files share
one audit record. A file under `references/` that is not Markdown is refused,
because the walk reads Markdown alone. A front matter block outside `SKILL.md`
is refused, because the harness that reads one is the whole warrant for the
exemption, and `checkSkill` takes the file it grades as `subject` with no
default. Every finding names the file it came from, beside the skill. The
report is keyed prototype-safely, so a skill directory or a stray matrix at a
name JavaScript owns reaches a reader rather than emptying the report or
ending the run. A matrix and a stray are compared by the filesystem's own
identity where two spellings resolve to one file, so a miscased matrix is the
matrix rather than a stray to delete. ADR-0030 records the decision, and it
amends ADR-0025's count from a note to an error. Issue #99.
- `skills/standards/simplified-technical-english/references/rule-navigation.md`
carries two tables where it carried one. A table is one unit, so a table is
one authority class, and the single table mixed source locations with our own
advice about when to read them. The first table states where the standard
answers each question, and the second is our advice. ADR-0030.
- A blockquote is a unit the checker reads, rather than a construct it refuses.
It is one block, from its first marker at column 0 to the first line without
one, named by a designator such as `[quote 8f3a2b1c]` whose digest binds the
quoted lines. That is the disposition a table and a fenced block already have.
The old refusal was never about the marker: the walk merged the quote with its
contents, so a quoted list reached a row as a paragraph carrying its own
markers. A line directly under a quote is refused instead, because a reader
continues a quote over a line that carries prose, and the walk holds no state
to say when. Leave a blank line under a quote. An indented marker stays
refused. `skills/standards/simplified-technical-english/references/examples.md`
went from 113 units and 41 refusals to 113 units and none. ADR-0031 records
the decision, and `test/gfm-render.test.js` holds every claim in it against
`micromark`.
- A grounding matrix names the reading its audits answer to, above its table,
as `**Source version:**` and a pin. The pin joins the row digest, so moving
the source on voids every audit in the file at once. A `G` row cites a rule
Expand Down
42 changes: 38 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,44 @@ Write your `SKILL.md` in the Markdown the check models. Four forms pass: a
blank line, any construct written at column 0, a line that continues the
paragraph above it, and an indented code block that stands on its own. The
check reads a line at a time and models no container, so it refuses every
other line and names it. A blockquote, an empty marker and an empty heading
are refused at column 0 as well, because the check does not read those either.
ADR-0016 gives the reason. Report a skill that needs a container to say what
it means on issue 37.
other line and names it. An empty marker and an empty heading are refused at
column 0 as well, because the check does not read those either. ADR-0016 gives
the reason. Report a skill that needs a container to say what it means on
issue 37.

A blockquote is one block, and its row names a digest of what the quote holds.
Leave a blank line under the quote. The check refuses the line directly below
one, because a reader may keep that line inside the quote. ADR-0031 gives the
reason.

## Grade every file the skill ships to a writer

A skill directory ships `SKILL.md`, `LICENSE`, `agents/`, and `references/`. A
matrix disposes of `SKILL.md` and of every Markdown file under `references/`,
one matrix for each file.

The matrix for `SKILL.md` is `grounding/<tier>/<skill>.md`. The matrix for a
reference file mirrors that file's own path, under a directory named for the
skill:

```
skills/standards/demo/references/examples.md
grounding/standards/demo/references/examples.md
```

Write the reference matrix the way you write the skill's own. It carries the
same seven columns, its own quotation declaration, and its own source version
when it holds a `G` row. A reference file with no matrix fails the check, and
so does a file under `grounding/` that grades no file any skill ships. ADR-0030
gives the reason.

A file under `references/` is Markdown. The walk reads Markdown alone, so
nothing can grade a file of another kind, and the check refuses one by name.

Do not open a reference file with a front matter block. That exemption belongs
to `SKILL.md`, whose block a harness reads as metadata. Nothing reads a
reference file's block, so a rule written there would be graded by nothing, and
the check refuses it.

## Write under the skills

Expand Down
34 changes: 26 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,19 @@ dictionary, which this repository does not ship.

## Grounding matrices

Each skill has a grounding matrix in `grounding/`. The matrix disposes of every
unit of content in the skill, and each row says what that unit claims.
Each file a skill ships to a writer has a grounding matrix in `grounding/`. The
matrix disposes of every unit of content in that file, and each row says what
that unit claims.

One matrix disposes of one file. `SKILL.md` answers to
`grounding/<tier>/<skill>.md`, and a file under `references/` answers to a
matrix that mirrors its path, such as
`grounding/standards/simplified-technical-english/references/examples.md`. A
row names a heading, and two files in one skill can carry the same heading, so
a shared row space would let a row claim the wrong occurrence. A file with no
matrix fails the check, and so does a file under `grounding/` that grades no
file any skill ships. ADR-0030
records the decision.

Rows come in three kinds:

Expand Down Expand Up @@ -369,25 +380,32 @@ skill fails the gate. ADR-0025 records that decision.

`stylewright ground --check --all` fails when a skill changes and its matrix
does not. Every heading, paragraph, list item, table and code block counts,
including the ones before the first heading. Front matter does not, because it
is metadata for the agent harness rather than instruction for a reader.
including the ones before the first heading. Front matter in `SKILL.md` does
not, because the harness reads it as metadata rather than as instruction for a
reader. No harness reads a reference file, so a front matter block in one is
refused instead.

The check reads Markdown a line at a time, and it models no container. So it
states the forms it reads: a blank line, any construct at column 0, a line that
continues the paragraph above it, and an indented code block that stands on its
own. It refuses every other line and names it, rather than reading a blockquote
or a nested construct as the wrong unit.
own. It refuses every other line and names it, rather than reading a nested
construct as the wrong unit.

A blockquote is one block, named by a digest of what it holds, as a table and a
fenced block are. The quote runs from its first marker to the first line
without one. Leave a blank line under it. A line directly below a quote is
refused, because a reader may keep that line inside the quote and the check
holds no state to say whether they do. ADR-0031 records the decision.

A continuation line states what it may begin with. It carries a letter, a
digit, or ordinary sentence punctuation. It also carries a backtick or a tilde,
where the line opens no fenced block. Any other lead is refused, because a lead
character alone cannot say whether the line opens a container. Write such a
line so it begins with a word, or write the construct at column 0.

Three constructs are refused at column 0 as well, because the check reads none
Two constructs are refused at column 0 as well, because the check reads neither
of them:

- A blockquote, whose contents the check reads as our own prose.
- A heading with no text, such as `#`, which opens no section.
- A list item with no content, such as `-`, which opens no item.

Expand Down
13 changes: 12 additions & 1 deletion docs/adr/0025-a-skill-directory-ships-what-something-governs.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ ungraded context is to grade it, not to evict it.

Grading it is not this decision. `examples.md` yields 113 content units, and 41
of its lines are blockquotes that the extractor refuses today, so a matrix
cannot cover it until that grammar admits them. Issue #99 carries the work.
cannot cover it until that grammar admits them. Issue #99 carries the work, and
ADR-0030 and ADR-0031 record how it landed.

## The count is a note, and it stays one

Expand All @@ -76,6 +77,16 @@ number exists to report. Do not promote it to an error, which would fail every
release until #99 lands. Do not remove it to quiet the output, which would hide
what this decision could not finish.

**Amended 2026-08-14, when #99 landed.** A matrix disposes of every file under
`references/`, one matrix per file, so the reason above no longer holds: an
ungraded reference file is a defect a contributor can fix rather than a state
the repository is stuck in. The count is an error now, per file, naming the
matrix to write. ADR-0030 records the decision and the row-space question it
turned on, and ADR-0031 records the grammar change that made `examples.md`
gradeable. The two instructions above stand for any future note of this kind:
what replaced this one refuses more than it counted, and nothing was removed to
quiet the output.

## What was rejected

**Grade every installed file now.** The six source records carry 166 content
Expand Down
Loading