Skip to content

Promote the agent-enablement framing and the write-guard owner scope to main - #498

Merged
ptr727 merged 8 commits into
mainfrom
develop
Aug 1, 2026
Merged

Promote the agent-enablement framing and the write-guard owner scope to main#498
ptr727 merged 8 commits into
mainfrom
develop

Conversation

@ptr727

@ptr727 ptr727 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Promotes eight commits from develop. Every one traces to a defect found in use rather than to a planned change, and five came from downstream agents reporting what the procedure did not cover.

What lands

Commit Change
a0f6f24 (#487) docs/content-import.md, the three capture-pass findings from the Blog migration: an export is not a media capture, a sitemap is not the URL contract, and an HTTP fetch is not the original
8bdfa22 (#494) The write-guard scopes by owner rather than exact origin, with GH_WRITE_GUARD_ALLOW for a different owner. Four target-flag spellings that silently bypassed rule 3 are closed
981d92f (#492) The purpose is restated as agent enablement, in README.md, HISTORY.md and AGENTS.md
275705b (#493) TODO.md becomes the fleet backlog destination, and spec/readme-structure.md stops mandating the construction GOVERNANCE.md bans
b6ab6db (#491) STANDUP.md step 0A names the maintainer-only prerequisites, and step 4 asserts the remote
89e3868 (#488) The version.json floor is chosen at standup rather than inherited
eed2e00 (#495) README.md gains "What It Achieves", the objectives and the fidelity ladder
f6dc5e6 (#497) CODESTYLE.md stops claiming CI runs the same checks as the clean-compile

Provenance

Five of the eight answer issues filed by downstream agents: #456 (Blog intake), #489 and #490 (the Blog carry), and #496 (Financial-Modeling). That loop is the one "What It Achieves" now describes, and this promotion is it closing.

Divergence, checked rather than assumed

main...develop reports 8 ahead, 102 behind, diverged. The 102 are topology, not content. They are 79 promotion merge commits, which are main-only by construction because a promotion is a two-parent merge, plus 23 Update codegen files bot commits from this repo's pre-2.0 life as a .NET sample template. git diff --name-status origin/develop origin/main returns exactly the 12 files these 8 commits touch, so there is no main-only content to reconcile.

Verification on the merged develop

Every gate re-run after the last merge, not inherited from the individual PRs:

  • prose_lint.py . --check charset --check dupword --check spelling clean tree-wide.
  • repo_gate.py clean (eol, sha-pin).
  • spec/validate.py clean, 21 cataloged repos classify.
  • gh-write-guard.py --selftest passes, including the nine new repository-scope cases.
  • python3 -m unittest discover -s scripts, 180 tests pass.
  • The README.md objectives list verified as one continuous list of 8 bullets with the fidelity table nested, since an unindented table split it in review.

Merge mechanics

This is a promotion, so it merges as a merge commit with two parents, never a squash. Its head is develop, so --delete-branch must not be used.

🤖 Generated with Claude Code

ptr727 and others added 8 commits July 31, 2026 20:26
Writes the three capture-pass findings from the Blog intake (#456) into
fleet guidance, which is the item that comment thread left owed. Both
findings the hub publicly committed to recording are here, plus the
third that arrived later and is the strongest of the three.

## The gap

`STANDUP.md` covers standing up a repo. It says nothing about the one
input it cannot re-derive: when a repo's content comes from a live
external system, that system is not under version control and stops
serving on someone else's calendar. Whatever the capture misses is gone,
and each of the three failures below produces a capture that reconciles
cleanly and is wrong.

## What lands

**`docs/content-import.md`**, hub-only on the same footing as the other
`docs/` procedures, holding the three findings with the measurement
behind each one:

1. **An export is not a media capture.** 261 of 972 referenced assets
(27%) are hotlinked to a third-party host and appear in no export. Half
the referencing URLs are proxied through the CMS image proxy, so a
third-party asset carries a first-party hostname and a host-keyed
inventory reports full coverage of a set it never read. Enumerate media
from the rendered pages, and treat localizing external assets as
required.
2. **A sitemap is not the URL contract.** 111 listed against 1,051
served, with the target generator's plural taxonomy roots breaking 195
term URLs while the build reports success. The golden list is generated
from the live crawl rather than the converter output (which would make
the check circular), and its length is floored before parity so a
truncated list cannot make everything below it pass vacuously.
Unlisted-and-unlinked URLs still need a disposition, ambiguous URL
shapes need a named discriminator, and a consumer-visible identifier
such as a feed GUID is preserved byte for byte or broken deliberately.
3. **An HTTP fetch is not the original.** 778 files captured over HTTP
against the official export reconcile at 778 of 778 while 31 differ and
17.2 MB is lost, worst case a 1.7 MB photo returned as an 8 KB thumbnail
at the same URL. Library media comes from the official export, verified
by content hash against its manifest, because a count is not a
verification.

**`STANDUP.md` step 1B**, a short pointer placed with steps 0 and 1A
because it is the third window that closes quietly. It states that the
capture runs as early as the source is reachable, ahead of scaffolding
where the source is rented or scheduled for shutdown.

## Why the numbers are in the doc

They are measured from one WordPress-to-Hugo import and labeled as
evidence for the rule rather than constants to expect. The rules
themselves are phrased for any import, not for WordPress or for Hugo.

## Scope

Guidance only. No spec, registry, or workflow change, and nothing here
claims the `hugo` type or the `ssh-deploy` mechanism, which stay with
the maintainer. The closing section ties all three to the existing floor
rule in `GOVERNANCE.md` "Verification Discipline" rather than restating
it.

## Verification

- `python3 scripts/prose_lint.py . --diff origin/develop` clean, and
both files clean whole (confirmed after staging, since the scan reads
tracked files and skipped the new file while it was untracked).
- `python3 scripts/repo_gate.py` clean, `python3 -m unittest discover -s
scripts` 180 passing.
- markdownlint-cli2 and editorconfig-checker via Docker, both clean.
- Both files verified CRLF-only by byte scan, and the `STANDUP.md` diff
is 7 inserted lines with nothing else touched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Resolves the gap reported in `gh-write-guard-override-gap.md`: rule 3's
deny message promised a per-session permission path that did not exist
in the code, so a maintainer's explicit, repeated authorization could
not be honored.

## Verified before changing anything

| Claim | Result |
| --- | --- |
| Rule 3 denies unconditionally | **True.** The logic is inline in
`classify`, not in a function named `_check_cross_repo` as the report
quotes, so the report's code excerpt is a paraphrase. The message and
behavior are quoted correctly. |
| `GOVERNANCE.md` is absent from HomeAutomation-Config, PhotoCleaner,
PlexCleaner | **True**, all three 404. The deny message cited a file the
reader cannot open. |
| The installed hook might be an older revision | **False.** The
installed copy differs from this one by a single British spelling
(`judgement`), so behavior is identical. |

## Why other repos wrote cross-repo without complaint

The report asks this to be reconciled, and it is not a permissions
difference. Rule 3 has a narrow trigger, measured against the installed
hook:

| Command shape | Decision |
| --- | --- |
| explicit `--repo`, sibling repo, same owner | DENY |
| explicit `--repo`, different owner | DENY |
| **no explicit target**, so the target is the cwd's origin | ALLOW |
| explicit target, **cwd is not a git checkout** | ALLOW |
| explicit `repos/owner/repo` API path | DENY |

So an agent that `cd`s into the other repo and runs a plain `gh issue
create` performs the same write invisibly, and an agent whose cwd does
not resolve to a git origin skips the check entirely by design.
HomeAutomation-Config's agent was not stricter, it used the one shape
the guard can see. The hook is also `matcher: "Bash"` only, and was
installed here on 2026-07-31, so nothing before that and no non-Bash
path was ever covered.

## What changes

**The boundary moves to where the harm is.** The incident was a stray
comment on a stranger's repository, not work across the maintainer's own
projects. A sibling repository under the same owner as `origin` is now
allowed. A different owner is denied unless named in
`GH_WRITE_GUARD_ALLOW`, as `owner/repo` or `owner/*`.

**The grant is a channel the agent cannot use on itself.** It is read
from the environment the session was launched with. A hook runs as its
own process, so an inline `VAR=x cmd` prefix or an `export` inside a
Bash call never reaches it. A self-test case asserts exactly that, by
classifying a command that carries the assignment as text and expecting
a deny.

**Nine self-test cases** cover the matrix: same owner, the API-path
form, a different owner with and without a grant, the owner wildcard, a
repo grant not extending to that owner's siblings, one owner's grant not
reaching another (the original incident, still denied), a malformed
grant granting nothing, and the inline-prefix case above.

**The prose moves with the code.** `GOVERNANCE.md` "Repository
Boundaries and Write Safety" and the `claude-md-safety.md` kit said
"write only to the current project's own repository", which the hook
would now contradict. A guard that allows what the rules forbid leaves
the agent to guess which one binds, which is the confusion this report
is about.

## Two things reported, not changed

1. **The no-origin skip is a real hole.** When `origin` does not
resolve, rule 3 is skipped and an explicit foreign target is allowed.
Tightening it would deny ad-hoc work outside a checkout, so it is
flagged for your call rather than changed alongside a loosening.
2. **Rule 3 scans the raw command string, so merely *mentioning* a write
denies.** This fired live while probing the guard for this PR: a
`python3` heredoc containing the text `gh issue create --repo
ptr727/PhotoCleaner` was denied, though it wrote nothing. Rule 1 strips
quoted spans before scanning and rule 3 does not. The fix is to require
`gh` in argv command position, the pattern `_push_targets` already uses
for `git push`, and it deserves its own change with its own cases rather
than riding along here.

## Verification

- `--selftest` passes, 9 new cases plus the existing matrix.
- Decision boundaries measured by classifying strings against the
installed hook, not inferred.
- `prose_lint` blocking set clean tree-wide, and clean on changed lines.
`repo_gate` clean, 180 script tests pass.
- The hook keeps LF endings, and the three prose files keep CRLF.

**Not installed to this host.** `~/.claude/hooks/gh-write-guard.py`
still carries the old rule, so the change takes effect after you merge
and reinstall. Say the word and I will run the install.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restates what this project is for. The tagline described the repo by its
contents, governance and orchestration and workflow audit, which names
the machinery without saying what the machinery is for. A reader learned
what is in here without learning why any of it exists.

## The framing

**The purpose is agent enablement.** An agent is fast and inconsistent,
so a fleet built by one drifts a different way in every repository, and
the drift stays invisible until something breaks where it matters. What
this repo makes repeatable is the outcome: an agent stands a repository
up, changes it, and releases it on its own, and lands in the same
known-good shape every time.

**The guardrails are what make granting that autonomy sound rather than
reckless**, and they are stated as enabling rather than restraining. A
rule earns its place by removing a decision an agent would otherwise
make differently every time, or by making a failure loud that would
otherwise pass green. Write safety bounds what an agent can reach
outside the project in front of it, the review loop closes before
anything merges, and the audit proves the result instead of accepting
the agent's report of it. Autonomy extends exactly as far as the
verification reaches.

**Nothing here is finished.** Every rule traces to a specific failure,
nearly all of them observed in this fleet rather than imagined, and a
procedure that lets a new one through is corrected as part of the work
that found it.

## Where it lands

The same sentence opens three files, so all three move together:

| File | What changes |
| --- | --- |
| `README.md` | the tagline, the release-note summary bullet, and the
opening of "What This Repo Is" (three paragraphs before the existing
file list, which is unchanged) |
| `HISTORY.md` | the tagline |
| `AGENTS.md` | the opening description an agent reads first |

## Two follow-ups this creates

1. **The GitHub About description is derived from the README tagline**
and currently matches the old one exactly. It needs updating after this
merges. That is a live repo-settings write, so it waits for the merge
and for your say-so rather than going out with the branch.
2. **`README.md` carries 16 warn-only prose findings** (9 `dash`, 7
`semicolon`), none of them on the lines this PR touches. The standing
rule corrects existing prose as a file is next edited, so they are owed.
They are deliberately not in this diff, because a 16-line sweep would
bury the wording you are meant to be reading. Offered as an immediate
follow-up PR.

## Verification

- `prose_lint` blocking set clean tree-wide, and the new prose carries
no `dash` or `semicolon` finding of its own.
- cspell clean over `README.md` and `HISTORY.md`, the gated scope.
- markdownlint-cli2 clean over all three files. Table of contents
unaffected, since no heading changed.
- CRLF-only by byte scan on all three.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Moves the running backlog out of `README.md` into `TODO.md`, and makes
that placement the fleet standard rather than a hub preference.

## Why the README was the wrong home

`spec/readme-structure.md` lists twelve README sections and **TODO is
not one of them**, so the hub's own README deviated from the structure
its audit checks every fleet README against. Beyond conformance, open
work does not belong on the adoption surface a reader lands on, and it
changes on a different cadence from everything around it.

## What makes it a standard

- **`spec/readme-structure.md` gains a `TODO.md` section**, stating that
a README carries no backlog section and that the backlog lives in a root
`TODO.md` with a defined shape. This is the file the `readme-structure`
audit dimension reads, so the rule lands where the check already looks.
- **`STANDUP.md` step 2 lists it as the fourth topical destination**,
alongside `CODESTYLE.md`, `ARCHITECTURE.md`, and `OPERATIONS.md`.

**It is a declared destination, not a required file**, the same footing
as `ARCHITECTURE.md`, so a repo with no backlog carries no file rather
than an empty one. Say the word if you would rather it be required by a
selector, which would mean a `spec/files.json` entry and an empty
`TODO.md` in every repo.

## Fleet impact is small, and measured

Surveyed live across twelve repos: **no repo has a `TODO.md`**, and
exactly **three** carry a README `## TODO` section, all of them
operational config repos (HomeAssistant-Config, Vantage-Config,
HomeAutomation-Config). The other nine have neither, so they are already
conformant. Those three are a follow-up, not this PR.

## Two things fixed while in these files

1. **`spec/readme-structure.md` instructed authors to use the
construction `GOVERNANCE.md` bans.** Its Style list said "ASCII only (no
em-dash; use a spaced hyphen)", against `GOVERNANCE.md` "No spaced
hyphen joining or interrupting a sentence", so an agent following the
more specific file produced prose the prose gate then flagged. The
bullet now defers to the tiered character rule, and the file's other 8
`dash` and `semicolon` findings are fixed in the same pass. This closes
finding 1 of #489.
2. **Three real backlog items were added while moving**, rather than the
list being copied unchanged: the `.editorconfig` / `.gitattributes` /
`.gitignore` comment cleanup (44 findings), the
`repo-config/configure.sh` sweep (54 findings, and that file is carried
`verbatim` so downstream cannot fix them locally, which is finding 6 of
#489), and the README's own 13 prose findings.

## The README sweep is deferred, deliberately

`README.md` carries 13 `dash` and `semicolon` findings, none on lines
this PR touches. Two other changes to that file are in flight (#492), so
a third overlapping edit would conflict with both for no gain. It is
recorded in `TODO.md` rather than left to memory, which is what that
file now exists for.

## Verification

- Fleet survey run live against the GitHub API, so the three-repo number
is measured rather than recalled.
- `prose_lint` blocking set clean tree-wide. `TODO.md`, `STANDUP.md`,
and `spec/readme-structure.md` clean on the warn set too.
- markdownlint clean over all four files, including the removed ToC
entry and the link fragments.
- No orphaned reference definitions: `[reports]` and `[repos]` are still
used elsewhere in the README.
- cspell clean, editorconfig-checker clean, all files CRLF-only by byte
scan.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#491)

Closes the gap reported in #490, found by standing Blog up against
`STANDUP.md`.

## What happened

Blog reached 24 signed commits, the full carried instruction set, the
baseline files, a working build, a proven URL gate, and a site serving
locally. The GitHub repository did not exist. Steps 0 through 3 all
completed, step 4 was never reachable, and the maintainer found it by
asking rather than by anything in the procedure reporting it.

Verified against the tree rather than taken on report: `STANDUP.md`
contains no occurrence of `gh repo`, `remote`, or `origin`, and names
the maintainer exactly three times, none of them for an onboarding
input.

## Why the procedure allowed it

Step 0 implies a local `git init` and step 4 presumes a remote, with
nothing in between creating the repository or saying who does. The
inputs that can only come from a human were never enumerated, so each
blocked at the step that needed it instead of being handed over at the
start. And every local step passes with no remote at all, so the
procedure reported progress the whole way.

## What lands

**Step 0A** lists what only the maintainer can supply, as a checklist to
hand over before step 1:

- the repository, with owner, name, and visibility
- the GitHub App **installed** on it, not merely created
(`repo-config/README.md` already states the distinction)
- the App secret values, in the Actions and Dependabot stores both
- every publish credential and environment the repo's mechanisms declare
in `spec/secrets.json`

Creating a repository is an outward-facing write, so it sits behind the
per-session permission `GOVERNANCE.md` "Repository Boundaries and Write
Safety" requires, and the agent asks rather than assuming.

Two statements carry the rest of the failure:

- **A repo with no remote is not partially stood up. It is not
started.** Local progress is not evidence of onboarding progress, and
`AUDIT.md` reads a live repo, so the one instrument that would catch
this is unavailable exactly while it holds.
- **A blocking prerequisite is escalated when it is found, not
carried.** In a task list it renders identically to a pending task,
which is how this one survived an entire session while work continued
around it.

**Step 4** asserts the remote before running anything, with `gh repo
view <owner>/<repo>`. An absent repository otherwise surfaces as a
resolution error from whatever `configure.sh` calls first, which reads
as a permissions or naming problem rather than the missing prerequisite
it is.

**Step 4 also states why it follows step 3.** A ruleset requiring a
check name no run has ever reported leaves the first pull request
waiting on a status nothing produces, and an operational repo promotes
by pull request too, so this is not only a release-repo concern.

## One deviation from the issue's suggestion

#490 says the check-name fact "is currently in `repo-config/README.md`
rather than in the step that needs it". It is in both: step 4 already
ended with it. So this adds the ordering consequence rather than
restating the fact, since duplicating a rule into a second location is
its own defect.

## Verification

- `python3 scripts/prose_lint.py . --check charset --check dupword
--check spelling` clean tree-wide, and the warn set clean on
`STANDUP.md`. Both invocations match the CI steps in `validate-task.yml`
rather than the narrower ad-hoc default.
- markdownlint-cli2 and editorconfig-checker clean.
- CRLF-only by byte scan, 24 insertions and 1 modified line.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
`STANDUP.md` step 2 lists `version.json` among the files a new repo
carries and says nothing about the number inside it, so the file arrives
carrying a floor that describes a release history the new repo does not
have. `WORKFLOW.md` D3.3 makes that field the repo's own major.minor
floor with NBGV appending the git height as the patch, so the carried
value is a claim, not a default.

## The failure is observed, not hypothetical

Four operational config repos run on a floor none of them chose, and
each has already released against it:

| Repo | Floor | Latest release |
| --- | --- | --- |
| HomeAutomation-Config | 2.0 | 2.0.14 |
| ESPHome-Config | 2.0 | 2.0.60 |
| HomeAssistant-Config | 2.0 | 2.0.23 |
| Vantage-Config | 2.0 | 2.0.13 |

The repos versioned deliberately show the rule already exists in
practice and only lacked a statement. A project with history keeps its
scheme (Utilities 4.0, PlexCleaner 3.22, NxWitness 2.15, LanguageTags
1.5, ESPHome-NonRoot 1.9, VSCode-Server-DotNetCore 1.1), and a new
project starts at 1.0 (aiopurpleair, MediaTools, PhotoCleaner,
homeassistant-purpleair) or at 0.1 while pre-release
(Financial-Modeling). Whether a repo got this right depended on who
stood it up.

## What lands

Step 2 gains the three cases and requires the floor to be set before the
first release:

1. A new project starts at `1.0`, or `0.1` while deliberately
pre-release.
2. A project with releases behind it keeps its established scheme,
adapted to NBGV, with the floor at or above the highest published
version, because a floor under an existing tag emits versions that sort
backwards.
3. A repo that ships no package still chooses. This is the case that
produced all four above: an operational or source-only repo still
releases a tag and a source archive, so having no consumer is not a
reason to leave the carried number alone.

It also records that the decision is effectively one-way. Once a repo
publishes against a floor, lowering it regresses the released version
order, so the four keep the floor they have and this is prevention
rather than a repair procedure.

## Scope

Hub-only, and deliberately not in `WORKFLOW.md`. D3.3 already defines
what the field means and is carried fleet-wide at `intent` fidelity, so
restating the bootstrap rule there would add re-vendor debt for guidance
that only ever applies while a repo is being stood up.

Two conformance findings surfaced by the same survey are **not**
addressed here, since they are downstream repo changes rather than hub
guidance: **AudioCleaner** and **DevKitCIoT** carry no `version.json` at
all, which `spec/files.json` requires for every repo (`appliesTo: "*"`).

## Verification

- Fleet survey run live against each repo's `version.json` and latest
release via the GitHub API, so every number above is measured rather
than recalled.
- `python3 scripts/prose_lint.py . --diff origin/develop` clean,
`STANDUP.md` clean whole.
- `python3 scripts/repo_gate.py` clean, markdownlint-cli2 and
editorconfig-checker clean.
- CRLF-only by byte scan, diff is 8 inserted lines with nothing else
touched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a `## What It Achieves` section between "What This Repo Is" and
"How This Repo Operates", so a reader learns what the model buys before
meeting the mechanics and the per-type rules.

## The gap

The README went from what the repo holds straight into how it operates,
then into the per-type rules. The objectives were real and consistently
applied across every file here, and nowhere written down. A reader had
to infer them from the machinery.

## What lands

Eight objectives, each naming the machinery that delivers it so the
claim is checkable rather than a slogan:

- **Workflow consistency by contract**, not by copying a YAML file: the
fixed part is the orchestration seam, and what a repo builds inside it
is its own, so a Hugo site and a NuGet package satisfy one contract
without pretending to be one pipeline.
- **Technical consistency the three surfaces share.** The editor, the
CLI, and CI read the same config, so a rule that holds in review holds
everywhere.
- **Best practices promoted once**, in `GOVERNANCE.md` or
`CODESTYLE.md`, rather than rediscovered and re-argued in the next repo.
- **Feedback loops that close on the procedure, not the instance.** A
repo that cannot be stood up from the docs alone is a documentation
defect.
- **A new language or target is a spec change**, with detection, checks,
and carried files declared, then proven by a cold standup.
- **Re-deployment measured and traceable**, with staleness detected by
content hash against the hub's own past revisions rather than a version
stamp a repo can keep while editing underneath it.
- **A fidelity table**, below.
- **The human/agent split**, below.

## The two that carry the weight

**Every carried unit declares how much freedom it grants.** This is the
"must be exactly this / must do something but how is yours / yours
entirely" distinction, and it already exists in `spec/files.json` as a
declared field. The table just surfaces it:

| Level | The obligation | Who owns the content |
| --- | --- | --- |
| `verbatim` | Byte-identical to canonical, after governed normalization
| The hub |
| `interface` | Honor a named contract, checked by name and wiring | The
repo owns the body entirely |
| `intent` | Reach the same outcome, judged by meaning | The repo owns
the wording and shape |
| `presence` | The unit exists | The repo owns all of it |

**The human contributes where domain expertise is decisive, and only
there.** The maintainer keeps what an agent cannot know or must not
decide: creating a repository, granting a write outside the owner
boundary, changing a ruleset, approving every merge, and every judgment
about the domain a repo serves. The agent takes the mechanical
scale-out, the part that does not benefit from human attention and
degrades under it. Each repo's own knowledge has a declared destination
so domain expertise is never diluted into a carried file that the next
re-vendor overwrites.

## Every number is checked, not recalled

| Claim | Verified against |
| --- | --- |
| thirteen project types | `spec/project-types.json`, 13 keys |
| guarantees D1 to D9 | `WORKFLOW.md`, 9 `### D<n>` headings |
| four fidelity levels | `spec/files.json`, the set actually in use is
exactly `intent`, `interface`, `presence`, `verbatim` |

## Also in this diff

The reference-definition block is alphabetized while three entries are
added to it. The `governance*` keys sat out of order against the rule
that each group is alphabetized by reference name.

## Verification

- `prose_lint` blocking set clean tree-wide, and clean on changed lines.
- markdownlint clean, including the new table, the hand-added ToC entry,
and the three new reference definitions.
- cspell clean over `README.md` and `HISTORY.md`.
- CRLF-only by byte scan.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fixes #496, raised from Financial-Modeling. Accepted in full, including
the issue's own reasoning about where the rule should *not* move.

## Verified against the tree, not taken on report

| Claim | Result |
| --- | --- |
| `CODESTYLE.md:19` asserts CI runs "the same checks" | **True**,
verbatim |
| `validate-task.yml` additionally runs the doc-lint set | **True**:
markdownlint (L25), cspell (L34), actionlint (L42),
`editorconfig-checker` (L45), plus `spec/validate.py`, the script
self-tests, `repo_gate.py` and the blocking prose run |
| `CODESTYLE.md:5` omits verification discipline from its
cross-reference list | **True** |

## Why the sentence mattered

It is the line a reader consults to answer "what must be green before I
push", and it licensed the inference *local clean-compile green implies
CI green*, which is false for every repo in the fleet. The rule that
actually governs is a section away in another file, so an agent starting
from the pre-commit gate never reaches it.

The issue reports the concrete cost: fifteen files written LF into a
CRLF-default repo, the documented clean-compile passing, markdownlint
and cspell run by hand and passing, and CI failing on the one checker
the pre-commit gate never names. `GOVERNANCE.md` "Verification
Discipline" predicts that exact failure in those words, naming
`editorconfig-checker` and line endings specifically.

## What lands

Both edits the issue proposed, and nothing more:

1. **The backstop bullet stops asserting equality.** It now says the
clean-compile is not the whole gate, names the doc-lint set, states
plainly that a green clean-compile does not predict a green CI, and
points at `GOVERNANCE.md` "Verification Discipline".
2. **The cross-reference list gains verification discipline**, since it
enumerated what lives in `GOVERNANCE.md` instead and omitted the one
rule this section needed.

**The rule is not moved into `CODESTYLE.md`**, per the issue's own
argument. `CODESTYLE.md` already delegates line endings to
`GOVERNANCE.md` deliberately, and "Verification Discipline" is the right
home for a rule about gates that pass while the work is unfinished. The
defect was only that the doc defining the pre-commit gate misstated the
gate's scope.

## One thing worth recording

The first draft of this fix repeated the defect it was fixing. It
claimed "Verification Discipline" also documents each linter's
known-working invocation. Those live under **Workflow YAML
Conventions**, a different H2, so the draft asserted a doc structure
that does not exist while correcting a sentence that asserted a CI scope
that does not exist. Caught by checking the heading rather than
recalling it, and the two are now cited separately.

That is the failure mode `GOVERNANCE.md` names directly: no linter
catches it, because markdownlint, cspell, actionlint and
`editorconfig-checker` all pass on a claim that is merely untrue.

## Carry

`CODESTYLE.md` is carried at `intent, whole` fidelity, so this is a hub
fix that every fleet repo re-vendors. It changes prose only, no gate
behavior.

## Verification

Ran the whole gate rather than the parts that looked relevant, which is
the rule this PR is about:

- `prose_lint` blocking set clean tree-wide, and clean on changed lines.
- markdownlint clean, both new reference definitions resolve, and both
anchors exist in `GOVERNANCE.md` (`## Verification Discipline`, `###
Running the Linters Locally (Known-Working Invocations)`).
- `editorconfig-checker` clean tree-wide, which is the checker the
incident turned on.
- CRLF-only by byte scan.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 05:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Promotes a set of develop fixes to main that tighten the agent-enablement framing, strengthen write-safety guidance/guard behavior around cross-repo writes, and improve standup/import documentation based on observed fleet onboarding failures.

Changes:

  • Reframe the repository purpose around agent enablement (README/HISTORY/AGENTS) and add a “What It Achieves” section explaining objectives and fidelity levels.
  • Add standup/import guidance (new content-import doc, expanded STANDUP steps) and move the running backlog into a dedicated root TODO.md aligned with the README structure spec.
  • Update the host write-safety kit and gh-write-guard.py to scope write allowance by owner (with maintainer-granted overrides) and close previously unhandled --repo/-R flag spellings, with additional self-tests.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
TODO.md Introduces a root backlog file and link references, replacing the README-embedded TODO section.
STANDUP.md Adds maintainer prerequisite handoff, early source-capture step, version-floor guidance, and remote/repo assertions before applying repo config.
spec/readme-structure.md Updates README style guidance to align with GOVERNANCE character-set tiers and specifies the TODO.md convention.
README.md Reframes purpose as agent enablement, adds “What It Achieves,” and removes the inline TODO section in favor of TODO.md.
host-setup/agent-safety/README.md Updates the installed write-safety kit description to reflect owner-scoped write safety and GH_WRITE_GUARD_ALLOW.
host-setup/agent-safety/gh-write-guard.py Implements owner-scoped repo targeting with maintainer-granted overrides; expands repo-flag parsing and adds self-test coverage.
host-setup/agent-safety/claude-md-safety.md Updates the user-level safety rules to match the owner-scoped write boundary.
HISTORY.md Updates the project tagline to the new agent-enablement framing.
GOVERNANCE.md Updates write-safety rule #1 to allow writes within the same owner, requiring explicit permission for different owners.
docs/content-import.md Adds hub-only import/capture guidance documenting observed failure modes and verification expectations.
CODESTYLE.md Corrects clean-compile wording to avoid implying CI equivalence and adds verification-discipline cross-references.
AGENTS.md Updates the opening description to the agent-enablement framing.

@ptr727
ptr727 merged commit cea1804 into main Aug 1, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants