Skip to content
Open
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
59 changes: 59 additions & 0 deletions .cit-quality/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# CIT quality tooling

This directory contains vendored contributor tooling, separate from project
source. It is maintained and tested in `cloud-innovation-team/cit-codex-skills`.

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.

[P2] Remove private-source disclosure from the public repository

Current main requires source, documentation, PR descriptions, and review comments to avoid naming or linking private components and repositories. This provenance block identifies an internal repository and internal implementation paths. Please replace it with public, self-contained provenance. Because the details also appear in this PR's commits and description, clean those surfaces too rather than only deleting the final-tree text.

Executing the local copy requires no GitHub authentication or source-repository
access.

## Provenance

- Installed file: `.cit-quality/vendor/check_nfc_filenames.py`.
- Upstream file:
`skills/cit-repository-quality-scaffolding/scripts/check_nfc_filenames.py`.
- Source revision: `2dbf02d13b73799d2fcf1d3c7bab0a8371fd82ee`.
- Source SHA-256:
`83d3bb79ebf3a5d6cb4f213f3af4421bd258693057514637ce87f3fc00a79056`.
- Upstream suite:
`skills/cit-repository-quality-scaffolding/scripts/test_scaffolding.py`.

The upstream behavioral suite tests rejection of non-NFC tracked filenames,
acceptance after a byte-preserving rename, and normalization collisions. It also
exercises the installed copy through the generated pre-commit hook. This
provenance identifies the source; rendering alone does not establish a passing
test run. Record the source revision and actual upstream validation in the PR.

## Upstream validation

On 2026-10-07, three focused upstream tests passed:

- `test_vendored_checker_is_separate_from_project_source` (includes the
installed hook).
- `test_normalization_collision_is_reported_without_renaming`.
- `test_non_nfc_tracked_name_fails_hook_until_byte_preserving_rename`.

Command:
`uv run --script <skill>/scripts/test_scaffolding.py -v -n 2 -k "vendored_checker_is_separate or normalization_collision_is_reported or non_nfc_tracked_name_fails_hook_until_byte_preserving_rename" --durations=5`.

Result: `3 passed` on Python 3.13.11; rerun during this refresh. This is focused
validation, not a claim that the entire upstream suite or all checker failure

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.

[P2] Keep regression coverage in a publicly verifiable location

This note acknowledges that the focused validation did not exercise every checker failure path, and this repository still contains no durable tests for the required quality gate. The cited upstream suite is not available to public contributors or reviewers. Please add local tests, or point to a public pinned source with equivalent tests, covering clean paths, non-NFC paths, normalization collisions, invalid UTF-8, unavailable/failed Git invocation, CLI exit codes, and diagnostics.

paths were exercised.

## Review and updates

Review source provenance, updates, and the repository's hook integration.
Implementation tests are maintained upstream; duplicate project tests are not
required for an unchanged, upstream-tested copy. Local behavior changes require
normal implementation review and appropriate regression coverage.

Update the checker and this provenance note together from the scaffolding skill.
Preserve the copied bytes; contribute fixes upstream instead of editing the
vendored copy. Keep this directory out of project source, test discovery,
coverage, and distribution inputs where those tools would otherwise traverse it.
The `linguist-vendored` attribute classifies the code; it does not disable
GitHub review requirements.

Run the installed hook from the repository root:

```shell
uvx --from pre-commit==4.6.2 pre-commit run check-nfc-filenames --all-files
```
87 changes: 87 additions & 0 deletions .cit-quality/vendor/check_nfc_filenames.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# /// script
# requires-python = ">=3.11"

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.

[P3] Keep the required hook compatible with Python 3.10

The repository targets Python 3.10–3.14, and this script does not use any Python 3.11-only syntax or APIs. Declaring >=3.11 can require an extra uv-managed interpreter—or warn/fail in restricted 3.10-only contributor environments. Please change this to >=3.10 and update the corresponding README statement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The SDK compatibility baseline and the contributor tooling baseline are different here. At this PR's head, .python-version selects Python 3.11, and pre-commit CI explicitly uses 3.11. The SDK remains compatible with 3.10, with the test matrix covering 3.10–3.14. This script is contributor tooling, so its declared 3.11 minimum matches the established development environment.

I also verified that direct execution under Python 3.10 succeeds; explicitly selecting 3.10 through uv succeeds with the metadata warning you described. Lowering the requirement would be a reasonable portability improvement, but a 3.10-only contributor environment is outside the currently configured development baseline. I would treat this as a non-blocking suggestion rather than an SDK compatibility defect, and retain the current declaration and README wording.

# ///
"""Reject tracked Git paths that are not UTF-8 NFC, including collisions."""

from __future__ import annotations

import argparse
import subprocess
import sys
import unicodedata
from pathlib import Path
from typing import Any


def tracked_filename_report(root: Path) -> dict[str, Any]:

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.

[P2] Add automated coverage for the checker’s failure paths

This function is now part of the required quality gate, but the PR does not add regression tests for non-NFC paths, normalization collisions, invalid UTF-8, missing Git, or a failed git ls-files invocation. The manual validation described in the PR will not prevent these guarantees from regressing later. Please add focused pytest coverage for the clean and failure cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed on the coverage gap: there are no automated tests for this checker in the current PR, and the manual validation does not provide lasting regression protection. Focused pytest cases for clean paths, non-NFC names, normalization collisions, invalid UTF-8, missing Git, and a failed git ls-files invocation are appropriate for a gate that can block contributor commits. The CLI exit codes and diagnostics should also be asserted so the tests cover the observable hook behavior. I consider this a valid finding to address before merging.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The NFC checking script is now injected in a location that is marked for not needing review. It's tested in the skill repository.

"""Inspect raw index paths, not filesystem names or quoted Git status text."""
process = subprocess.run(
["git", "ls-files", "--cached", "-z"],
cwd=root,
check=False,
capture_output=True,
)
if process.returncode != 0:
return {
"checked": False,
"error": process.stderr.decode("utf-8", errors="replace").strip(),
"issues": [],
"collisions": [],
}

paths: list[str] = []
invalid_utf8: list[str] = []
for raw_path in process.stdout.split(b"\0"):
if not raw_path:
continue
try:
paths.append(raw_path.decode("utf-8"))
except UnicodeDecodeError:
invalid_utf8.append(raw_path.decode("utf-8", errors="backslashreplace"))

by_nfc: dict[str, list[str]] = {}
for path in set(paths):
by_nfc.setdefault(unicodedata.normalize("NFC", path), []).append(path)
collisions = [
{"nfc_path": normalized, "paths": sorted(originals)}
for normalized, originals in sorted(by_nfc.items())
if len(originals) > 1
]
issues = [
{
"path": path,
"nfc_path": normalized,
"collides_with": sorted(other for other in originals if other != path),
}
for normalized, originals in sorted(by_nfc.items())
for path in sorted(originals)
if path != normalized
]
return {
"checked": True,
"issues": issues,
"collisions": collisions,
"invalid_utf8": sorted(invalid_utf8),
}


def main() -> int:
"""Print actionable failures for a local pre-commit hook."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo", type=Path, default=Path.cwd())
args = parser.parse_args()
report = tracked_filename_report(args.repo)
if not report["checked"]:
print(f"Cannot inspect tracked filenames: {report['error']}", file=sys.stderr)
return 2
for issue in report["issues"]:
print(f"Non-NFC tracked path: {issue['path']!r} -> {issue['nfc_path']!r}")
if issue["collides_with"]:
print(f" Normalization collision with: {issue['collides_with']!r}")
for path in report["invalid_utf8"]:
print(f"Tracked path is not UTF-8: {path!r}")
return 1 if report["issues"] or report["invalid_utf8"] else 0


if __name__ == "__main__":
raise SystemExit(main())
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ root = true

[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
indent_size = 2
max_line_length = 80

Expand Down
2 changes: 1 addition & 1 deletion .editorconfig-checker.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"Version": "v3.4.0",
"Version": "v3.11.1",
"Verbose": false,
"Debug": false,
"IgnoreDefaults": false,
Expand Down
59 changes: 45 additions & 14 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# BEGIN source: https://github.com/gitattributes/gitattributes/blob/2c20a14833a5ab196c7fc3effcc72ef4e895f4d4/Common.gitattributes
# Common settings that generally should always be used with your language specific settings

# Auto detect text files and perform LF normalization
# https://www.davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
* text=auto

#
Expand All @@ -10,26 +10,28 @@

# Documents
*.bibtex text diff=bibtex
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.md text
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.md text diff=markdown
*.mdx text diff=markdown
*.tex text diff=tex
*.adoc text
*.textile text
*.mustache text
*.csv text
*.csv text eol=crlf
*.tab text
*.tsv text
*.txt text
*.sql text
*.epub diff=astextplain

# Graphics
*.png binary
Expand All @@ -39,7 +41,7 @@
*.tif binary
*.tiff binary
*.ico binary
# SVG treated as an asset (binary) by default.
# SVG treated as text by default.
*.svg text
# If you want to treat it as binary,
# use the following line instead.
Expand All @@ -49,7 +51,9 @@
# Scripts
*.bash text eol=lf
*.fish text eol=lf
*.ksh text eol=lf
*.sh text eol=lf
*.zsh text eol=lf
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
*.cmd text eol=crlf
Expand All @@ -64,10 +68,24 @@

# Archives
*.7z binary
*.bz binary
*.bz2 binary
*.bzip2 binary
*.gz binary
*.lz binary
*.lzma binary
*.rar binary
*.tar binary
*.taz binary
*.tbz binary
*.tbz2 binary
*.tgz binary
*.tlz binary
*.txz binary
*.xz binary
*.Z binary
*.zip binary
*.zst binary

# Text files where line endings should be preserved
*.patch -text
Expand All @@ -78,6 +96,9 @@

.gitattributes export-ignore
.gitignore export-ignore
.gitkeep export-ignore
# END source: https://github.com/gitattributes/gitattributes/blob/2c20a14833a5ab196c7fc3effcc72ef4e895f4d4/Common.gitattributes

# Basic .gitattributes for a python repo.

# Source files
Expand Down Expand Up @@ -106,3 +127,13 @@
# with the python modules ``pickle``, ``dbm.*``,
# ``shelve``, ``marshal``, ``anydbm``, & ``bsddb``
# (among others).

# Service inputs must survive checkout byte-for-byte, including LF-only CSVs.
/tests/resources/** -text !eol
/examples/resources/** -text !eol
# Resource helpers are maintained Python, not immutable test data.
/tests/resources/**/*.py text eol=lf
/tests/resources/**/*.pyi text eol=lf

# CIT quality tooling is vendored, not project source.
/.cit-quality/vendor/** linguist-vendored
38 changes: 0 additions & 38 deletions .github/workflows/basedpyright.yml

This file was deleted.

51 changes: 0 additions & 51 deletions .github/workflows/docs.yml

This file was deleted.

Loading
Loading