diff --git a/.github/GOVERNANCE.md b/.github/GOVERNANCE.md index 54145f71f7..c214acba84 100644 --- a/.github/GOVERNANCE.md +++ b/.github/GOVERNANCE.md @@ -146,7 +146,7 @@ but do not replace the approval required from an eligible GitHub reviewer. ## Main Branch Merge Gates -The live [main ruleset](https://github.com/huangruiteng/loopx/rules/18121976) +The live [main ruleset](https://github.com/loopx-project/loopx/rules/18121976) is the operational authority. It requires a pull request, one approving review, code-owner approval where applicable, dismissal of stale approvals, approval of the last push by another reviewer, resolved review threads, and @@ -220,7 +220,7 @@ The versioned [Current Technical Directions](../docs/project/technical-directions.md) page is the canonical map of active strategic programs, maturity, contribution routes, and promotion gates. The pinned -[GitHub Discussion](https://github.com/huangruiteng/loopx/discussions/2851) is +[GitHub Discussion](https://github.com/loopx-project/loopx/discussions/2851) is its community-facing projection; an issue, Discussion, RFC, or integration branch does not override merged runtime and stable reference contracts. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 991975bb67..b2e9338f40 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: | - Thanks for helping improve LoopX. Do not report an unpatched security vulnerability here; use [Private Vulnerability Reporting](https://github.com/huangruiteng/loopx/security/advisories/new). Remove credentials, private data, raw agent sessions, internal links, and local runtime state before submitting. + Thanks for helping improve LoopX. Do not report an unpatched security vulnerability here; use [Private Vulnerability Reporting](https://github.com/loopx-project/loopx/security/advisories/new). Remove credentials, private data, raw agent sessions, internal links, and local runtime state before submitting. - type: checkboxes id: preflight diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index c57e8669e5..9203623c5c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,17 +1,17 @@ blank_issues_enabled: false contact_links: - name: Ask a question - url: https://github.com/huangruiteng/loopx/discussions/categories/q-a + url: https://github.com/loopx-project/loopx/discussions/categories/q-a about: Get community help with usage, configuration, or design questions. - name: Discord community url: https://discord.gg/XmGgQyCFZd about: Join informal onboarding, workflow, and show-and-tell conversations. - name: Report a security vulnerability - url: https://github.com/huangruiteng/loopx/security/advisories/new + url: https://github.com/loopx-project/loopx/security/advisories/new about: Privately report suspected unpatched vulnerabilities. Do not open a public issue. - name: Contributor task board - url: https://github.com/huangruiteng/loopx/blob/main/docs/development/contributor-tasks.md + url: https://github.com/loopx-project/loopx/blob/main/docs/development/contributor-tasks.md about: Start here for public, claimable work. - name: Current technical directions - url: https://github.com/huangruiteng/loopx/blob/main/docs/project/technical-directions.md + url: https://github.com/loopx-project/loopx/blob/main/docs/project/technical-directions.md about: Understand active programs, maturity, ownership boundaries, and promotion gates. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6f109ca6da..f95a319092 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -58,7 +58,7 @@ baseline/head comparison and a failing-before or mutation check, not just test c Documentation-only changes may use a static/manual row and explain runtime N/A. A passing row does not waive required real-path/backend gates. --> -See [validation disclosure guidance](https://github.com/huangruiteng/loopx/blob/main/CONTRIBUTING.md#validation-disclosure). +See [validation disclosure guidance](https://github.com/loopx-project/loopx/blob/main/CONTRIBUTING.md#validation-disclosure). ## Frontend / Visual Evidence diff --git a/.github/SECURITY.md b/.github/SECURITY.md index d2d9782cb3..c81e1e168e 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -10,7 +10,7 @@ version-specific regression. ## Reporting A Vulnerability Please report suspected vulnerabilities through -[GitHub Private Vulnerability Reporting](https://github.com/huangruiteng/loopx/security/advisories/new). +[GitHub Private Vulnerability Reporting](https://github.com/loopx-project/loopx/security/advisories/new). Do not open a public issue, discussion, or pull request for an unpatched vulnerability. diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md index d64f84b2cc..cd1048aa23 100644 --- a/.github/SUPPORT.md +++ b/.github/SUPPORT.md @@ -9,10 +9,10 @@ channels. | Need | Channel | Use it for | | --- | --- | --- | -| Reproducible bug or installation failure | [GitHub Issues](https://github.com/huangruiteng/loopx/issues/new/choose) | Public, sanitized reproduction steps for behavior that can be investigated or fixed in the repository. | -| Feature request | [GitHub Issues](https://github.com/huangruiteng/loopx/issues/new/choose) | A concrete problem, desired outcome, alternatives, and the smallest useful product change. | -| Usage or design question | [GitHub Discussions: Q&A](https://github.com/huangruiteng/loopx/discussions/categories/q-a) | Questions, configuration help, and design discussion that do not yet identify a repository bug. | -| Security vulnerability | [Private Vulnerability Reporting](https://github.com/huangruiteng/loopx/security/advisories/new) | Suspected unpatched vulnerabilities. Do not post them in an issue, discussion, or chat. See [`SECURITY.md`](SECURITY.md). | +| Reproducible bug or installation failure | [GitHub Issues](https://github.com/loopx-project/loopx/issues/new/choose) | Public, sanitized reproduction steps for behavior that can be investigated or fixed in the repository. | +| Feature request | [GitHub Issues](https://github.com/loopx-project/loopx/issues/new/choose) | A concrete problem, desired outcome, alternatives, and the smallest useful product change. | +| Usage or design question | [GitHub Discussions: Q&A](https://github.com/loopx-project/loopx/discussions/categories/q-a) | Questions, configuration help, and design discussion that do not yet identify a repository bug. | +| Security vulnerability | [Private Vulnerability Reporting](https://github.com/loopx-project/loopx/security/advisories/new) | Suspected unpatched vulnerabilities. Do not post them in an issue, discussion, or chat. See [`SECURITY.md`](SECURITY.md). | | Informal peer help | [Discord](https://discord.gg/XmGgQyCFZd) | Onboarding, workflow comparison, show and tell, and community conversation. Chat is not an authoritative support or release record. | Public contributor work belongs on the @@ -25,14 +25,14 @@ requests should follow ## Official Publication Sources -- [GitHub Releases](https://github.com/huangruiteng/loopx/releases) is the +- [GitHub Releases](https://github.com/loopx-project/loopx/releases) is the authoritative source for published versions and release notes. -- [GitHub Discussions: Announcements](https://github.com/huangruiteng/loopx/discussions/categories/announcements) +- [GitHub Discussions: Announcements](https://github.com/loopx-project/loopx/discussions/categories/announcements) is the authoritative source for project announcements that are not tied to one release. The pinned - [Current technical directions and known limitations](https://github.com/huangruiteng/loopx/discussions/2851) + [Current technical directions and known limitations](https://github.com/loopx-project/loopx/discussions/2851) post is the community-facing projection of the versioned repository map. -- [GitHub Security Advisories](https://github.com/huangruiteng/loopx/security/advisories) +- [GitHub Security Advisories](https://github.com/loopx-project/loopx/security/advisories) is the authoritative source for coordinated vulnerability disclosures. Repository documentation describes the current product and contributor @@ -49,7 +49,7 @@ official publication source. Reposts, screenshots, personal accounts, and third-party communities may be useful, but they are not authoritative project communications. When sources conflict, prefer the official GitHub source for the relevant topic and ask for clarification in a public -[Discussion](https://github.com/huangruiteng/loopx/discussions). +[Discussion](https://github.com/loopx-project/loopx/discussions). ## Make A Useful Request diff --git a/examples/repository-hygiene-smoke.py b/examples/repository-hygiene-smoke.py index 76127ab427..cf6dbd747e 100644 --- a/examples/repository-hygiene-smoke.py +++ b/examples/repository-hygiene-smoke.py @@ -34,13 +34,20 @@ # A surface is live by where it is, never by what else its text happens to # contain: it hands an address to a user, a host or another tool at run time, # or it is the command someone copies. -LIVE_SURFACE_PREFIXES = ("loopx/", "scripts/", ".github/workflows/", "packages/") +# `.github/` is whole, not just its workflows: GitHub renders +# `ISSUE_TEMPLATE/config.yml` as the contact links on the new-issue page, and +# `SECURITY.md`, `SUPPORT.md`, `GOVERNANCE.md` and `PULL_REQUEST_TEMPLATE.md` +# each hand an address to the person reading them. +LIVE_SURFACE_PREFIXES = ("loopx/", "scripts/", ".github/", "packages/") # A built bundle is regenerated, not edited, so its baked-in address is fixed by # the release that rebuilds it. This is the tracked-build-output cost #4677 names. GENERATED_ASSET_PREFIXES = ("loopx/web/chat/assets/",) # Where the pre-transfer address is the reviewed-correct content, by path and by # use: this project's own disambiguation terms must keep matching the archived -# address, and prose may cite the pull request an event happened under. +# address, and prose may cite the pull request an event happened under. An entry +# is either a whole use shape or one exact record as ":", and a +# record stays a record: reviewing one dated citation cannot vouch for the old +# addresses later written next to it. REVIEWED_ADDRESS_EXCEPTIONS: dict[str, frozenset[str]] = { "packages/loopx-community-discussion/src/loopx_community_discussion/normalize.py": frozenset({"repository", "issue"}), @@ -49,6 +56,16 @@ "loopx/capabilities/issue_fix/README.md": frozenset({"pull"}), "loopx/capabilities/issue_fix/README.zh-CN.md": frozenset({"pull"}), "packages/loopx-codex-provider-routing/RUNBOOK.md": frozenset({"pull"}), + # Governance records where the project started and which issue settled a + # roster change, each by its exact reference: a category here would also + # tolerate every old-owner commit or issue link later added to the file. The + # ruleset link in the same file is called live and stays under review. + ".github/GOVERNANCE.md": frozenset( + { + "commit:7dcdc9dc79226d157ba57d3e8ff4bae664f020c1", + "issue:4069", + } + ), } DISAMBIGUATION_TERMS_SOURCE = ( "packages/loopx-community-discussion/src/loopx_community_discussion/normalize.py" @@ -87,24 +104,41 @@ def _address_use(raw_path: str) -> str: ) -# A use is either a live pointer this project must own or a dated citation that -# may keep the address the event happened under. -LIVE_ADDRESS_USES = frozenset( - {"repository", "issue_form", "discussion", "release_asset", "main_pointer", "branch"}) +#: Uses that name one reviewable record, so an exception can quote its number. +_IDENTITY_BEARING_USES = ("issue", "pull", "commit") + + +def _address_reference(raw_path: str) -> tuple[str, str | None]: + """Return one occurrence's use plus the single record it names, if any. + + ``issue:4069`` is one dated citation; the bare ``issue`` shape is every + old-owner issue link in a file. Only the occurrence decides either part. + """ + + use = _address_use(raw_path) + if use not in _IDENTITY_BEARING_USES: + return use, None + segments = [part for part in raw_path.strip("/").split("/") if part] + return (use, f"{use}:{segments[1]}") if len(segments) > 1 else (use, None) def stale_address_uses(name: str, text: str) -> list[str]: - """Return the old-address uses in a live surface that were never reviewed.""" + """Return the old-address uses in ``name`` that were never reviewed. + + Every classified use is an offender until a path-and-use exception reviews it, + so widening which files are live cannot quietly reclassify a dated citation as + safe: it has to be judged and named here, and an exception that names a record + covers only that record. + """ tolerated = REVIEWED_ADDRESS_EXCEPTIONS.get(name, frozenset()) - return [ - use - for use in ( - _address_use(match.group(1) or "") - for match in OLD_ADDRESS_RE.finditer(text) - ) - if use not in tolerated - ] + offenders: list[str] = [] + for match in OLD_ADDRESS_RE.finditer(text): + use, record = _address_reference(match.group(1) or "") + if use in tolerated or (record is not None and record in tolerated): + continue + offenders.append(use) + return offenders def tracked_files() -> set[str]: @@ -248,6 +282,50 @@ def _validate_stale_address_classifier() -> None: "main_pointer" ]: raise AssertionError("a documentation pointer must be named as a live address") + advisory = "https://github.com/huangruiteng/loopx/security/advisories/new\n" + if stale_address_uses(".github/SECURITY.md", advisory) != ["security"]: + raise AssertionError( + "the private-vulnerability-reporting entry is how a reporter reaches this " + "project, so it must be named as a live address rather than a citation" + ) + if not _is_live_surface(".github/ISSUE_TEMPLATE/config.yml"): + raise AssertionError( + "GitHub renders ISSUE_TEMPLATE/config.yml as the contact links on its own " + "new-issue page, so it is a live surface" + ) + if stale_address_uses( + ".github/GOVERNANCE.md", + "https://github.com/huangruiteng/loopx/commit/7dcdc9dc79226d157ba57d3e8ff4bae664f020c1\n", + ): + raise AssertionError( + "widening .github/ must not turn a dated history citation into an " + "offender: the commit a project started under keeps that address" + ) + if stale_address_uses( + ".github/GOVERNANCE.md", + "https://github.com/huangruiteng/loopx/issues/4069\n", + ): + raise AssertionError( + "the issue that settled a roster change is cited under the address it " + "happened at, so it must stay tolerated" + ) + if stale_address_uses( + ".github/GOVERNANCE.md", + "https://github.com/huangruiteng/loopx/issues/4070\n", + ) != ["issue"]: + raise AssertionError( + "an exception for one reviewed issue must not tolerate another " + "old-owner issue link in the same file" + ) + if stale_address_uses( + ".github/GOVERNANCE.md", + "https://github.com/huangruiteng/loopx/commit/" + "1111111111111111111111111111111111111111\n", + ) != ["commit"]: + raise AssertionError( + "an exception for one reviewed commit must not tolerate another " + "old-owner commit link in the same file" + ) if _is_live_surface("loopx/web/chat/assets/index-abc123.js"): raise AssertionError( "a generated bundle is outside the guard: its address is fixed by the "