Skip to content

docs: correct the sentences this week's fixes left behind - #610

Merged
Vivswan merged 5 commits into
mainfrom
docs/sentences-left-behind
Nov 12, 2026
Merged

Vivswan merged 5 commits into
mainfrom
docs/sentences-left-behind

Conversation

@Vivswan

@Vivswan Vivswan commented Nov 12, 2026 •

Copy link
Copy Markdown
Owner

What this specifies

Sixteen sentences, on the pages and in two test files, each checked against the code it describes. All sixteen were stale or too wide, so each has one edit.

 1  docs/reference/architecture.md, docs/upgrading/v2-to-v3/layering.md
    before  the higher layer's value wins at every depth
    after   ... at every depth (a label's `name` aside: the rename rule)
    code    src/engine/layers.ts mergedPair(): under deep the lower `name` is written when a rename needs it

 2  docs/reference/library.md, docs/upgrading/v2-to-v3.md
    before  `branches`, `bypass_actors`, `reviewers`, and scalar lists as written
    after   `branches`, the pinned environments, `bypass_actors`, `reviewers`, and scalar lists as written
    code    src/engine/canonical.ts RANKED_LIST, sortEntries(): pinned entries lead in their written order

 3  README.md
    before  the drift report lists everything an apply would change or delete
    after   ... lists what an apply would change or delete
            + The report cannot list the value of a declared secret that already exists, which GitHub never reads back
    code    secrets-engine.ts planSecrets(): a declared secret that exists plans a PUT and no drift line

 4  docs/reference/semantics.md
    before  a check right after an apply reports clean.
    after   ... reports clean wherever that apply reached the declared state.
            + three examples of a state no operation of the plan reaches: a workflow with no file,
              a creation cap answered 405, Pages with neither build_type nor source
    code    workflows plan(), interaction_limits planCreationCap(), pages enablePlan(): drift with no operation

 5  docs/reference/semantics.md
    before  the entry fails with the same line and nothing of it is written
    after   + The section stops at that entry: the operations its plan still held are never sent, the run lists each
            as `not attempted` under a warning that counts them, and the other sections still run.
    code    src/engine/execute.ts executePlan(), src/engine/orchestrate.ts reportUnattempted()

 6  docs/operate/layering.md
    before  a list item of 73 words, over the cap of 70
    after   67 words: "A YAML alias inside the node its own anchor opens" -> "A YAML alias cycle"
    code    the quoted message already says "refers back into the node its anchor &loop opens"

 7  docs/operate/snapshot.md
    before  (an `actions` key ...; an environment's branch policies or protection rules)
    after   (...; the `interaction_limits` creation cap or bypass list)
    code    interaction_limits/index.ts snapshotPullRequestKeys(): two readOrNote() reads

 8  docs/schema.docs.yml, the `_layering` hover
    before  one paragraph of 117 words
    after   three paragraphs of 31, 50, and 60 words
    code    .github/scripts/lib/schema-descriptions.ts: the text is the description as written

 9  docs/start/cli.md, the --summary row
    before  the empty file and its directories stay when the run is then refused for another reason
    after   a file the open created stays, empty, with its directories, and a file that already existed keeps what it held
    code    src/cli/io.ts openSummaryFile(): openSync(path, "a")

10  CONTRIBUTING.md
    before  `bun run build:check` regenerates every table entry and fails on drift.
    after   + Before that, it fails on a GENERATED marker, in a file the table lists, that names a region no generator registers.
    code    .github/scripts/generated.ts unregisteredRegions()

11  docs/reference/semantics.md
    before  a field GitHub reports but cannot set is refused at parse, with no exception named
    after   + Three passthrough entry shapes name such a key in a note instead, until the next major refuses it there:
            an environment entry, one of its deployment_branch_policies patterns, and a variable
    code    src/sections/shared/reported-key-note.ts reportedKeyNote(), its three callers

12  docs/sections/actions_variables.docs.yml, docs/sections/agents_variables.docs.yml
    before  no mention of the note
    after   + A declared created_at or updated_at, which the GET reports and neither write takes,
            is named by a note in check and in apply, whatever the live variable holds.
    code    variables-engine.ts planVariables(), REPORTED_KEYS

13  test/sections/repository/schema.test.ts, a describe title
    before  a repository setting GitHub would 422 or never converge on is refused at parse
    after   each repository setting listed here, which GitHub would 422 or never converge on, is refused at parse
    code    src/sections/repository/index.ts declarationNotes(): two such settings draw a note, not a refusal

14  docs/upgrading/v2-to-v3/run.md, a comment in test/engine/diff.test.ts
    before  (`rules[].parameters`, the fields inside a bypass actor)
    after   (inside a ruleset's rule, its `parameters` included, and inside a bypass actor)
    code    snapshot-helpers.ts replaceSweep(RulesetConfig): the paths are `rules[]` and `bypass_actors[]`

15  docs/operate/layering.md
    before  No `_remove` anywhere
    after   No `_remove` on a keyed entry
            + One on an entry of a list that is not keyed removes nothing and stays, a field under a warning.
    code    src/engine/separate-removals.ts gatherUnkeyed()

16  docs/reference/architecture.md, docs/schema.docs.yml, docs/upgrading/v2-to-v3/settings-file.md
    before  One downgrade | apply and check ignore it | A directive out of its place is refused like any unknown key
    after   Three downgrades | apply and check do not read it. On a single document they warn when its value is
            none of the three | + Two cases draw a warning instead
    code    src/engine/directives.ts unreadDirectiveNotes(), called by validateSettingsDoc()

How

  • No code: nothing under src/ changes.
  • One edit per row: a clause, a table row, or a split paragraph, and no section is rewritten.
  • Examples stay examples: where the code has more cases than a sentence lists, the sentence says "examples".
  • Tests: one describe title and one comment change, and no assertion or fixture value moves.
  • Generated: docs/reference/coverage.md gains the two variables bullets from bun run build:check.

Proof

  • Docs tests: bun test test/docs ends 341 pass, 0 fail.
  • Word cap: the twelve hand-edited pages have no paragraph or list item over 70 words, where main had one.
  • Gates: typecheck, lint, lint:arch, knip, check:compat, and build:check exit 0.
Technical details
  • Whitespace: a longer cell re-pads its table under biome, so four tables carry rows that differ in padding alone.
  • Whitespace: under git diff -w origin/main...HEAD each re-padded table shows two rows, the worded row and its dash separator.
  • Hover text: the _layering hover is the first schema description with a paragraph break, which lib/settings.schema.json carries as a line break.
  • Word counts: counting the words of each paragraph of the twelve pages finds none over 70 at this head, and one on main (docs/operate/layering.md:443, 73 words).
  • Runs: every block below except row 9's is the real bundle against the e2e mock, with debug lines dropped and the settings path shown as /repo/settings.yml.
  • Runs: a named scenario is bun test/e2e/run.ts --scenario <name> --print-stdout.
  • Runs: an input the corpus lacks went through the runner's parseScenario and runScenario, and its settings and live state head its block.
  • Runs: "apply, then check" is the runner's fixpoint: converges re-run against the same mock.

Row 3, actions_secrets: [{name: DEPLOY_TOKEN, value: $DEPLOY_TOKEN}] over a live DEPLOY_TOKEN, a check and then an apply:

::notice::actions_secrets: Actions secret values cannot be read back from GitHub, so check mode cannot verify them, only that each declared secret exists; apply re-seals and rewrites every declared value on every run
result: clean

::notice::actions_secrets: Actions secret values cannot be read back from GitHub, so check mode cannot verify them, only that each declared secret exists; apply re-seals and rewrites every declared value on every run
actions_secrets: updated secret "DEPLOY_TOKEN"
result: applied

Row 4, workflows: [{path: ci.yml, state: active}] with no workflow live:

apply   ::notice::workflows[ci.yml]: declared in the settings file but no workflow with that path exists on the repo, so apply skips it - create the workflow file, or remove it from the workflows section
apply   result: applied
check   drift: workflows[ci.yml]: declared in the settings file but no workflow with that path exists on the repo, so apply skips it - create the workflow file, or remove it from the workflows section
check   result: drift

Row 4, interaction_limits: {pull_request_creation_cap: {enabled: true}} where the cap endpoints answer 405:

apply   ::notice::interaction_limits.pull_request_creation_cap: declared but the pull request creation cap is not available on this repository (405); apply cannot set it
apply   result: applied
check   drift: interaction_limits.pull_request_creation_cap: declared but the pull request creation cap is not available on this repository (405); apply cannot set it
check   result: drift

Row 4, pages: {https_enforced: true} with no site live:

apply   ::notice::pages: GitHub reports no Pages site. A fine-grained token missing the Pages permission gets the same answer; if this repo does have a Pages site, grant the token Pages read and write
apply   ::notice::pages: declared in the settings file but GitHub Pages is not enabled on the repo, and GitHub enables a site only from build_type or source, so apply changes nothing - declare build_type or source to enable the site, or remove the pages section
apply   result: applied
check   ::notice::pages: GitHub reports no Pages site. A fine-grained token missing the Pages permission gets the same answer; if this repo does have a Pages site, grant the token Pages read and write
check   drift: pages: declared in the settings file but GitHub Pages is not enabled on the repo, and GitHub enables a site only from build_type or source, so apply changes nothing - declare build_type or source to enable the site, or remove the pages section
check   result: drift

Row 5, an apply of the rulesets main-protection and release-protection and the milestone v1, where the live main-protection holds a bypass actor the file omits:

::error::rulesets[main-protection]: not applied - the update would remove a live value the settings file omits. rulesets[main-protection].bypass_actors: live has [{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"always"}] but the settings file omits it, so apply would REMOVE it; declare bypass_actors to keep it, or bypass_actors: [] to remove it on purpose
::warning::rulesets: 1 operation after this failure was not attempted; re-run once it is fixed
rulesets: not attempted - creating ruleset "release-protection"
milestones: created milestone "v1"
result: failed

Row 9, the built command line (bun run build:lib) with no token in the environment, on a new path and then on a file holding one line:

$ node /repo/lib/pkg/cli.js check --repository o/r --settings-file settings.yml --summary out/dir/summary.md
error: cannot call the GitHub API: no token was provided. Set the "token" input (--token on the command line), or export GITHUB_TOKEN
result: failed
result=failed
skipped-sections=
repos-result={}
$ wc -c out/dir/summary.md
0 out/dir/summary.md
$ printf '## earlier\n' > held.md
$ node /repo/lib/pkg/cli.js check --repository o/r --settings-file settings.yml --summary held.md
error: cannot call the GitHub API: no token was provided. Set the "token" input (--token on the command line), or export GITHUB_TOKEN
result: failed
result=failed
skipped-sections=
repos-result={}
$ cat held.md
## earlier

Rows 11 and 12, a check of actions_variables: [{name: REGION, value: eu-west-1, updated_at: "2026-01-01T00:00:00Z"}] over a live REGION updated at 2025-06-01T00:00:00Z:

::notice::actions_variables[REGION]: "updated_at" is a value GitHub reports, not a setting it accepts (the GET returns it, neither the POST nor the PATCH takes it), so a declared value that differs from the live one drifts on every check and its update re-runs on every apply without converging; remove it from the settings file
drift: actions_variables[REGION].updated_at: "2026-01-01T00:00:00Z" != "2025-06-01T00:00:00Z"
result: drift

Row 12, the same check of agents_variables with a declared created_at:

::notice::agents_variables[REGION]: "created_at" is a value GitHub reports, not a setting it accepts (the GET returns it, neither the POST nor the PATCH takes it), so a declared value that differs from the live one drifts on every check and its update re-runs on every apply without converging; remove it from the settings file
drift: agents_variables[REGION].created_at: "2026-01-01T00:00:00Z" != "2025-06-01T00:00:00Z"
result: drift

Row 16, the scenario apply-layering-outside-values-warns:

::warning::/repo/settings.yml: _layering must be one of "replace", "shallow", "deep"; got a string that is none of them. A single document is not folded, so the directive is not read and the run goes on; mode: render refuses this file as a layer. Write one of the values, or remove the key; the next major version refuses it here too
labels: created label "bug"
result: applied

Row 16, the same file in check mode over a live bug label:

::warning::/repo/settings.yml: _layering must be one of "replace", "shallow", "deep"; got a string that is none of them. A single document is not folded, so the directive is not read and the run goes on; mode: render refuses this file as a layer. Write one of the values, or remove the key; the next major version refuses it here too
result: clean

Rows 15 and 16, the scenario apply-unkeyed-remove-warns:

::warning::/repo/settings.yml: rulesets[0].bypass_actors[0]._remove: _remove belongs on an entry of a keyed list, and this list is not keyed, so it removes nothing and passes through as a field of the entry. Remove the key; the next major version refuses it
rulesets: created ruleset "r"
result: applied
  • Row 7: the scenario interaction-limits-snapshot-cap-denied-warn pins both left-out notes and the written file.
  • Row 10: test/scripts/generated.test.ts pins the refusal of a marker no generator registers, before any generator runs.
  • Row 11: the environment entry is the scenario environments-apply-refused-entry-reports-unattempted.
  • Row 11: the pattern is the case "a pattern's id, which GitHub only reports, is named once" in test/sections/environments/environments.test.ts.
  • Row 11: bun run check:compat lists the three COMPAT(v4) markers that defer the refusal.
  • Row 13: the two notes are the scenarios repository-private-visibility-contradiction-note and repository-null-security-and-analysis-note.
  • Row 14: replaceSweep(RulesetConfig).passthrough holds rules[] once per rule shape and bypass_actors[], and no rules[].parameters.
  • Row 14: the fixture list in test/engine/diff.test.ts stays rules[].parameters, the one cover of a passthrough path that is a field.
  • Row 15: the scenario render-unkeyed-remove-warns pins a rendered document that still carries the marker.
  • Noticed, not changed here: docs/reference/architecture.md says "a check right after it reads clean", as wide as row 4's old sentence.
  • Noticed, not changed here: docs/start/getting-started.md says "the report lists exactly what an apply would change or delete", as wide as row 3's old sentence.
  • Noticed, not changed here: docs/start/migrating-from-probot.md says "lists everything an apply would delete", which was not checked against the code here.
  • Noticed, not changed here: docs/reference/semantics.md says "two keys that contradict each other" are refused, with no caveat for the repository private and visibility pair that draws a note.
  • Noticed, not changed here: docs/reference/semantics.md says "A key with no empty state refuses it", with no caveat for repository.security_and_analysis: null, which draws a note.
  • Noticed, not changed here: the row 7 cell in docs/operate/snapshot.md still omits repository, whose readable toggles and two GraphQL-routed keys are read on their own.
  • Noticed, not changed here: 17 other hover texts, among the schema: entries of docs/schema.docs.yml and docs/sections/*.docs.yml, are one paragraph of more than 70 words, the longest UndeclaredPolicyList<*>._layering at 130.
  • Noticed, not changed here: docs/sections/environments.docs.yml says "in every run" three times for the note that row 12 words "in check and in apply".
  • Found beside row 11: a key GitHub only reports, written on a list entry, is neither refused nor noted today, which another change is fixing, so row 11's sentence names only the three shapes that carry a note today.
  • Found beside row 11: a check of labels: [{name: bug, color: d73a4a, description: x, id: 5}] over a live bug prints drift: labels[bug].id: declared 5 != live 90000000; apply will set the declared value and no note.
  • Found beside row 11: id on a ruleset, a webhook, an autolink, or a deploy key, and number on a milestone, draw drift and no note in the same check.

Sixteen sentences, on the pages and in two test files, said what the code no longer does, or said it too widely. Each gets the smallest edit that makes it true, checked against the code it describes. Nothing under src/ changes.

- The fold: a label's name under the rename rule is the one value the higher layer does not win (architecture, the v2-to-v3 layering page).
- The canonical order: the pinned environments keep their written order too (library, the v2-to-v3 index).
- Check and apply: the drift report cannot list the value of a declared secret that already exists. A check right after an apply reports clean where that apply reached the declared state, with three states no apply reaches as examples. A refused entry stops its section, which lists what it left as not attempted (README, semantics).
- Keys GitHub only reports: three passthrough entry shapes name one in a note until the next major refuses it, and the two variables sections say so (semantics, actions_variables, agents_variables, and the regenerated coverage page).
- Directives: a _remove on an entry of a list that is not keyed stays as a field under a warning, and a single document's top-level _layering outside its values warns (layering, architecture, the settings-file upgrade page, the _layering hover).
- The replace sweep stops inside a ruleset's rule, not at its parameters (the run upgrade page, a test comment).
- The snapshot page names the interaction_limits keys read on their own, the --summary row tells a created file from an existing one, and CONTRIBUTING says build:check also refuses an unregistered GENERATED marker.
- One list item and one hover paragraph come under the 70-word cap, and a describe title claims only its own rows.
Copilot AI balanced review requested due to automatic review settings November 12, 2026 07:31
@github-actions

Copy link
Copy Markdown
Contributor

File size check

0 over a hard cap (fails), 6 warning(s).

File Size Tier Cap
src/engine/diff.ts:56 11 comment lines warn 10
src/github/api-error.ts:9 11 comment lines warn 10
src/problem.ts:73 18 comment lines warn 10
src/sections/contract/errors.ts:18 11 comment lines warn 10
src/sections/contract/module.ts:48 12 comment lines warn 10
src/sections/shared/list/decl.ts:265 14 comment lines warn 10

Split the file, wrap the line, shorten or exempt the comment, or list the path in .file-size-allow.local with a # reason.

5 managed file(s) skipped; repo-platform owns them.

@github-actions

Copy link
Copy Markdown
Contributor

Member shape check

22 finding(s).

File Line Rule
src/action/io.ts 24 one-line-comment
src/cli/actions.ts 12 one-line-comment
src/github/api.ts 55 one-line-comment
src/sections/branches/schema.ts 246 all-or-none
src/sections/branches/schema.ts 267 all-or-none
src/sections/branches/schema.ts 405 constant-spacing
src/sections/branches/schema.ts 444 one-line-comment
src/sections/environments/schema.ts 46 one-line-comment
src/sections/environments/schema.ts 108 one-line-comment
src/sections/pages/index.ts 71 one-line-comment
test/cli/actions.test.ts 45 one-line-comment
test/scripts/release-pipeline-fixture.test.ts 25 one-line-comment
test/scripts/release-pipeline-fixture.ts 53 one-line-comment
test/sections/contract/validate-hook.test.ts 80 all-or-none
test/sections/teams/teams.test.ts 20 all-or-none
test/sections/teams/teams.test.ts 23 all-or-none
test/sections/teams/teams.test.ts 24 all-or-none
test/sections/teams/teams.test.ts 25 all-or-none
test/sections/teams/teams.test.ts 26 all-or-none
test/sections/teams/teams.test.ts 28 all-or-none
test/sections/teams/teams.test.ts 31 all-or-none
test/sections/teams/teams.test.ts 34 constant-spacing

Add the blank lines, make the comment one line directly above the item, comment every field or none, or list the path in .member-shape-allow.local with a # reason.

4 generated file(s) skipped.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues block the documentation clarifications.

No open issues 🎉

What changed in this PR

This documentation-only PR aligns GitHub Settings as Code's guidance with existing behavior, correcting broad claims and documenting exceptions. Runtime code, test assertions, and fixtures are unchanged.

Changes:

  • Clarifies layering, validation warnings, drift reporting, and apply behavior.
  • Corrects snapshot permission handling, CLI summary-file behavior, and generated-file checks.
  • Updates schema descriptions, generated coverage documentation, and two test descriptions/comments.
File Description
test/​sections/​repository/​schema.test.ts Narrows the describe title to the settings tested.
test/​engine/​diff.test.ts Clarifies the fixture's passthrough paths in a comment.
README.md Explains why existing secret values do not produce drift.
docs/​upgrading/​v2-to-v3/​settings-file.md Documents two directive cases that warn instead of failing.
docs/​upgrading/​v2-to-v3/​run.md Corrects the ruleset omission-sweep boundary.
docs/​upgrading/​v2-to-v3/​layering.md Notes the label-renaming exception to higher-layer precedence.
docs/​upgrading/​v2-to-v3.md Adds pinned environments to ordering exceptions.
docs/​start/​cli.md Clarifies preservation of existing summary-file contents.
docs/​sections/​agents_variables.docs.yml Documents notes for declared read-only timestamps.
docs/​sections/​actions_variables.docs.yml Documents notes for declared read-only timestamps.
docs/​schema.docs.yml Splits the layering description and explains invalid-value warnings.
docs/​reference/​semantics.md Clarifies convergence limits, stopped operations, and read-only-key exceptions.
docs/​reference/​library.md Corrects canonical ordering guidance for pinned environments.
docs/​reference/​coverage.md Includes generated variable timestamp notes.
docs/​reference/​architecture.md Documents validation warnings and label-renaming precedence.
docs/​operate/​snapshot.md Adds interaction-limit reads to partial-denial examples.
docs/​operate/​layering.md Clarifies unkeyed removal markers and shortens alias-cycle wording.
CONTRIBUTING.md Documents checks for unregistered generated-region markers.

Review effort: Balanced

…le states

The sentence gave the reason "because its section has no write for it". That is literal only for workflows: interaction_limits declares a cap PATCH, and pages declares a create and an update. What the three examples share is that the plan holds no operation that reaches the declared state, so the clause says that.
Copilot AI balanced review requested due to automatic review settings November 12, 2026 08:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues remain for these documentation and wording clarifications.

No open issues 🎉

Review effort: Balanced

@Vivswan Vivswan added the merge-when-green Owner approved: merge once every gate is green label Nov 12, 2026
Copilot AI balanced review requested due to automatic review settings November 12, 2026 09:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues require further changes.

No open issues 🎉

Review effort: Balanced

@Vivswan
Vivswan marked this pull request as ready for review November 12, 2026 09:06
@Vivswan
Vivswan merged commit a8855c9 into main Nov 12, 2026
29 checks passed
@Vivswan
Vivswan deleted the docs/sentences-left-behind branch November 12, 2026 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-when-green Owner approved: merge once every gate is green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants