Skip to content
Closed
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
10 changes: 6 additions & 4 deletions docs/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -3055,10 +3055,12 @@ docstrings, string fixtures, and prose. Only spellings required by external
contracts or deliberate spelling-test fixtures are exempt.

Before checking the repository, the generator refreshes the shared/base
en-GB-oxendict dictionary into an untracked local cache only when the authority
is newer, then merges `typos.local.toml`. The generated `typos.toml` is
reviewed and committed so a clean, network-restricted checkout can still
enforce the last known-good policy.
en-GB-oxendict dictionary into an untracked local cache, then merges
`typos.local.toml`. `scripts/generate_typos_config.py` fixes the shared source
to its recorded commit and SHA-256, so a fresh checkout cannot silently adopt a
new `main` policy or render a different document as the selected baseline. The
generated `typos.toml` is reviewed and committed so a clean, network-restricted
checkout can still enforce the last known-good policy.

Put an unavoidable external-contract spelling or a deliberate spelling-test
fixture in `typos.local.toml` as a narrowly anchored `[patterns].ignore` entry.
Expand Down
15 changes: 14 additions & 1 deletion scripts/generate_typos_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
repository-specific policy that must not weaken the estate-wide base.
"""

import hashlib
import logging
import tomllib
import urllib.error
Expand All @@ -28,13 +29,23 @@

DEFAULT_BASE_URL = (
"https://raw.githubusercontent.com/leynos/agent-helper-scripts/"
"refs/heads/main/data/typos-oxendict-base.toml"
"64bd9ce54942562cd89252b66fcedf5683324a78/data/typos-oxendict-base.toml"
)
PINNED_BASE_REVISION = "64bd9ce54942562cd89252b66fcedf5683324a78"
PINNED_BASE_SHA256 = "7eb3d405d49d466f918d189a671afc708fab26f982845ea82be3b1d377166b6a"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
REPOSITORY_ROOT = Path(__file__).resolve().parent.parent

_logger = logging.getLogger(__name__)


def _verify_pinned_base(cache: Path) -> None:
"""Reject a default-source cache whose bytes differ from the pinned base."""
content_hash = hashlib.sha256(cache.read_bytes()).hexdigest()
if content_hash != PINNED_BASE_SHA256:
message = "pinned shared dictionary SHA-256 does not match the baseline"
raise ValueError(message)


def dictionary_from_cache(repository: Path = REPOSITORY_ROOT) -> rollout.Dictionary:
"""Load the cached shared base merged with local repository policy.

Expand Down Expand Up @@ -176,6 +187,8 @@ def main(
if fallback is not None:
return fallback
raise
if source == DEFAULT_BASE_URL:
_verify_pinned_base(repository / ".typos-oxendict-base.toml")
rollout.write_config(destination, dictionary_from_cache(repository))
return result

Expand Down
219 changes: 219 additions & 0 deletions scripts/tests/data/typos-oxendict-base-64bd9ce.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# Shared en-GB-oxendict dictionary for the leynos code estate.
#
# Keep only generally valid Oxford forms and estate-wide terms here. Product
# names, quoted fixtures, and repository-specific identifiers belong in that
# repository's typos.local.toml overlay.

schema = 1

[oxford]
stems = [
"absolut",
"actual",
"alphabet",
"amort",
"anonym",
"apolog",
"atom",
"author",
"canonical",
"capital",
"categor",
"central",
"character",
"civil",
"colon",
"colour",
"common",
"conceptual",
"concret",
"container",
"contextual",
"critic",
"crystall",
"custom",
"daemon",
"decentral",
"denormal",
"derandom",
"deserial",
"desynchron",
"destabil",
"docker",
"dramat",
"emphas",
"energ",
"equal",
"external",
"factor",
"familiar",
"final",
"formal",
"fossil",
"general",
"global",
"harmon",
"homogen",
"human",
"hypothes",
"ideal",
"initial",
"industrial",
"institutional",
"internal",
"international",
"italic",
"item",
"jeopard",
"kernel",
"legitim",
"lemmat",
"linear",
"local",
"material",
"maxim",
"mechan",
"memo",
"memor",
"miniatur",
"minim",
"mobil",
"modern",
"modular",
"monet",
"monomorph",
"monopol",
"moral",
"neutral",
"normal",
"notar",
"operational",
"optim",
"ordinal",
"oxid",
"organ",
"palett",
"parallel",
"parameter",
"parametr",
"parenthes",
"penal",
"personal",
"plural",
"polymer",
"popular",
"priorit",
"privat",
"product",
"public",
"quant",
"random",
"raster",
"rational",
"real",
"recogn",
"regular",
"reinitial",
"reorgan",
"reserial",
"resynchron",
"retoken",
"romantic",
"sanit",
"scrutin",
"serial",
"sexual",
"singular",
"social",
"special",
"stabil",
"standard",
"styl",
"subsid",
"summar",
"symbol",
"synchron",
"synthes",
"system",
"systemat",
"templat",
"terminal",
"theor",
"token",
"trivial",
"unauthor",
"uncategor",
"underutil",
"uninitial",
"unlocal",
"unoptim",
"unparameter",
"unrecogn",
"unsynchron",
"util",
"vector",
"virtual",
"visual",
"weapon",
"zero",
]

[words]
accepted = [
"ASO",
"dialog",
"dialogs",
"handwritten",
"organizational",
"oxendict",
"yse",
]

[words.corrections]
exercize = "exercise"
exercized = "exercised"
exercizes = "exercises"
exercizing = "exercising"
organisational = "organizational"
otherwize = "otherwise"
raize = "raise"
raized = "raised"
raizes = "raises"
raizing = "raising"

[phrases.corrections]
"hand-written" = "handwritten"

[patterns]
ignore = [
'(?s)```.*?```',
'\brust-analyzer\b',
'Azure\s+Architecture\s+Center\s*\|\s*Microsoft\s+Learn\b',
'GitHub\s+Flavored\s+Markdown\b(?:\s\(GFM\))?',
]

[files]
exclude = [
".git",
".hypothesis",
".pytest_cache",
".tox",
".terraform",
".typos-oxendict-base.json",
".typos-oxendict-base.toml",
".uv-cache",
".uv-tools",
".venv",
"Cargo.lock",
"bun.lock",
"data/typos-oxendict-base.toml",
"dist",
"node_modules",
"package-lock.json",
"pnpm-lock.yaml",
"target",
"typos.local.toml",
"typos.toml",
"uv.lock",
"yarn.lock",
]
Loading
Loading