{"owner":"newton-physics","repo":"newton","hasSkills":true,"totalSkillsCount":14,"totalTokensCount":29338,"categories":["anthropic-skill","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":[".agents/skills/code-review-newton/SKILL.md",".agents/skills/release-audit/SKILL.md",".agents/skills/release-audit/agents/openai.yaml",".agents/skills/release-audit/references/classification-rules.md",".agents/skills/release-audit/references/language-review-examples.md",".agents/skills/release-audit/references/render-rules.md",".agents/skills/release-audit/references/report-template.md",".agents/skills/release-changelog/SKILL.md",".agents/skills/release-notes/SKILL.md",".claude/skills/code-review-newton/SKILL.md",".claude/skills/release-audit/SKILL.md",".claude/skills/release-changelog/SKILL.md",".claude/skills/release-notes/SKILL.md","AGENTS.md"],"skills":{".agents/skills/code-review-newton/SKILL.md":"---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nRead `REVIEW_GUIDELINES.rst` and `CODING_GUIDELINES.rst` in full. Treat the\nformer as the explicit definitions of the Fit, Requirements, and Standards\naxes, and enforce the latter during Standards review.\n\n1. Resolve the exact merge base and head. Read the complete\n   `merge-base..head` diff and commit list.\n2. Read the pull-request description, linked issue or specification, relevant\n   primary sources, and `CODING_GUIDELINES.rst`. If no separate specification\n   exists, use the pull-request description as the stated intent. Do not read\n   existing review comments yet.\n3. Perform an adversarial correctness-first Requirements pass. Trace changed\n   inputs, state, counts, offsets, ownership, and outputs through every relevant\n   supported execution mode. Check applicable zero/one/many and capacity\n   boundaries, heterogeneous inputs, toggle/reset/reuse and partial failures,\n   CPU/CUDA and backend differences, autodiff, determinism, graph capture, and\n   numerical invariants. For performance changes, examine setup and steady-state\n   complexity, allocations, synchronization, transfers, and whether benchmarks\n   exercise the changed path. Answer the Honest contract, Siblings, Tests, and\n   Cost questions in `REVIEW_GUIDELINES.rst`. Run a minimal adversarial probe\n   when feasible. Apply the guides' schema and importer checks to authorable\n   features, including behavioral equivalence and explicit acceptance of\n   deferrals.\n4. Freeze candidate findings before reading existing reviews. Record the\n   location, triggering input or condition, mechanism, observable impact,\n   evidence, and confidence for each candidate.\n5. Read the top-level discussion and review threads. Refine or deduplicate the\n   independently discovered concerns; acknowledge existing concerns when they\n   affect the verdict.\n6. Review Fit and Standards independently using their definitions in\n   `REVIEW_GUIDELINES.rst`, and answer its Simplest and Principled questions\n   as part of Fit. When independent agent contexts are available, use separate\n   passes so one conclusion does not bias another.\n7. Report Fit and architectural concerns first, but retain every supported\n   material behavioral, correctness, compatibility, and performance finding\n   even when Fit fails. Do not let missing tests, documentation, or measurements\n   replace the search for an underlying behavioral defect.\n8. For each remaining concern, state its priority, location, problem, impact,\n   and evidence. Distinguish demonstrated defects from questions, evidence\n   requests, requirements, and judgment calls. Do not prescribe a correction\n   unless the user asks for one.\n\nAggregate the three axes without suppressing a finding merely because another\naxis passes. Give the explicit Fit verdict defined by the review guide.\n",".agents/skills/release-audit/SKILL.md":"---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\n---\n\n# Release Audit\n\nGenerates a markdown audit of a Newton release for keep/defer decisions (or, in retrospective mode, for skill calibration). Three modes, auto-detected in Phase 1:\n\nRead `CODING_GUIDELINES.rst` and `REVIEW_GUIDELINES.rst` from the\nrepository root before auditing. They define the canonical coding, API, and\nreview policies. This skill performs the final cross-release reconciliation;\nit does not replace pull-request review, and a prior review pass does not make\nany audit phase optional. In retrospective mode, using the current guides is\nintentional: calibrate the current audit policy against evidence pinned to the\ntarget tag. Do not claim historical noncompliance unless the requirement also\nexisted at that tag.\n\n- **Pre-release**: spot-check while work is still landing on main. No release branch cut. Version string is `X.Y.Z.devN`.\n- **Release-candidate**: readiness review after the release branch is cut. Version string is `X.Y.ZrcN` or head is `release-X.Y`.\n- **Retrospective**: audit an already-shipped release (e.g., `v1.1.0`) against its predecessor, with a Calibration Notes section (Phase 7) that checks the audit's flags against what subsequent patch/minor releases actually did. Triggered by passing a bare released-version argument that matches an existing git tag.\n\n**Output:** a single markdown report, filed according to the destination chosen in Phase 1:\n- **Secret gist** (default when `gh` is available and authenticated): stable filename `newton-<version-string>-<prerelease|rc|retrospective>-report.md`, stable description `Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report`. Later runs against the same version revise the same gist in place; prior versions are preserved in the gist's git history.\n- **Local markdown file** (fallback when `gh` unavailable, or opt-in when `gh` available): dated path at `$(git rev-parse --show-toplevel)/newton-<version-string>-<prerelease|rc|retrospective>-report-<YYYY-MM-DD>.md`. Not auto-committed; user moves, shares, or deletes as desired.\n\n**Inputs inferred from repo state:**\n- Pre-release / RC: target version from `pyproject.toml` (`version = \"...\"`). `newton/_version.py` reads from installed metadata at runtime and is not a static source.\n- Retrospective: target version from the user's argument. `pyproject.toml` is ignored.\n- Base = latest tag matching previous minor's line (`vX.Y-prev.*`, latest patch).\n- Head (pre-release / RC) = `upstream/release-<target>` if it exists, else `upstream/main`. Head (retrospective) = the `vX.Y.Z` tag itself.\n\n**Reference documents to load on demand** (via `Read`):\n- `references/report-template.md` — fill this in during Phase 7b (the `{{HEADLINE_SUMMARY}}` placeholder is drafted in Phase 7a).\n- `references/render-rules.md` — rendering conventions and output style hard constraints for Phase 7b.\n- `references/classification-rules.md` — path/symbol rules used in Phases 3-5.\n- `references/language-review-examples.md` — Phase 5 language-review calibration.\n\n## Phase 1 — Align on scope\n\n1. **Determine the mode.** Look at any target-version argument supplied with the invocation:\n\n   - **Argument present AND matches an existing tag** (`git rev-parse --verify v<arg>` or `git rev-parse --verify <arg>` succeeds, AND the resolved name looks like `vX.Y.Z` / `vX.Y.ZrcN`): **Retrospective mode**. The argument is the already-shipped target version. Skip `pyproject.toml` entirely; the tag is authoritative. Do not run the pre-release / RC reconciliation in step 4.\n   - **Argument present but does NOT match any tag**: treat as a version override for the upcoming release. Use it as if it came from `pyproject.toml`, then fall through to the pre-release / RC detection below.\n   - **No argument**: read the version string from `pyproject.toml` — the top-level `[project]` table's `version = \"...\"` line.\n\n   Normalize the selected version by removing one leading `v`, if present. Before using it in a title, filename, or path, require the normalized value to match `^[0-9]+\\.[0-9]+\\.[0-9]+(?:rc[0-9]+|\\.dev[0-9]+)?$`. If it does not match, stop and report the unsupported version. Do not construct an output path from an unvalidated version string.\n\n   Record the report date at the same time. In retrospective mode, use the target tag's creator date:\n   ```bash\n   git for-each-ref --format='%(creatordate:short)' refs/tags/v<version>\n   ```\n   This returns the tagger date for an annotated tag and the commit date for a lightweight tag. For pre-release and RC modes, use the current date (`date +%F`).\n\n   For the non-retrospective path, parse the version string to extract the target minor (e.g., `1.2.0.dev0` → target `1.2`) and pre-classify mode:\n   - If the version string contains `\"rc\"` (e.g., `1.2.0rc1`) → **RC mode candidate**: this is a release-candidate readiness report.\n   - If the version string contains `\"dev\"` (e.g., `1.2.0.dev0`) → **Pre-release mode candidate**: this is an early-stage audit of unreleased work.\n   - Otherwise → pre-release mode (default), but record the raw version string so the header can show it as-is.\n\n2. **Enumerate previous-minor tags** (applies to all modes):\n   ```bash\n   git tag --list 'v<prev-major>.<prev-minor>.*' --sort=-v:refname\n   ```\n   where `<prev-major>.<prev-minor>` is `target - 0.1` (e.g., for target `1.2`, previous minor is `1.1`). Retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`; release-candidate and other prerelease tags are not release baselines. Take the first remaining result as the base candidate. Ignore pre-1.0 `beta-*` tags when a stable `vX.Y.Z` line exists.\n\n   **Major-boundary fallback.** When `target.minor == 0` (e.g., `2.0.0`), the `target - 0.1` computation yields a minor line that never existed (`1.9`), and the tag list comes back empty. In that case, enumerate the highest minor line of the previous major instead:\n   ```bash\n   git tag --list 'v<target-major - 1>.*' --sort=-v:refname\n   ```\n   Apply the same exact stable-release filter, then take the first result (the last-patch of the last-minor of the previous major) as the base candidate. If both the primary and fallback searches return empty (which should only happen on a never-released line), surface that to the user in step 6 rather than silently proceeding.\n\n   For **retrospective mode** with target `X.Y.Z`: the base is the last `vX.Y-prev.*` tag strictly before `vX.Y.Z`. Also check whether `X.Y.Z` is itself a patch release (`.Z > 0`): if so, the \"base\" could be either the previous patch on the same minor (`vX.Y.<Z-1>`) OR the previous minor's latest. Present both in step 6 and let the user pick — a patch retrospective usually wants patch-on-patch; a minor-release retrospective wants previous-minor's last patch.\n\n3. **Probe for the head**:\n   - **Retrospective mode**: head is the `vX.Y.Z` tag directly. Resolve with `git rev-parse --verify v<target>`.\n   - **Pre-release / RC**:\n     ```bash\n     git rev-parse --verify upstream/release-<target>\n     ```\n     If this succeeds, head = `upstream/release-<target>` and this is also a strong signal for **RC mode** (the branch-cut has happened). Otherwise try `origin/release-<target>`; otherwise head = `upstream/main` (falling back to `origin/main`, then `main`) which is **pre-release mode**. Record whichever fallback was used for the report header.\n\n4. **Reconcile mode** from version string and head (skipped for retrospective mode; its mode is already fixed):\n   - Version says RC AND head is a release branch → **RC report** (strong match).\n   - Version says RC but head is main (branch not cut yet) → **RC report** (version is authoritative; note the mismatch in the header).\n   - Version says dev AND head is a release branch → **RC report** (branch cut implies we're past the dev window).\n   - Version says dev AND head is main → **Pre-release report**.\n\n5. **Probe `gh` availability and look up any existing matching gist.**\n\n   First run:\n   ```bash\n   gh --version && gh auth status\n   ```\n   If either fails → `gh` unavailable; destination will be a local markdown file only; skip the rest of this step.\n\n   Both succeeded → compute the stable gist title for this report:\n   ```text\n   Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report\n   ```\n   (e.g., `Newton 1.2.0rc1 Release Candidate Report`, `Newton 1.2.0.dev0 Pre-Release Report`, `Newton 1.1.0 Retrospective Report`). No date. The gist filename and description are stable so later runs can find the same gist and revise it; gist git history preserves prior versions automatically.\n\n   Run `gh gist list --limit 1000` and filter rows whose description exactly matches that stable title. Capture the matching gist IDs; display URLs are `https://gist.github.com/<id>`. Record the match count (0, 1, or N ≥ 2) for step 6.\n\n6. Present proposal in chat and **wait for explicit user confirmation** of refs AND output destination. Mandatory pause.\n\n   Lead with the mode-specific intro line:\n   - Pre-release: `Generating **pre-release report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>**. **<N>** commits in range.`\n   - RC: `Generating **release-candidate report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>** (release branch cut). **<N>** commits in range.`\n   - Retrospective: `Generating **retrospective report** for Newton **<version>** (already shipped). Base **<base-ref>** → Head **v<version>**. **<N>** commits in range. Calibration pass will cross-reference the audit's flags against subsequent patch / minor releases.`\n\n   For retrospective mode with a patch-target (when `.Z > 0`), also present the base choice explicitly:\n   > Base candidates for retrospective of `vX.Y.Z`:\n   > 1. `vX.Y.<Z-1>` (patch-on-patch: what changed since the previous patch on the same minor)\n   > 2. `v<prev-major>.<prev-minor>.<latest-patch>` (minor-boundary: what changed since the previous minor)\n   >\n   > Pick (1) or (2), or specify a different base.\n\n   Append the output block for the current `gh` / match state:\n\n   **`gh` unavailable:**\n   > Output: markdown file at repo root (`gh` not available). Confirm, or specify different refs?\n\n   **`gh` available, 0 matches:**\n   > Output: (a) new secret gist [default], (b) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, 1 match:**\n   > Output: (a) revise existing gist `<url>` [default], (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, N matches (N ≥ 2):**\n   > Multiple existing gists share the stable title:\n   > 1. `<url-1>` — updated `<time-1>`\n   > 2. `<url-2>` — updated `<time-2>`\n   > ...\n   >\n   > Output: (a) revise gist by number, (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   Do not run any further phase until the user confirms refs and (when `gh` is available) chooses destination. Translate the user's reply into exactly one of the destination tokens `local`, `new-gist`, `revise-gist:<id>` and record it for Phase 7c. Letters `(a)`, `(b)`, `(c)` are positional within the current branch's prompt, not global: resolve them against the option list you just showed the user. For the N-match branch, the user picks a gist by the number you listed (e.g., \"revise 2\" → `revise-gist:<id-of-listed-row-2>`), or says new / local.\n\n## Phase 2 — Gather ground truth\n\n1. Run the commit-list tool:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n     --base <base-ref> \\\n     --head <head-ref> \\\n     --report-date \"<report-date>\" \\\n     --main-ref <resolved-main-ref>\n   ```\n   from the repo root (`$(git rev-parse --show-toplevel)`). Use the date recorded in Phase 1 so retrospective bake time is measured as of the audited release rather than as of today. Capture stdout as the `commit_list_json`.\n\n2. Run the dependency and license audit helper:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py \\\n     --base <base-ref> \\\n     --head <head-ref>\n   ```\n   from the repo root. The helper requires Python 3.11+ for stdlib TOML parsing and exits with a clear preflight error on older Python versions. Capture stdout as `dependency_license_audit_md`. The helper compares:\n   - Direct requirements in `pyproject.toml`, grouped by runtime and optional extra.\n   - Resolved package names, duplicate variants, and version sets in `uv.lock` when present.\n   - `project.license` and `project.license-files` metadata in `pyproject.toml`.\n   - In-tree notice files matched by the `project.license-files` pathspecs declared at the base or head ref.\n   - Version-specific PyPI license metadata for newly introduced package names and changed locked package versions when network access is available. If metadata lookup fails, keep the helper's \"not checked\" text and surface that uncertainty rather than filling in a guessed license. If the helper was run with `--skip-pypi`, treat package-index metadata as deliberately deferred, not as per-package review failures.\n\n   Use one helper invocation as the source of the entire dependency/license section. Do not splice prose from a live metadata check onto tables produced by `--skip-pypi`. If a sandboxed or deferred run used `--skip-pypi` and a later host-side run can reach package indexes, replace the complete section with the default host-side output. Use `--skip-pypi` only as a fallback when a live metadata pass cannot be completed.\n\n   In Existing Resolved Package Version-Set Changes, the helper keeps standard license expressions and review statuses inline. Legacy or verbose nonstandard license text is rendered as a compact package-metadata link rather than copied into the report. The helper wraps this potentially long table in a closed `<details>` block; keep it collapsed by default so it does not dominate report scrolling.\n\n   The helper is intentionally stdlib-only. Do not replace it with a dependency inventory tool during the audit run: Newton avoids new release-only dependencies, and this script needs deterministic comparisons across arbitrary git refs without installing the target environment. External tools such as `pip-licenses`, `cyclonedx-py`, `pip-audit`, or `syft` can supplement a deeper investigation, but they do not replace this git-ref diff over `pyproject.toml`, `uv.lock`, declared license files, and version-specific PyPI metadata.\n\n   Interpretation rules for `dependency_license_audit_md`:\n   - A newly introduced external direct dependency or new resolved package name is license-relevant even when it lives behind an optional extra. Do not dismiss optional dependencies; state the extra or install path that pulls them in.\n   - A package that first appears in the lockfile only beneath a direct dependency already declared at the base is resolved-set churn, not a new dependency. The helper renders it in Existing Resolved Package Version-Set Changes with `(not resolved)` as the base and attributes the existing direct root. Reserve New Resolved Packages for packages introduced by a new direct dependency root or packages whose root cannot be established.\n   - A new optional extra whose dependencies are all already present is a support/install-surface change, but not a new package-license change.\n   - Existing package version bumps are not new licenses by themselves. The helper separates direct requirement moves from transitive-only churn; only elevate version bumps to release highlights or Behavioral & Support Changes when the package pin or compatibility constraint is user-visible.\n   - In-tree notice-file additions, removals, or modifications under the declared `project.license-files` pathspecs always appear in the dependency/license section. If a notice file is missing for a new bundled asset or vendored component, flag it in CHANGELOG Review Notes.\n   - If the helper reports license metadata as \"not checked\" due to lookup failure or \"not declared\" for a new package, keep that wording and mark it as needing release-manager review. Do not infer a license from package authorship or project name.\n   - If the helper reports \"not evaluated (--skip-pypi)\", say that package-index metadata was deferred and should be checked before final release sign-off. Do not turn that into a per-package review list.\n   - If a new package is proprietary, copyleft, commercial, unknown, not declared, or not checked due to lookup failure, mention that in the release highlights only when users can install it through a published extra or documented workflow.\n\n3. Load the pending or released changelog source by mode:\n   - **Pre-release / RC**: user-facing release scope is the rolling\n     `## [<target-version>]` section in `CHANGELOG.md`, when already assembled,\n     plus any later `.md` fragments on the resolved head. Before the first\n     Towncrier build, use the fragments plus legacy `[Unreleased]` entries.\n     Enumerate `changelog/*.md` with\n     `git ls-tree -r --name-only <head> -- changelog`, exclude `README.md`,\n     and read each file with `git show <head>:<path>`. Inventory `.skip` files\n     separately. Read `CHANGELOG.md` with `git show <head>:CHANGELOG.md`. If the\n     target's dated section exists, collect it through the next dated heading\n     and treat it as the assembled baseline. Otherwise, legacy entries are\n     between `<!-- towncrier release notes start -->` and the next dated `##`\n     heading.\n     If the audited head is the checked-out clean working tree, also run:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Use the draft output as the canonical preview for fragments not yet folded\n     into the rolling section; it does not modify `CHANGELOG.md` or delete\n     fragments. Audit the assembled baseline and draft additions together.\n   - **Retrospective**: read the target tag's changelog with\n     `git show v<target>:CHANGELOG.md`. Locate the `## [<target-version>]`\n     header and collect content up to the next dated `##` heading.\n\n4. Parse entries. Infer a fragment's section from its filename type (`added`,\n   `changed`, `deprecated`, `removed`, or `fixed`); the file content is one\n   entry without a leading bullet. Parse legacy or dated Markdown under the\n   corresponding five `###` headings. For every entry, extract:\n   - **Raw text (FULL — never truncate)**: the full bullet content (may span multiple lines).\n   - **Section**: one of the five names above.\n   - **Source path**: the fragment path or `CHANGELOG.md`.\n   - **Fragment identifier**: the numeric issue or leading-`+` orphan prefix\n     from the filename. Same-category counters do not change the identifier.\n   - **GH refs**: regex `GH-(\\d+)` over the bullet text. Dedup. (Newton commits and CHANGELOG entries sometimes also reference `#NNNN` as a bare PR number; capture these too.)\n   - **Migration hint**: does the prose contain a migration phrase (`use <new>`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`)? Record a boolean.\n\n   **Newton does NOT use a `**Breaking:**` literal marker in CHANGELOG** (unlike Warp). Do not rely on its presence. Breaking-change detection in Newton comes from: (a) the `### Removed` section (implicitly breaking), (b) signature-diff AST analysis (Phase 4e), and (c) reading `### Changed` prose for rename / parameter-reorder / signature-shift language (Phase 4d).\n\n## Phase 3 — Cross-reference\n\n1. **Build the commit ↔ CHANGELOG join** on GH-ref overlap:\n   - For each CHANGELOG entry with at least one GH ref, find commits (from `commit_list_json`) whose `gh_refs` intersect.\n   - For each pending fragment, find the commit that added its exact path:\n     ```bash\n     git log --reverse --diff-filter=A --format='%H|%s|%cs' \\\n       <base-ref>..<head-ref> -- changelog/<fragment-filename>\n     ```\n     Numeric identifiers link to issues, not necessarily to the implementing\n     pull request, so the fragment-addition commit is the authoritative join.\n   - For legacy entries and any fragment still lacking a backing commit, put\n     the distinctive substring in `entry_text` without interpolating it into\n     shell source, then search exact text across both storage forms:\n     ```bash\n     git log --reverse -S\"$entry_text\" \\\n       --format='%H|%s|%cs' <base-ref>..<head-ref> -- CHANGELOG.md changelog\n     ```\n     The first commit that is not a Towncrier build, synchronization, or another\n     changelog-only edit usually is the code change associated with the entry.\n     Record that as the backing commit.\n   - After these two passes, any CHANGELOG entry still with no matching commit is a genuine orphan case (deferred/dropped). Keep full entry text; do not truncate in the report.\n\n2. **Do NOT build an audit trace of unmatched commits.** The old \"commits without CHANGELOG entries\" appendix adds noise without value. Commits that don't map to a CHANGELOG entry are not surfaced in the report.\n\n## Phase 4 — Analyze API surface\n\n### 4a — Determine what is genuinely NEW API\n\nFor each CHANGELOG `Added` entry, extract the named symbol(s) — text in backticks matching `newton.*`, bare `ClassName`, bare `snake_case_name()`, or `ClassName.method()` patterns.\n\nFor EACH named symbol, check if it existed at base. Newton exposes user-facing symbols through multiple public re-export modules (not a single `__init__.py`). See `references/classification-rules.md` → \"Public API surface\" for the discovery rules. `docs/generate_api.py::api_modules()` discovers top-level public modules from module-valued names in `newton.__all__`; `solver_submodule_pages()` adds public solver module trees. There is no fixed `MODULES` constant. Inspect this discovery code plus `newton/__init__.py` and `newton/solvers.py` at both refs because the exported module set may grow or shrink between releases.\n\nTo check presence at base, run `git show <base>:<path>` for each relevant public module and grep its imported names. For method additions on an existing class (e.g., `SolverXPBD.update_contacts()`), inspect the class body at base in its real source (resolved via `_src/`). For retrospective mode, \"HEAD\" in the symbol-resolution text below means the `v<target>` tag, not the working tree. Use `git show v<target>:<path>` everywhere the pre-release / RC flow uses the working tree.\n\nClassification:\n- **Genuinely new** (symbol was not present at base) → **New API** section.\n- **Existed at base** (entry is adding a new parameter, option, or capability to something that already existed) → **Changes to Existing API** section with a \"capability extension\" or \"new parameter\" kind. Cite the backing commit's signature diff.\n- **Does not name a single symbol** (e.g., \"Interactive example browser in the GL viewer with tree-view navigation\") and describes a cross-cutting capability → **Behavioral & Support Changes** section unless one of the mentioned symbols is genuinely new (in which case split: put the new symbol in New API, the capability description in Behavioral).\n\n**If an entry mentions multiple symbols where some are new and some pre-existed** (e.g., \"Add `newton.geometry.compute_offset_mesh()` and a viewer toggle\"), split: the genuinely new symbols each get a New API entry; the extensions to existing symbols each get a Changes entry.\n\n**Public-API declaration and exposure check.** At HEAD, inspect every public\nmodule discovered by `api_modules()` and `solver_submodule_pages()`. Each module\nmust define `__all__` as a list or tuple containing only strings; a missing or\ninvalid declaration is a policy finding in \"CHANGELOG Review Notes\". For every\nsymbol that passes the \"genuinely new\" test, collect its memberships across\nthose declarations:\n\n- No memberships: report 🕵️ Private-only. The symbol exists only under\n  `newton._src.*` and was not re-exported through a public module.\n- One membership: the symbol has a canonical public import path.\n- More than one membership: report a duplicate-public-export policy finding\n  and list every public module that exports it.\n\n`CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one\npublic module's `__all__` and forbids examples/docs from importing\n`newton._src`. Do not treat the private-only finding as a hard block on the\nentry; surface it so the release manager can confirm the symbol was intended\nto be public. Treat missing or invalid declarations and duplicate exports as\npolicy findings that require an explicit release decision.\n\n### 4b — Resolve New API signatures + docstrings\n\nFor each symbol confirmed as new:\n\n1. Find its real source module by following the re-export in the public module (e.g., `newton/solvers.py` → `newton/_src/solvers/xpbd.py`).\n2. `ast.parse` the source module; find the `FunctionDef` / `ClassDef` / `AsyncFunctionDef`.\n3. Extract the signature by re-stringifying the args (preserve type annotations).\n4. Extract the docstring verbatim via `ast.get_docstring(node)`.\n5. Render as shown in the template.\n\nNewton has no kernel-scope builtins layer to extract (no `add_builtin()` registry like Warp). All user-facing symbols live in Python modules and `ast` resolves them directly.\n\n### 4c — Symbol resolution fallbacks\n\n- **Symbol in backticks doesn't resolve at HEAD**: render the entry with a ⚠️ note: \"Couldn't resolve `<symbol>` in source — verify entry names a real public symbol.\" Do not fabricate a header like `newton.*(no symbol)*`. Use the entry's natural subject as the section title.\n- **Entry describes a topic, not a symbol** (e.g., \"Interactive example browser in the GL viewer\"): use a short descriptive title summarized from the entry (e.g., \"Interactive example browser\"), not a synthetic `newton.*` name.\n- **Header naming rule**: section headers in the report should be either real fully-qualified symbols (`newton.solvers.SolverXPBD.update_contacts`) OR short descriptive titles extracted from the entry. Never `newton.*`, `newton.(something)`, or similar stub patterns.\n\n### 4d — Changed / Removed / Deprecated signature diffs\n\nFor each CHANGELOG entry in Changed / Removed / Deprecated (plus any \"capability extension\" entries routed here from 4a):\n\n- Compute signatures at base and HEAD (same resolution as 4b).\n- For signature-shape changes: render a fenced `diff` block showing `-` and `+` lines.\n- For semantic-only changes (no signature shift) where the prose describes a rename / reorder / behavioral flip: skip the diff block; include the backing commit's URL and the full CHANGELOG text.\n- For Removed entries: show the old signature on a `-` line; omit `+`.\n\n**Deprecation-window lookup for Removed entries.** Newton's policy (per `CODING_GUIDELINES.rst`) is: *breaking changes require a deprecation first*. Every Removed entry needs evidence of a deprecation in a prior release. Start with the released CHANGELOG, then fall back to code-level runtime-warning evidence at the base ref. For every Removed entry (and every Changed entry whose prose describes a removal), search CHANGELOG.md for the matching prior Deprecated entry:\n\n1. Extract distinctive tokens from the Removed entry: the named symbol(s) in backticks and, if the entry carries a GH ref, that ref number.\n2. Scan the appropriate released-version sections of CHANGELOG.md for a `### Deprecated` bullet that names the same symbol(s) OR the same GH ref. The search scope depends on mode:\n   - **Pre-release / RC**: scan all dated sections, top-down. Pending fragments and legacy current-cycle entries do not prove a prior shipped deprecation.\n   - **Retrospective** (current target is `X.Y.Z`): scan ONLY the sections strictly below `## [X.Y.Z]` in CHANGELOG.md — the prior-release sections. Do NOT consider `## [Unreleased]` or later-version sections; they were written after `X.Y.Z` shipped and cannot have preceded it. Top-down within the allowed range.\n   The FIRST such entry (highest version, since CHANGELOG is reverse-chronological) is the deprecation introduction.\n3. If a matching CHANGELOG entry is found, record: (a) the release version heading that contains the Deprecated entry (e.g., `1.0.0`), (b) the full Deprecated entry text.\n4. If no matching prior CHANGELOG entry is found, check for a code-level runtime deprecation at the base ref. Resolve candidate source paths using the removed symbol, legacy parameter, or literal value, then grep those paths for deprecation warnings and inspect the surrounding source:\n   ```bash\n   git grep -n -F '<distinctive-symbol-or-legacy-value>' <base-ref> -- newton\n   git grep -n -E 'DeprecationWarning|deprecated' <base-ref> -- <candidate-paths>\n   git show <base-ref>:<candidate-path>\n   ```\n   If the candidate uses a shared deprecation helper or decorator, resolve the imported name and inspect its definition at the base ref too:\n   ```bash\n   git grep -n -F '<helper-or-decorator-name>' <base-ref> -- newton\n   git show <base-ref>:<helper-definition-path>\n   ```\n   Count this as prior-deprecation evidence when a runtime `DeprecationWarning` at the base ref clearly applies to the exact removed symbol or behavior, either through a direct `warnings.warn(...)` call or through a shared helper / decorator. For helper-mediated evidence, verify both sides of the connection: the candidate path applies or calls the helper for the removed API, and the helper definition emits `DeprecationWarning` for the calling mode or behavior being removed. For example, `@deprecate_nonkeyword_arguments` is evidence for removing positional-argument support only when it decorates that callable at the base ref; it is not evidence that the callable itself was deprecated. A generic helper that merely exists or is imported, a warning elsewhere in the same file, a docstring without a runtime warning, or a warning added only after the base release does not count. Record the warning text, the helper application path, and the warning-emission path. The base ref proves the deprecation shipped by that release; only claim an earlier introduction version if the same connected evidence is verified at that earlier tag.\n5. In the rendered Removed entry, include one of these deprecation-window lines:\n   - CHANGELOG evidence: `Deprecated in X.Y.Z; removed here.`\n   - Runtime-only evidence: `Runtime deprecation present in <base-ref>; removed here. No matching prior CHANGELOG Deprecated entry was found.`\n   - No evidence: `No prior deprecation found in released CHANGELOG sections or in code at <base-ref> — Newton's policy requires deprecation before removal.`\n   Do NOT fabricate a version.\n\nThe deprecation window belongs in BOTH the Breaking Changes entry for the removal AND the Changes-to-Existing-API row (in the Description cell or as an appended sentence in the detail block). A reader should never have to ask \"was this deprecated first, and for how long?\"\n\n**Missing-deprecation flag.** Surface `🚨 Policy: removed without prior deprecation` only when BOTH checks fail: no prior Deprecated entry exists in a previously-released CHANGELOG section, and no matching direct or helper-mediated runtime `DeprecationWarning` exists at the base ref. This fires whether or not the current release's own `### Deprecated` section also names the symbol because a warning added only in the removal release did not ship in a prior release. The release manager needs this to block the release or add migration tooling.\n\nIf a matching runtime warning exists at the base ref but the released CHANGELOG has no corresponding Deprecated entry, the deprecation window is real. Do not emit a policy violation. Instead, add a non-blocking `🧾 Deprecation omitted from CHANGELOG` review note with the base ref, warning text, and the direct source path or connected helper application / emission paths so the release-note gap remains visible.\n\n**Exception: `1.0.0` pre-stable cleanup.** Removed entries in the `1.0.0` release (and `1.0.0rcN`) are exempt from the deprecation-first policy — PRs labeled `1.0-release` are the pre-stable API cleanup and were not required to go through a prior deprecation window. When the target version is `1.0.0` or `1.0.0rcN`, do not emit the `🚨 Policy` flag or the \"No prior **Deprecated** entry found\" line for its Removed entries. Still render the deprecation-window line if a matching Deprecated entry happens to exist; otherwise note `1.0 pre-stable cleanup; no prior deprecation required.`\n\n### 4e — Signature-AST diff for unlabeled migration-required changes\n\nIndependently of CHANGELOG content, compute the public API surface at base vs. HEAD by walking every symbol re-exported from the public modules in 4a:\n\n- Base: `git show <base-ref>:<module.py>` for each public module and for every real-source module it re-exports from → parse with `ast`. Resolve each re-export's real signature at base.\n- Target: same as Base, but at the target ref — the working tree in pre-release / RC mode, or `git show v<target>:<module.py>` in retrospective mode. Do NOT read the working tree in retrospective mode; later commits on `main` would otherwise be falsely attributed to `vX.Y.Z`.\n- For each symbol whose signature shape changed AND whose matching CHANGELOG entry (if any) doesn't indicate a rename / parameter shift / removal → add to Breaking Changes section as \"unlabeled signature change — please verify\".\n\n**Exception: Removed symbols are breaking by definition.** A symbol that appears in CHANGELOG's `Removed` section does NOT need prose hedging to be valid. Do NOT flag Removed entries as \"unlabeled breaking\" — the section name itself communicates the breakage. Removed entries surface in the Breaking Changes callout and in the Changes-to-Existing-API section (as \"removed\" kind), but the report must not whinge about missing Breaking labels on them.\n\n**Exception: additive keyword-only parameters with defaults are not migration-required.** A signature change that only adds new kwargs with defaults after `*` is additive; do not surface in Breaking Changes. It belongs in Changes-to-Existing-API with Kind `new parameter` and Breaking `No`.\n\n### 4f — Semantic-change candidates from solver / integrator commits\n\nNewton has no native C++/CUDA code (unlike Warp); there is no build-and-run verification step. However, changes to solver internals, integrators, collision pipelines, and math helpers can still change observable numerical behavior without altering any signature.\n\nFor each commit in `commit_list_json` that touches paths under `newton/_src/solvers/**`, `newton/_src/sim/**` (integrator / collision code), or `newton/_src/math/**`:\n\n1. Skip if the commit is already mapped to a CHANGELOG entry explicitly describing the semantic shift.\n2. Read the commit's diff: `git show --stat <sha>` then `git show <sha>` for small diffs, or read specific hunks for large ones.\n3. **Triage** into one of three buckets:\n   - **Clearly not semantic-breaking** → drop. Examples: renaming internal symbols, comment / format changes, pure internal refactors, performance optimizations that preserve output, test-only changes, bug fixes where the pre-fix behavior was itself a bug.\n   - **Clearly semantic-shifting** with an obvious user-observable numerical / behavioral change visible from the diff alone → include in Breaking Changes with a short \"Before / After\" explanation derived from the diff and commit message.\n   - **Ambiguous** — the diff suggests the change could affect numerical output but the audit cannot establish from reading alone whether users would notice → add a concise entry in a \"Review candidates\" subsection of CHANGELOG Review Notes (NOT Breaking Changes). Include the commit, the touched file(s), and a one-sentence hypothesis. Do not speculate in Breaking Changes.\n\n**Do NOT attempt to build and run Newton at base vs. HEAD.** Newton's solver outputs depend on Warp, MuJoCo, and GPU state; reproducing a numerical diff in a one-shot audit is not reliable and not worth the setup cost. When in doubt, route to the review-candidates list and leave verification to the release manager.\n\n### 4g — Experimental-marker cross-reference\n\nSome Newton features ship with an explicit `experimental` note in the CHANGELOG entry that introduced them (e.g., \"Add differentiable rigid contacts (experimental)\") or in docstrings. Changes to those features do NOT carry the same stability contract as changes to stable APIs. The report must reflect that so the release manager does not over-weight the concern.\n\nFor each entry in Breaking Changes, Changes to Existing API, and Removed (as collected through 4a–4f), determine whether the affected symbol or feature area is currently experimental:\n\n1. Collect candidate symbols / feature-area phrases from the entry: backticked identifiers, class names, and (for topic-style entries) the most distinctive descriptive noun phrase.\n2. Search CHANGELOG.md in released-version sections for bullets that name one of the candidates AND contain the literal substring `experimental` (case-insensitive). Also match via GH ref if the current entry and a prior experimental entry share a GH number. Scope:\n   - **Pre-release / RC**: all dated sections.\n   - **Retrospective** (current target is `X.Y.Z`): everything below `## [X.Y.Z]`. The stability-promotion check (step 3 below) likewise only considers versions strictly before `X.Y.Z`.\n3. If a match exists AND there is no subsequent CHANGELOG bullet in a later released version explicitly promoting the symbol to stable (e.g., \"Promote X out of experimental\", \"Stabilize Y\"), the symbol is still experimental. Record: (a) the release version that introduced the symbol as experimental, (b) the full text of that introduction bullet.\n4. Also check the module source at HEAD for an in-code `.. experimental` / `Experimental:` / `experimental_api` / `@experimental` annotation on the symbol's declaration. If present, treat as experimental regardless of CHANGELOG signal.\n\nTag every matched entry internally as `experimental=True`. Do not alter the CHANGELOG text itself.\n\n**How the tag changes rendering:**\n- Breaking Changes heading for the entry: prefix with `Experimental:` and do not use a warning emoji. Include a short sentence reminding readers that the symbol is opt-in and has a looser stability contract, with the release where the experimental marker was introduced.\n- Changes-to-Existing-API table: the Breaking column shows `Experimental` rather than `Yes`.\n- Release Highlights bullet (Phase 7a): if the item independently clears the significance bar, use a neutral `Experimental:` label without a warning emoji. Experimental status alone does not make an item a highlight.\n\n**Never drop the entry from the detailed audit.** Experimental status changes the stability interpretation, not the underlying API diff. A removed or signature-changed experimental symbol still appears in Breaking Changes and Changes to Existing API, but it is not presented as a release-manager warning.\n\n### 4h — Schema and importer completeness\n\nApply the guides' schema/importer policy to new or substantially changed\nauthorable features across the audited range, including existing-API extensions\nand commits without changelog entries. Inspect schema definitions/proposal\nrevisions, parsing, compatible schema-package versions, and behavioral tests at\nthe audited ref; schema representation alone is not complete support.\n\nRender **Schema & Importer Support** with columns\n`Feature | Disposition | Evidence / remaining work`:\n\n- **Supported**: record the supported subset and cite schema-to-builder-to-runtime\n  evidence, tests against equivalent builder-created models, and verified schema\n  semantics.\n- **Explicitly deferred**: cite review acceptance, reason, issue, owner, and\n  target milestone, plus the remaining limitation.\n- **Not applicable**: explain why the feature is runtime-only or non-authorable.\n- **Gap / decision required**: identify missing support, evidence, or accepted\n  deferral details for a keep/defer decision.\n\nFor retrospective audits, distinguish current-policy gaps from violations of\nrequirements in force at the target tag.\n\n## Phase 5 — Review CHANGELOG language and bake\n\n### 5a — Language review\n\nRead `references/language-review-examples.md`. For EACH CHANGELOG entry, apply LLM judgment:\n\n- **🔗 Wrong ref (tier-1)**: for every GH ref in the entry, fetch the mapped commits' subjects and paths. If the entry topic doesn't match the commits' actual scope, flag.\n- **🔗 Wrong ref (tier-2)**: if `gh --version` and `gh auth status` both succeed, run `gh issue view <num> --json title,body` per ref and compare issue title to entry topic. Skip silently if `gh` unavailable.\n- **🗣️ Internal language**: internal module paths (`newton._src.*`), private identifiers with a leading underscore, Warp-internal types (`wp.types.*` that are not documented user types), implementation-detail verbs (\"refactor\", \"reorganize\", \"rewrite\") without a user-visible outcome.\n- **📝 Too terse**: under ~10 words with no context, or missing migration guidance in a Deprecated / Changed entry that names a rename or removal.\n- **🕵️ Private-only symbol**: the CHANGELOG `### Added` entry names a symbol that exists only in `newton._src.*` at HEAD and is not re-exported through a public module. See Phase 4a.\n- **⬆️ Missing migration guidance** (Newton-specific): entries in `### Deprecated`, `### Removed`, or `### Changed` (where the prose indicates rename / reorder / removal) MUST include migration guidance per `changelog/README.md` (\"Use `Y` instead\", \"in favor of `Y`\", \"switch to `Y`\"). Flag entries that rename or remove symbols without pointing to the replacement.\n- **🏷️ Naming-convention drift** (Newton-specific): new public symbols in `### Added` whose names violate Newton's prefix-first convention (e.g., `PDActuator` should be `ActuatorPD`; `add_sphere_shape()` should be `add_shape_sphere()`). See `CODING_GUIDELINES.rst`.\n\nRecord flagged entries. Keep the FULL entry text in the audit table — do not truncate.\n\n### 5b — Bake aggregation\n\nFrom `commit_list_json`:\n- Bucket each commit's `days_in_main` into **🟢 (>14 days)**, **🟡 (7–14 days)**, **🟠 (<7 days)**. Commits whose `days_in_main` is `null` (no main equivalent) skip bucketing — do NOT coerce `null` to `0` or compare it to a numeric threshold; those commits are accounted for in the next bullet instead.\n- Count anomalies: commits with `main_equivalent_sha == null`. If non-zero, prepare the ⚠️ banner for the report header.\n\n### 5c — Dependency and license audit\n\nUse `dependency_license_audit_md` from Phase 2 as the report's `{{DEPENDENCY_LICENSE_AUDIT}}` section. Apply the interpretation rules listed with the helper invocation in Phase 2.\n\n## Phase 6 — Calibration Notes (retrospective mode only)\n\n**Skip this phase entirely in pre-release / RC mode.** There is no shipped history to calibrate against.\n\nIn retrospective mode, the Phase 3–5 output is a set of flags and classifications that would have surfaced had the skill been run *before* `X.Y.Z` shipped. The point of calibration is to check those flags against what *actually* happened after the release — did the concerns hold up? The output of this phase is a \"Calibration Notes\" section in the report (Phase 7b renders it).\n\n### 6a — Enumerate post-target history\n\nIdentify releases that shipped strictly after `X.Y.Z`:\n\n```bash\ngit tag --list 'v*' --sort=v:refname\n```\n\nBefore selecting post-target history, retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`. Exclude release-candidate and other prerelease suffixes. From that filtered, sorted list, drop everything up to and including `vX.Y.Z` and keep the rest. Typical post-target history for a minor release `vX.Y.0` is:\n- `vX.Y.1`, `vX.Y.2`, ... (patch releases on the same minor)\n- `vX.Y+1.0`, `vX.Y+1.1`, ... (the next minor and its patches)\n\nFor each post-target tag, read its CHANGELOG section (the `## [<version>]` block in `CHANGELOG.md` at HEAD, or via `git show <tag>:CHANGELOG.md` if the section has since been edited). Parse the five subsections (`Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`) the same way Phase 2 does.\n\nAlso collect the commits in each post-target range (`<prior-tag>..<tag>`) — one full `list_commits.py` invocation per range, with the same required args as Phase 2. `--main-ref` reuses the main ref resolved in Phase 1 (don't rely on the script's `upstream/main` default; Phase 1 may have fallen back to a different remote):\n\nFor each retained post-target tag, derive `<post-target-release-date>` with the same `git for-each-ref --format='%(creatordate:short)'` command used in Phase 1. This keeps any soak-time metadata relative to that release rather than the day the retrospective audit happens.\n\n```bash\nuv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n  --base <prior-tag> \\\n  --head <tag> \\\n  --report-date \"<post-target-release-date>\" \\\n  --main-ref <resolved-main-ref>\n```\n\nThese commits become the evidence pool for validating the Phase 4f semantic-change candidates.\n\n### 6b — Cross-reference audit flags against post-target history\n\nFor each flag class, run the check below and record one of three outcomes per flag:\n- **Validated** — subsequent history confirms the audit concern was real.\n- **Invalidated** — subsequent history contradicts the audit concern (false positive).\n- **Unresolved** — no post-target evidence either way (flag stands as-is, but the reader can treat it as lower-confidence).\n\nThe calibration section groups results by flag class and, within each, by outcome. Never drop a flag from the original report body because of calibration — the calibration is a separate layer of commentary.\n\n**🚨 Missing-deprecation (Removed without prior evidence):**\n- Validated if: (a) no prior released CHANGELOG section names the deprecation, (b) no matching direct or helper-mediated runtime `DeprecationWarning` exists at the retrospective base ref, and (c) the symbol stays removed. Users actually lost the API without a deprecation window.\n- Invalidated if: a prior Deprecated entry existed that the audit missed. Re-scan CHANGELOG scope with fuzzier matching (different casing, plural / singular, alternate backtick placement). Report the missed entry with its version.\n- Invalidated if: the base ref contains a matching direct or helper-mediated runtime `DeprecationWarning`. Report the warning text and the direct source path or connected helper application / emission paths, and classify the missing CHANGELOG bullet as a documentation gap rather than a deprecation-policy violation.\n- Invalidated if: a later patch (`vX.Y.<Z+1>`) added the symbol *back* (revert). Name the revert commit and note \"removal reverted in vX.Y.<Z+1>\".\n\n**🕵️ Private-only (new public API with `_src`-only reachability):**\n- Validated if: a later release adds a re-export for the symbol through a public module (`newton.<module>.py`). Cite the release and the re-export commit.\n- Invalidated if: the symbol stays reachable only via `_src` in every post-target release AND no issues reference it — it was probably intentional internal-only despite its position in the Added section. Note this as \"intended internal; CHANGELOG language could have been clearer\".\n- Unresolved if: the symbol was removed / renamed before re-export resolution.\n\n**⬆️ Missing-migration-guidance:**\n- Validated if: a later release's CHANGELOG bullet (in `### Changed` or `### Fixed`) retroactively points to the replacement, OR a subsequent issue references users stuck on the migration. The second signal is only available if `gh issue list` returns matches for the symbol name; probe with `gh issue list --search \"<symbol>\" --state all --json number,title`.\n- Invalidated if: the migration was handled by a runtime `DeprecationWarning` with a clear message (grep the code at `v<target>` for the warning text).\n- Unresolved: default.\n\n**🏷️ Naming-convention drift:**\n- Validated if: a later release renames the symbol to match Newton's prefix-first rule, typically with a DeprecationWarning on the old name. Cite the rename commit and the release.\n- Invalidated if: the symbol stays and matches the *local* module convention rather than the global prefix-first rule (e.g., a module of siblings that all use `<Kind>Foo`). Note which convention it actually follows.\n- Unresolved: default.\n\n**Phase 4f semantic-change candidates** (the ones routed to \"Review Candidates\", not Breaking Changes):\n- Validated if: a later patch release's `### Fixed` entry touches the same file(s) and describes a symptom consistent with the candidate's hypothesis (e.g., \"Fix convergence regression in SolverXPBD step ordering\" after a candidate about solver step ordering). Cite the fix commit and the release.\n- Invalidated if: the file stayed stable for the rest of the minor line with no related bug reports. Probe `gh issue list --search \"<file-or-feature>\" --state all --json number,title,createdAt` if `gh` is authenticated — only count issues created after `v<target>`'s release date. Skip the probe silently if `gh` is unavailable.\n- Unresolved: default.\n\n**Deprecation-follow-through (new check, retrospective-only):** for every entry in `X.Y.Z`'s own `### Deprecated` section, check subsequent minor releases for the corresponding `### Removed` entry.\n- **Followed through** — a later minor removed the symbol as promised. Cite the release.\n- **Still deprecated** — symbol remains in the public surface with the deprecation warning in all later minors. No action required; just a fact.\n- **Silently dropped** — symbol was removed but no `### Removed` entry cites it (CHANGELOG hygiene bug in the later release). Flag this as a separate concern.\n\n### 6c — Compose the calibration narrative\n\nAggregate the per-flag outcomes into a short section with this shape:\n- One-paragraph headline: how many flags were validated / invalidated / unresolved overall, a\n\n<!-- [TRUNCATED AT 50KB] -->",".agents/skills/release-audit/agents/openai.yaml":"policy:\n  allow_implicit_invocation: false\n",".agents/skills/release-audit/references/classification-rules.md":"# Classification Helpers\n\nThis reference is loaded during Phases 3, 4, and 5 of the skill. It defines concrete path and naming rules the audit relies on when analyzing commits and CHANGELOG entries.\n\n## Public API surface (Phase 4a, 4e)\n\nUsed to decide whether a symbol is \"genuinely new\" vs. \"pre-existed and got extended\":\n\nNewton exposes its public surface through per-topic re-export modules discovered dynamically by `docs/generate_api.py`:\n\n- `api_modules()` imports `newton`, starts with the top-level module, and adds every module-valued name exported through `newton.__all__`.\n- Each discovered module's own `__all__` list or tuple defines its public symbols. `public_symbols()` rejects missing declarations, invalid containers, and non-string entries.\n- `solver_submodule_pages()` adds public solver submodules and recursively exposed module trees under `newton.solvers`.\n- There is no fixed `MODULES` constant. Inspect `docs/generate_api.py`, `newton/__init__.py`, and `newton/solvers.py` at both refs so additions such as a new top-level public module or nested experimental solver namespace are included.\n\nRepresentative modules include `newton.geometry`, `newton.solvers`, and `newton.viewer`. Each public module re-exports from `newton/_src/<topic>/...`. `newton._src` is internal (`CODING_GUIDELINES.rst`: examples and docs must not import from `newton._src`).\n\n**To determine if `newton.X` existed at base**:\n- Inspect module-valued exports in `newton.__all__` at base and target using the `api_modules()` rules above.\n- For top-level symbols: `git show <base>:newton/__init__.py` and check `from ._src.<submodule> import X` / `__all__`.\n- For submodule public attributes (e.g., `newton.geometry.Mesh`): `git show <base>:newton/geometry.py` and check imports / `__all__`.\n- For nested solver modules: apply `solver_submodule_pages()` reachability rules to `newton.solvers` at the relevant ref.\n- For method additions on an existing class (e.g., `SolverXPBD.update_contacts`): resolve the class's real source file (e.g., `newton/_src/solvers/xpbd.py`) and `ast`-walk it at base.\n\n**Public-API declaration and exposure check (Phase 4a addition)**: inspect every discovered public module at HEAD. Its `__all__` must be a list or tuple containing only strings. For every genuinely new symbol, collect all public-module `__all__` declarations that contain it. Zero memberships raise a 🕵️ Private-only flag; one establishes the canonical public import path; more than one raises a duplicate-public-export policy finding listing all paths. Reason: `CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one public module's `__all__` and forbids examples/docs from importing `newton._src`.\n\n## No kernel-scope builtin registry\n\nNewton has no separate builtin registry to audit. All user-facing symbols are ordinary Python classes, functions, enums, and constants defined in `newton/_src/**` and re-exported through the public modules above. Skip kernel-scope symbol extraction.\n\n## Paths that trigger Phase 4f semantic-change review\n\nCommits touching these paths get per-commit judgment (Phase 4f). Not every change in them is a semantic shift — the audit reads the diff and decides:\n\n- `newton/_src/solvers/**` — solver implementations (XPBD, MuJoCo, Featherstone, VBD, implicit MPM). Changes can alter convergence, contact handling, step semantics.\n- `newton/_src/sim/**` — integrators, collision pipeline, model building, state transfer. Changes can alter per-step dynamics or contact ordering.\n- `newton/_src/math/**` — math helpers, raycast, quaternion utilities. Changes can shift numerical output.\n- `newton/_src/geometry/**` — geometry primitives, SDF / mesh representations, support functions. Changes can shift contact normals, distances, or inside/outside tests.\n\nTypical NOT-SEMANTIC-SHIFTING signals in these paths:\n- Pure internal refactors, renames of internal identifiers.\n- Comment or formatting changes.\n- Performance optimizations that preserve observable output (e.g., vectorization, precomputed AABBs).\n- Caching / memoization where the cached value is equivalent.\n- Test-only changes.\n- Build-system touches.\n- Bug fixes where the previous behavior was demonstrably wrong.\n\nTypical SEMANTIC-SHIFTING signals:\n- Algorithm swaps that produce different numerical results (e.g., switching SDF construction from winding-number to parity).\n- Default parameter value changes that affect physics (e.g., changing MPM quadrature, contact stiffness, solver iteration defaults).\n- Ordering / determinism changes that affect contact reduction or constraint solving.\n- Convergence criteria changes (different tolerance, different iteration bound behavior).\n- Unit / frame-of-reference changes for authored values (e.g., \"stop multiplying joint damping by 180/π\").\n- Control-flow changes that alter when callbacks / registered hooks / user kernels are invoked.\n\n**Never attempt to build and run Newton at base vs. HEAD for verification.** Newton's output depends on Warp codegen, MuJoCo, and GPU state; reliable head-to-head numerical verification in a one-shot audit is out of scope. When in doubt, route the commit to a \"Review candidates\" section in the report's review notes rather than speculating in Breaking Changes.\n\n## Heuristic paths commonly relevant (reference only)\n\nThese are noted here so the audit can pattern-match when reading commits, but the skill does NOT use them to produce an appendix-style commit audit. Purpose is recognition, not bucketing:\n\n- `.github/**`, `.pre-commit-config.yaml`, `uv.lock`, `.python-version` — infrastructure, not user-facing.\n- `asv.conf.json`, `asv/**`, root-level `_bench_*.py` — benchmark harness.\n- `docs/**`, root-level `*.md`, `CHANGELOG.md`, `changelog/**` — documentation.\n- `newton/examples/**` — example scripts. New files here are user-facing (a new example is a release-notable addition). Changes to existing examples are typically not release-notable unless they change the example's registered name or behavior.\n- `newton/_src/**` other than the solver / sim / math / geometry paths above — internal Python implementation.\n- `pyproject.toml`, `uv.lock`, and files matched by `project.license-files` — dependency and license-audit inputs. New external dependency names, direct requirement scope changes, new resolved package names, and notice-file changes belong in \"Dependency & License Audit\". Version bumps are not release-notable on their own; dependency changes may also belong in \"Behavioral & Support Changes\" if a user-visible pin moves (e.g., `mujoco-warp ~=3.7.0`).\n\n## Newton-specific rename and parameter-reorder recognition (Phase 4d, 5a)\n\nNewton's CHANGELOG does NOT use the `**Breaking:**` literal marker. Instead, migration-required changes appear in `### Changed` with prose like:\n\n- \"Rename `X.old_name` to `X.new_name`. Old name still accepted as keyword argument but emits a `DeprecationWarning`.\"\n- \"Reorder `X()` parameters so `a` precedes `b`.\"\n- \"Migrate all Y logic to Z, all Y functions now return ...\"\n\nWhen Phase 4d / 5a encounter these patterns, treat them as migration-required changes (Kind `rename` or `parameter reorder` in the Changes-to-Existing-API table). Check that the entry includes migration guidance (`Use ...`, `in favor of ...`, `prefer ...`). If guidance is missing, raise a ⬆️ flag in the language review.\n\n## Deprecation policy (Phase 4d)\n\n`CODING_GUIDELINES.rst`: breaking changes require a deprecation first. A prior released `### Deprecated` entry is the preferred evidence. A matching runtime `DeprecationWarning` at the base ref also proves that users received a deprecation window, even if the released CHANGELOG omitted it. The warning may be emitted directly or by a shared helper / decorator that clearly applies to the removed API or behavior.\n\nWhen Phase 4d cannot find the prior Deprecated entry:\n- Resolve the symbol or legacy behavior in code at the base ref.\n- Run a targeted `git grep` for `DeprecationWarning` / `deprecated` in the candidate path and inspect the warning context.\n- If the candidate calls or applies a shared deprecation helper / decorator, resolve that name and inspect its definition at the base ref. Verify that the candidate's call site connects the helper to the exact removed API or behavior and that the helper emits `DeprecationWarning`. A generic helper's existence or import alone is not evidence.\n- If a matching direct or helper-mediated runtime warning exists, record the base ref, warning text, and the direct source path or connected helper application / emission paths. Do not emit a policy violation; flag the missing released CHANGELOG entry as a documentation gap.\n- If no matching warning exists, surface `🚨 Policy: removed without prior deprecation` in the Breaking Changes section and cite the Removed entry in full.\n- Note whether the current CHANGELOG's own `### Deprecated` section also names the same symbol. Deprecating and removing in the same release is a policy violation because the warning did not ship in a prior release.\n\nA release manager reading the report should see one of three resolved outcomes:\n1. Prior CHANGELOG entry found: report its release version.\n2. Runtime `DeprecationWarning` found at base: deprecation policy satisfied, with a non-blocking CHANGELOG documentation flag.\n3. Neither found: block the release or add a deprecation shim for one more release cycle.\n\nDo not infer a policy violation from CHANGELOG evidence alone. The code-level check is mandatory before raising the blocking flag.\n",".agents/skills/release-audit/references/language-review-examples.md":"# CHANGELOG Language Review Examples\n\nLoaded during Phase 5 of the skill. Use these examples to calibrate the language-review pass: flagging entries whose language would confuse end users, whose refs look wrong, or whose content violates Newton's conventions.\n\n## What to flag\n\n### 🗣️ Internal / implementation language\n\nFlag entries that reference:\n\n- **Internal module paths**: `newton._src.foo`, `newton._src.solvers.xpbd.internal_helper`.\n- **Warp-internal helpers** that leaked into user-facing prose: e.g. `warp.fem.geometry.closest_point` (a Newton internal refactor may cite this; it is internal to Warp).\n- **Private identifiers** with leading underscores: `_foo`, `Model._finalize`.\n- **Implementation-detail verbs** without a user-visible outcome: \"Refactor internal dispatch path\", \"Reorganize private helpers\", \"Rewrite foo bar\".\n\nGood examples (user-facing):\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes from any collision shape, and a viewer toggle to visualize gap + margin wireframes in the GL viewer.\n>\n> Use pre-computed local AABB for `CONVEX_MESH` shapes in `compute_shape_aabbs`, avoiding a per-frame support-function AABB computation.\n\nFlag these:\n\n> Inline a `wp.vec3`-specialized point-to-triangle squared-distance helper in the implicit-MPM rasterized collider, removing the dependency on Warp's internal `warp.fem.geometry.closest_point`.\n> *Reason:* references `warp.fem.geometry.closest_point`, which is Warp-internal. User-facing rewrite: \"Inline point-to-triangle distance in the implicit-MPM collider so it no longer depends on Warp's `warp.fem` module.\"\n>\n> Refactor `newton._src.solvers.xpbd._update_constraints` to unify storage path.\n> *Reason:* references internal module + private method. Implementation detail with no user-observable effect. Candidate for deletion from CHANGELOG, not rewording.\n\n### 📝 Too terse\n\nFlag entries that are too short to convey meaning or that omit enough context for a user to act on:\n\n- Under ~10 words AND no linked issue for context.\n- Entries like \"Fix bug in XPBD solver\" without specifying which bug or what the fix does.\n\nFlag:\n\n> Fix bug.\n> *Reason:* insufficient — user can't tell what was fixed.\n>\n> Improve solver performance.\n> *Reason:* no specifics; which solver, how much, under what conditions?\n\nDon't flag (long but load-bearing):\n\n> Fix MJCF importer in `compiler.angle=\"degree\"` mode: (1) stop multiplying joint `damping`/`stiffness` by `180/π` (MuJoCo stores these in `N·m·s/rad` and `N·m/rad` regardless of `angle`); (2) stop `deg2rad`-scaling the default `±MAXVAL` sentinel for joints without an explicit `range=`.\n\n### 🔗 Suspected wrong GH reference\n\nFlag when the CHANGELOG entry's topic doesn't match the commits that cite that GH number.\n\n**Tier-1 heuristic (always on, fully local):**\n\nFor entry \"Add support for Gaussian splats (GH-NNNN)\", fetch commits tagged `GH-NNNN` and look at their subjects and file paths. If every commit only touches `.github/**` or `docs/**`, the GH ref is likely wrong — the entry describes a model-builder API change, but nothing in those commits modifies the builder or geometry. Flag.\n\nDon't flag if:\n- Commits touch `newton/_src/geometry/**` or `newton/_src/sim/builder.py` for a geometry-addition entry → topic matches.\n- Commits touch `docs/**` and the `Added` or `Changed` entry describes that documentation → topic matches.\n- Commits touch `newton/_src/solvers/**` for a solver-capability entry → topic matches.\n\n**Tier-2 heuristic (only if `gh` CLI is installed + authenticated):**\n\nFor each GH ref, run `gh issue view <num> --json title,body`. Compare the issue's title/topic to the entry's description. If clearly unrelated (e.g., issue is \"Improve MuJoCo solver performance\", entry is \"Add USD tetmesh import\"), flag.\n\nSkip tier-2 silently if `gh` is absent or auth fails.\n\n### 🕵️ Private-only symbol\n\nFlag `### Added` entries whose named public symbol exists only under `newton._src.*` at HEAD and is not re-exported through a public module (see `classification-rules.md` for the module list).\n\nExample flag:\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes.\n> *Check:* grep `newton/geometry.py` at HEAD. If `compute_offset_mesh` is not re-exported, raise 🕵️. If it is (the expected case), no flag.\n\nRationale: `CODING_GUIDELINES.rst` forbids examples and docs from importing `newton._src`. A user-facing symbol that lives only in `_src` cannot be used by Newton's own examples and is a maintenance liability.\n\n### ⬆️ Missing migration guidance (Newton-specific)\n\n`changelog/README.md`: for `Deprecated`, `Changed`, and `Removed` entries, include migration guidance such as \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n\nFlag `### Deprecated`, `### Removed`, and `### Changed` entries that name a rename / removal / reorder but do NOT express migration direction. Direction can be expressed with one of these phrases (case-insensitive): `use`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`, `prefer`. The phrase must identify a non-empty replacement target, normally as a backtick-delimited symbol. Direction can also be expressed structurally — an imperative `Rename X to Y`, an arrow `X → Y`, or a parameter-rename table — which counts as migration guidance even when none of the listed phrases appear verbatim (see the `ModelBuilder.add_shape_ellipsoid` example below).\n\nFlag:\n\n> Remove `SolverXPBD.legacy_substep()`.\n> *Reason:* no migration guidance. User does not know which method replaces it.\n>\n> Deprecate `Model.geo_meshes`.\n> *Reason:* no replacement named. Should read \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n>\n> Remove `Model.foo`; switch to improve performance.\n> *Reason:* \"switch to\" does not name a replacement target.\n\nDon't flag:\n\n> Deprecate `SensorContact.net_force` in favor of `SensorContact.total_force` and `SensorContact.force_matrix`\n> *Reason:* migration guidance present (\"in favor of ...\").\n>\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`. Old names are still accepted as keyword arguments but emit a `DeprecationWarning`\n> *Reason:* rename is explicit and the old-name behavior is documented.\n\n### 🏷️ Naming-convention drift (Newton-specific)\n\n`CODING_GUIDELINES.rst`: \"Prefix-first naming for autocomplete: `ActuatorPD` (not `PDActuator`), `add_shape_sphere()` (not `add_sphere_shape()`).\"\n\nFlag `### Added` entries whose newly-named public symbol puts the discriminator before the prefix. Examples of names to flag:\n\n- `PDActuator`, `VelocityActuator` → should be `ActuatorPD`, `ActuatorVelocity`\n- `SphereShape`, `CapsuleShape` → should be `ShapeSphere`, `ShapeCapsule`\n- `add_sphere_shape()`, `add_mesh_shape()` → should be `add_shape_sphere()`, `add_shape_mesh()`\n\nBefore flagging, cross-check against existing sibling symbols in the same module. If the rest of the module uses `Foo<Kind>` rather than `<Kind>Foo`, the new symbol should match the established pattern whichever direction it goes. Prefer consistency over a mechanical reading of the rule when the module has an entrenched local convention; call out the exception to `CODING_GUIDELINES.rst` explicitly.\n\n## Judgment philosophy\n\n**Err on \"mention, don't block\"**: flagging should raise a question for human review, not gate the report. The audit appendix shows flagged entries and a one-line reason; a human decides.\n\n**Don't auto-rewrite**: The audit flags the entry, never modifies it. Before the\nTowncrier build, the release manager updates pending fragments during changelog\nmaintenance; after release, corrections to dated history require explicit\nmaintainer approval.\n\n**Prefer false positives over false negatives**: a flag that turns out to be fine costs a 5-second eyeball. A missed wrong-ref or jargon-leak ships to users.\n\n**Exception for 🚨 policy flags.** The `🚨 Policy: removed without prior deprecation` flag (Phase 4d) is NOT a false-positive-tolerant flag. Only raise it after both an exhaustive search of prior released CHANGELOG sections and a targeted code search at the base ref fail to find deprecation evidence. A matching runtime `DeprecationWarning` satisfies the deprecation-window policy even when the CHANGELOG entry was forgotten; flag that case as `🧾 Deprecation omitted from CHANGELOG` instead.\n\n## Row format (for the report)\n\n| Entry (excerpt) | Flag | Why |\n|---|---|---|\n| \"Inline a `wp.vec3`-specialized ...\" | 🗣️ Internal language | References `warp.fem.geometry.closest_point` in user-facing prose |\n| \"Fix crash\" | 📝 Too terse | 2 words, no context link |\n| \"Add `newton.foo.bar` (GH-NNNN)\" | 🔗 Wrong ref? | Commits tagged GH-NNNN touch only CI files |\n| \"Deprecate `Model.foo`\" | ⬆️ Missing migration guidance | No \"in favor of\" replacement named |\n| \"Add `PDActuator`\" | 🏷️ Naming-convention drift | Should be `ActuatorPD` per prefix-first rule |\n| \"Add `newton.utils._x`\" | 🕵️ Private-only | Named symbol lives only in `newton._src`, not re-exported |\n| \"Remove deprecated `Model.foo`\" | 🧾 Deprecation omitted from CHANGELOG | Runtime warning exists at the base ref, but no released Deprecated entry records it |\n\nEntry excerpt should be ~60-80 chars so the table stays scannable. Keep the full entry text in the detail sections (never truncate there).\n",".agents/skills/release-audit/references/render-rules.md":"# Rendering Rules\n\nThis reference is loaded during Phase 7b of the release-audit skill. It defines the hard constraints and conventions for how the report is formatted when the template is filled in. Phase-flow logic lives in `SKILL.md`; this file is pure reference material.\n\n## Key rendering rules\n\n- Full commit URLs: `https://github.com/newton-physics/newton/commit/<full-sha>`.\n- Full issue URLs: `https://github.com/newton-physics/newton/issues/<num>`.\n- Preserve `diff` fence blocks for signature diffs.\n- Anomaly banner appears ONLY if any commit has `main_equivalent_sha: null`.\n- **Table of contents** sits immediately after the Release Highlights section (so the front matter reads: scope → version control → counts → bake → highlights → TOC → body). Link every top-level `##` section and every per-symbol / per-topic `###` heading under them.\n- **Document Version Control** appears near the top after the report scope metadata. For gist revisions, summarize the immediately preceding revision's audited head and commit count, list only materially changed report sections, and direct prior reviewers to those sections. Keep the report body current by replacing superseded conclusions rather than retaining them as history. For first publication, label it as the initial report. Include the section in the table of contents.\n- **Behavioral & Support Changes** section: group by topic with short descriptive titles (e.g., \"Deterministic contact ordering\", \"Dependency pins\", \"Build requirements\"). The audit synthesizes the titles from the entry content.\n- **Dependency & License Audit** section: render immediately after Behavioral & Support Changes and before Fixed. Use one complete `scripts/license_audit.py` output as-is except for global output-style cleanup. Never combine tables from a `--skip-pypi` run with prose from a separate live query. If a live host-side run succeeds, it replaces the entire deferred result. Keep uncertainty text such as \"not checked\", \"not evaluated (--skip-pypi)\", or \"not declared\"; do not replace it with guessed license metadata.\n- **Existing resolved package license cells stay concise.** Preserve standard license expressions and review statuses emitted by the helper. For legacy or verbose nonstandard values, keep the helper's package-metadata link instead of copying full license text into the report.\n- **Existing resolved package changes stay collapsed.** Keep the Existing Resolved Package Version-Set Changes table inside the helper's closed GFM `<details>` block. Leave the subsection heading and row-count summary visible, but do not add the `open` attribute; readers expand the long table only when needed.\n- **Experimental is a neutral stability label.** Never attach a warning emoji merely because an API is experimental. In Breaking Changes, use `Experimental:` without an emoji. Reserve `⚠️` for stable API or behavior changes that need an explicit acceptability review, and `🚨` for policy violations. The mixed Breaking Changes section heading itself has no warning emoji.\n- **Release highlights are significance-gated.** Keep 3-6 release-defining capabilities, workflows, broad behavioral shifts, or material compatibility decisions. Breaking or experimental status alone is not enough; omit routine deprecation cleanup, narrow signature changes, and minor dependency metadata follow-ups from highlights.\n\n## Output style — hard constraints on the generated report\n\n1. **No em dashes (`—`) anywhere in the report output.** Use colons, parentheses, or rewrite the sentence. This includes headings, bullet points, table cells, prose. Check every line before writing.\n\n2. **No internal skill terminology in the output.** The reader does not know what \"Phase 4f\", \"Phase 5a\", \"tier-1 heuristic\", or similar skill-internal names refer to. If a section needs explanation of how flags were produced, write it in plain user terms (e.g., \"Flagged because commits tagged with this GH ref don't touch any solver code\" instead of \"Tier-1 topic mismatch from Phase 5a\").\n\n3. **No mention of previously-shipped patch-release fixes.** The commit-list tool already scopes to `<base>..<head>`, so patch-release content is excluded automatically; do not manufacture a comparison to it.\n\n4. **No \"end of report\" or similar terminal markers.** The last section is the last section. No \"— end —\", no \"Thanks for reading\", no concluding paragraph, no closing quote.\n\n5. **Every GH ref is a markdown hyperlink** to `https://github.com/newton-physics/newton/issues/NNNN`. Plain-text `GH-NNNN` tokens, paren-grouped lists like `(GH-1287, GH-1298, ...)`, and shorthand like `(multiple GHs)` / `(see CHANGELOG)` are NOT acceptable, even when many refs bunch into one bullet or cell.\n\n6. **Signature and docstring render as a single fenced code block**, shaped like Python source so users see them in one glance. The exact shape depends on the kind of symbol.\n\n   **Functions and methods:**\n\n   ```python\n   newton.geometry.compute_offset_mesh(shape: ShapeFlags, offset: float) -> Mesh\n   \"\"\"Extract the offset surface mesh of a collision shape.\n\n   Longer description if present in the real docstring.\n   \"\"\"\n   ```\n\n   **Classes with only a constructor** (simple data holders or context managers):\n\n   ```python\n   class TetMesh:\n       \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n       Longer description if present.\n       \"\"\"\n\n       def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n   ```\n\n   **Classes with additional public methods**: list EVERY public (non-dunder, non-leading-underscore) method with its signature, plus the class docstring and each method's docstring if present. Do not just show `__init__`.\n\n   ```python\n   class SolverXPBD:\n       \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n       Short description of the solver's scope and typical use.\n       \"\"\"\n\n       def __init__(self, model: Model, iterations: int = 10)\n\n       def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n       \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n       def update_contacts(self, contacts: Contacts) -> None\n       \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n   ```\n\n   **Enum / IntEnum / IntFlag classes:** list every member with its integer value and its attribute docstring or comment, plus the class docstring. Do not show a constructor for enums.\n\n   ```python\n   class ShapeFlags(IntFlag):\n       \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n       VISIBLE = 1 << 0\n       \"\"\"Shape is rendered by viewers.\"\"\"\n\n       COLLIDE_SHAPES = 1 << 1\n       \"\"\"Shape participates in shape-shape collision.\"\"\"\n   ```\n\n   Extract member docstrings from the source using `ast` attribute-docstring form (`\"\"\"...\"\"\"` immediately following the assignment). If the member uses a `#:` comment or a trailing `#` comment, preserve that instead. If there is no per-member doc, show the member without one.\n\n   Do NOT separate \"Signature\" and \"Docstring\" into two headed subsections. Do NOT blockquote the docstring line by line; it lives inside the code block as Python source.\n\n7. **API summary tables** include a Description column AND a short-form signature in the Symbol cell. The Symbol cell shows the call shape WITHOUT type annotations so readers can skim the args at a glance. Defaults ARE included. The column order for New API tables is: `Symbol | Description | GH | Bake`. Examples of Symbol cells:\n\n   - Function: `newton.geometry.compute_offset_mesh(shape, offset)`\n   - Method: `SolverXPBD.update_contacts(contacts)`\n   - Class with constructor: `newton.TetMesh(vertices, tets)`\n   - Enum / flag (no call form): `newton.ShapeFlags`\n   - Decorator: `@newton.experimental`\n\n   Description is a short (≤ 10 word) phrase summarizing what the symbol does, pulled from the first sentence of its docstring or the CHANGELOG entry.\n\n8. **New API tables are grouped by Kind.** Render one table per Kind (\"Functions\", \"Classes\", \"Methods on existing classes\", \"Enums / flags\", \"Examples\"). Newton's \"Examples\" kind specifically covers additions under `newton/examples/**` that ship a user-runnable `python -m newton.examples <name>` entry.\n\n9. **Changes-to-Existing-API table columns**: `API | Kind | Breaking | Description | GH | Commits | Bake`. The API cell uses the same short-form call-shape convention as rule 7 (parameter names + defaults, no annotations). Description is a short phrase. Kind values include: `signature change`, `new parameter`, `capability extension`, `rename` (Newton-specific), `parameter reorder` (Newton-specific), `removed`, `deprecated`, `semantic change`. For any entry tagged experimental in Phase 4g, the Breaking cell reads `Experimental`. For any Removed entry, the Description also includes the deprecation-window fact from Phase 4d, using either the released CHANGELOG version (for example, \"Deprecated in 1.0.0; removed here.\") or the base-ref runtime-warning evidence.\n\n   **Bake-cell format (tables only).** Render the Bake column as `🟢 47d`, `🟡 12d`, `🟠 4d` — emoji, space, number-and-`d` joined with no intervening space. The joined `<N>d` form keeps the bucket/duration pair on one line when a narrow Markdown table wraps. For per-symbol detail blocks and prose, continue to spell out `🟢 47 days in main`; the compact form is for table cells only.\n\n10. **Audit appendix rendering is conditional.** If only one of the audit sections (CHANGELOG-orphan entries / language-review flags / Phase 4f semantic-review candidates) has any content, do not render an \"Audit Appendix\" umbrella heading. Just render the non-empty sections with their own top-level headings (e.g., `## CHANGELOG Review Notes`, `## Semantic-Change Review Candidates`). Only use an umbrella when two or more subsections are non-empty.\n\n11. **No Phase names anywhere.** If the report needs to explain a flag, write it in user-facing terms. Never write \"Phase 4e\", \"Phase 5\", etc.\n\n12. **Dependency/license section is always rendered.** If there are no package-name changes or in-tree notice changes, keep the helper's no-change sentence. Do not drop the section, because release managers use it as evidence that the audit ran.\n",".agents/skills/release-audit/references/report-template.md":"# Newton {{VERSION_STRING}} {{REPORT_KIND}} Report\nGenerated: {{REPORT_DATE}}\n\n<!-- {{REPORT_KIND}} is \"Pre-Release\", \"Release Candidate\", or \"Retrospective\",\n     chosen in Phase 1 from the argument, version string, and head ref.\n     {{VERSION_STRING}} is the raw version (e.g. \"1.2.0.dev0\" for pre-release,\n     \"1.2.0rc1\" for RC, \"1.1.0\" for retrospective). -->\n\n- Mode: {{MODE_DESCRIPTION}}\n- Head: {{HEAD_REF}} @ `{{HEAD_SHA_SHORT}}`\n- Base: {{BASE_REF}} @ `{{BASE_SHA_SHORT}}`\n- Commits in range: {{N_COMMITS}}\n\n<!-- {{MODE_DESCRIPTION}} is a one-liner:\n     Pre-release: \"Pre-release audit of unreleased work on main\"\n     RC: \"Release candidate readiness review (release branch cut)\"\n     Retrospective: \"Retrospective audit of shipped release v<version>; calibration\n                     pass cross-references the audit's flags against post-target history\" -->\n\n## Document Version Control\n\n{{DOCUMENT_VERSION_CONTROL}}\n\n<!-- Keep this section short and reviewer-oriented.\n\n     For a first publication, state that this is the initial report and name the\n     audited head and commit count.\n\n     For a revised gist, compare the prior report's audited head and commit count\n     with the current values, then list only the report sections whose conclusions\n     materially changed. Tell prior reviewers where to focus. End by stating that\n     every other finding was revalidated and that the report body contains only\n     current conclusions rather than retaining superseded text.\n\n     Do not use this section as a historical changelog. Gist history preserves old\n     revisions; this section is a compact review map for the immediately preceding\n     revision. -->\n\n\n**Headline counts**\n\n- {{N_NEW_API}} new public APIs\n- {{N_BREAKING}} breaking changes\n- {{N_CHANGED}} changes to existing API\n- {{N_BEHAVIORAL}} behavioral / support changes\n- {{N_FIXED}} fixes\n- {{N_EXAMPLES}} new examples\n\n**Bake distribution**\n\n| Bucket | Commits |\n|---|---:|\n| 🟢 > 14 days in main | {{N_BAKE_GREEN}} |\n| 🟡 7 to 14 days | {{N_BAKE_YELLOW}} |\n| 🟠 < 7 days | {{N_BAKE_ORANGE}} |\n\n{{ANOMALY_BANNER_IF_ANY}}\n\n<!-- Anomaly banner appears ONLY when any commit has main_equivalent_sha: null. Example:\n     > ⚠️ **N commits in the release have no equivalent on main. Investigate: these\n     > shipped without nightly/main-branch bake.**\n-->\n\n---\n\n## Release highlights\n\n{{HEADLINE_SUMMARY}}\n\n<!-- The audit's qualitative synthesis of what would land in the official release\n     notes. Drafted in Phase 7a. NOT release notes: a reviewer's preview so the\n     release manager can see at a glance whether the real release notes will\n     match expectations and spot items that need a keep/defer decision.\n\n     Shape: one short intro paragraph (2-3 sentences) followed by 3-6 bulleted\n     highlight items. Each bullet starts with a bold 2-6 word headline, then a\n     colon and a one-sentence rationale (what it is and why it matters).\n\n     Include status/risk markers inline only when they apply:\n       - 🟠 `N days` bake (if the headline item's minimum bake is < 7 days)\n       - Experimental (neutral label, no warning emoji, and only when the item\n         independently clears the significance bar)\n       - ⚠️ Stable change (a non-experimental API or behavior change that needs\n         a deeper release-manager acceptability decision)\n\n     Do NOT include counts (\"4 new APIs were added\"): that's already in the\n     headline counts block above. Highlights are qualitative.\n     Do NOT promote an item only because it is breaking or experimental. Routine\n     compatibility removals after a valid deprecation window, narrow signature\n     shifts, and dependency metadata follow-ups belong in the detailed sections.\n\n     Example shape (do NOT copy verbatim; pick items that are actually headline\n     material in THIS release):\n\n     Newton 1.2 lands Gaussian splat geometry, deterministic contact ordering, and\n     a new texture-based SDF pipeline that replaces NanoVDB for mesh-mesh collision.\n     One stable default change needs an explicit acceptability decision before cut.\n\n     - **Gaussian splat geometry** ([GH-NNN](...)): `Gaussian`, `ModelBuilder.add_shape_gaussian()`,\n       and USD import unlock radiance-field-style rendering as a first-class shape.\n       🟢 30 days bake.\n     - **Deterministic contact ordering** ([GH-NNN](...)): `deterministic` flag on\n       `CollisionPipeline` and `NarrowPhase` makes contact output GPU-thread-schedule\n       independent via radix sort and fingerprint tiebreaking. Required for reproducible\n       RL training. 🟢 22 days bake.\n     - **Texture-based mesh SDF** ([GH-NNN](...), [GH-NNN](...)): replaces NanoVDB\n       volumes in the mesh-mesh collision pipeline; faster and CPU-compatible. Every\n       GH ref is an individual hyperlink; never collapse to \"(multiple GHs)\" or a\n       plain-text comma list.\n     - **⚠️ Stable change: particle contacts enabled by default** ([GH-NNN](...)):\n       existing scenes can change trajectories, so the release manager should confirm\n       the new default and preservation path are acceptable.\n     - **Experimental: differentiable rigid contacts** ([GH-NNN](...)): gradients\n       with respect to body poses via `CollisionPipeline` when `requires_grad=True`;\n       contact-pipeline API may change in 1.3.\n     - **RJ45 plug-socket insertion example**: demonstrates SDF contacts, latch joint,\n       and interactive gizmo; release notes should lead with the showcase.\n-->\n\n---\n\n## Contents\n\n{{CONTENTS_BULLETS}}\n\n<!--\nExpand the TOC to include every `###` heading rendered in the body, not\njust the `##` top-level sections. List each per-symbol / per-topic heading\nas a sub-bullet under its parent section. Example shape (replace with the\nreal symbols / topics present in this specific report):\n\n- [Document Version Control](#document-version-control)\n- [New API](#new-api)\n  - [`newton.<symbol>`](#newtonsymbol)\n  - [`newton.<submodule>.<symbol>`](#newtonsubmodulesymbol)\n  - ...\n- [Breaking Changes](#breaking-changes)\n  - per-entry heading as sub-bullet\n- [Changes to Existing API](#changes-to-existing-api)\n  - per-entry heading as sub-bullet\n- [Behavioral & Support Changes](#behavioral--support-changes)\n  - per-topic heading as sub-bullet\n- [Dependency & License Audit](#dependency--license-audit)\n- [Schema & Importer Support](#schema--importer-support)\n- [Fixed](#fixed)\n- [Calibration Notes](#calibration-notes) (retrospective mode only)\n  - per-flag-class sub-bullet\n- [CHANGELOG Review Notes](#changelog-review-notes) (only if the conditional\n  appendix renders content)\n\nThe sample symbol names above are illustrative placeholders; do NOT ship them\nas-is. GitHub auto-renders a floating outline panel, but an explicit TOC\nstill helps raw-text readers.\n-->\n\n---\n\n## New API\n\n{{NEW_API_TABLES_BY_KIND}}\n\n<!-- Render one summary table per Kind. Columns: Symbol | Description | GH | Bake.\n     Kind groupings for Newton: \"Functions\", \"Classes\", \"Methods on existing classes\",\n     \"Enums / flags\", \"Constants\", \"Examples\". If only one Kind has entries, one\n     table is fine.\n\n     The Symbol cell uses a short-form call shape (no type annotations; defaults\n     included). Examples:\n     - `newton.geometry.compute_offset_mesh(shape, offset)`\n     - `newton.TetMesh(vertices, tets)`\n     - `SolverXPBD.update_contacts(contacts)`  (method on existing class)\n     - `newton.ShapeFlags`  (no parens for enums, decorators)\n     - `newton.examples.basic_pendulum`  (example module; the Symbol cell links to\n       the runnable name `python -m newton.examples basic_pendulum`). -->\n\n{{NEW_API_DETAIL_BLOCKS}}\n\n<!-- Per-symbol block template. Headings use the symbol name alone (no colons/em dashes).\n     The single fenced code block underneath holds signature-shaped content and\n     the docstring.\n\nSimple data class (constructor-only rendering):\n\n### `newton.TetMesh`\n\nLinks: [GH-NNN](...), commits: [abc1234](...), [def5678](...)\nSource: `newton/_src/geometry/tetmesh.py`\nBake: 🟢 47 days in main\n\n```python\nclass TetMesh:\n    \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n    Holds per-vertex positions and per-tet index quads; builders accept this\n    shape via ModelBuilder.add_shape_tetmesh.\n    \"\"\"\n\n    def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n```\n\nClass with multiple public methods (interface-style): list every public method\nwith its signature and docstring, not just __init__.\n\n### `newton.solvers.SolverXPBD`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 30 days in main\n\n```python\nclass SolverXPBD:\n    \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n    Supports rigid bodies, particles, cloth, and soft-body elements with a\n    common substepping loop.\n    \"\"\"\n\n    def __init__(self, model: Model, iterations: int = 10)\n\n    def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n    \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n    def update_contacts(self, contacts: Contacts) -> None\n    \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n```\n\nEnum / IntFlag: list every member with its value and per-member doc.\n\n### `newton.ShapeFlags`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/geometry/flags.py`\nBake: 🟡 12 days in main\n\n```python\nclass ShapeFlags(IntFlag):\n    \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n    VISIBLE = 1 << 0\n    \"\"\"Shape is rendered by viewers.\"\"\"\n\n    COLLIDE_SHAPES = 1 << 1\n    \"\"\"Shape participates in shape-shape collision.\"\"\"\n\n    COLLIDE_GROUND = 1 << 2\n    \"\"\"Shape participates in ground-plane collision.\"\"\"\n```\n\nMethod added to an existing class: the heading names the fully-qualified\nmethod path. The fenced block shows only that method, not the whole class.\n\n### `newton.solvers.SolverXPBD.update_contacts`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 21 days in main\n\n```python\ndef update_contacts(self, contacts: Contacts) -> None\n\"\"\"Populate contacts.force with per-contact spatial forces.\n\nDerives linear force and torque [N, N·m] from XPBD constraint impulses\naccumulated during the most recent step. Call after step().\n\"\"\"\n```\n\nExample (runnable under `python -m newton.examples <name>`): the Source cell\npoints to the example module; list the one-liner user invocation and the\nheadline simulation topic.\n\n### `newton.examples.robot.example_robot_humanoid`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/examples/robot/example_robot_humanoid.py`\nBake: 🟢 19 days in main\n\nRun:\n\n```\npython -m newton.examples example_robot_humanoid\n```\n\nShort paragraph explaining what the example demonstrates (the solver used,\nwhat the user will see, any dependencies like MuJoCo assets).\n-->\n\n---\n\n## Breaking Changes\n\n{{BREAKING_ENTRIES}}\n\n<!-- Flat list. Do NOT group under \"Author-labeled\" / \"Unlabeled\" / \"Semantic\"\n     subheadings. Every entry is simply a confirmed breaking change, regardless\n     of how it was identified. The audit collects entries from four sources:\n     (1) CHANGELOG Changed entries whose prose describes a rename / parameter\n         reorder / signature shift (Newton does not use a **Breaking:** marker;\n         recognition is prose-based),\n     (2) CHANGELOG Removed entries (implicitly breaking; flag as 🚨 Policy only\n         if neither a prior Deprecated entry nor a matching runtime warning at\n         the base ref is found),\n     (3) public-surface AST diffs between base and HEAD that aren't covered by\n         a CHANGELOG Changed / Removed entry,\n     (4) solver / integrator / math / geometry commits whose diff the audit reads\n         as clearly semantic-shifting (a numerical-output shift that a user\n         would observe). Ambiguous candidates go to \"Semantic-Change Review\n         Candidates\" in the review notes, NOT here.\n\n     Warning semantics:\n     - Prefix a non-experimental entry heading with `⚠️` when the stable API or\n       behavior change needs a deeper acceptability decision (for example, a\n       changed default, output semantics, or unshimmed signature shift).\n     - Prefix experimental entry headings with `Experimental:` and no warning\n       emoji. Their looser compatibility contract is context, not an alarm.\n     - Planned removals after a valid shipped deprecation window need no warning\n       emoji unless their breadth or remaining migration risk warrants review.\n     - Keep `🚨 Policy` for removals with no prior deprecation evidence.\n\n     Per-entry render format:\n\n     ### <heading: symbol name or short descriptive title>\n\n     Links: [GH-NNN](...), commit(s): [sha](...). 🟢 N days baked in main.\n\n     [If signature diff applies, a fenced diff block.]\n     [If behavior shift, a before/after code snippet synthesized from the diff\n      and the commit message.]\n\n     [1-3 sentences of explanatory prose in plain user-facing language.]\n\n     [Full CHANGELOG text blockquoted, if the entry came from CHANGELOG.]\n\n     [For removals backed only by a runtime warning at the base ref: a one-line\n      deprecation-window note plus a non-blocking CHANGELOG documentation flag.]\n\n     [For 🚨 Policy: removed without prior deprecation entries: a one-line\n      callout stating that neither released CHANGELOG nor base-ref code contains\n      deprecation evidence and what the release manager should do about it.]\n\n     Illustrative example (do not copy verbatim):\n\n     ### `ModelBuilder.add_shape_gaussian` parameter reorder\n\n     Links: [GH-NNN](https://github.com/newton-physics/newton/issues/NNN),\n     commit: [abc1234](https://github.com/newton-physics/newton/commit/abc1234). 🟢 22 days baked in main.\n\n     The `xform` argument now precedes `gaussian` to match every other\n     `add_shape_*` method on `ModelBuilder`. Callers that relied on positional\n     arguments must switch to keyword form. Passing a `Gaussian` as the second\n     positional argument still works but emits a `DeprecationWarning`.\n\n     Before:\n     ```python\n     builder.add_shape_gaussian(body_idx, gaussian, xform=my_xform)\n     ```\n\n     After:\n     ```python\n     builder.add_shape_gaussian(body_idx, xform=my_xform, gaussian=gaussian)\n     ```\n-->\n\n---\n\n## Changes to Existing API\n\n<!-- Covers CHANGELOG Changed, Removed, Deprecated, plus capability extensions\n     routed here from the new-API classification pass (e.g., \"Add support for X\n     in existing Y\"). -->\n\n{{CHANGED_SUMMARY_TABLE}}\n\n<!-- Columns: API | Kind | Breaking | Description | GH | Commits | Bake\n     Kind values: signature change, new parameter, capability extension, rename,\n     parameter reorder, removed, deprecated, semantic change. Description is a\n     short phrase (≤ 10 words). Breaking cell values: Yes / No / Experimental. -->\n\n{{CHANGED_DETAIL_BLOCKS}}\n\n<!-- Per-entry template (signature change). Use a colon in the heading, not an em dash.\n\n### `SolverMuJoCo`: new `enable_multiccd` parameter\n\nBreaking: **No** (additive keyword-only default)\nLinks: [GH-NNN](...), commit: [5c5f67e9](...)\nBake: 🟢 38 days in main\n\n```diff\n- def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True)\n+ def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True, enable_multiccd: bool = False)\n```\n\n**From CHANGELOG**\n> Add `enable_multiccd` parameter to `SolverMuJoCo` for multi-CCD contact generation\n> (up to 4 contact points per geom pair).\n\nCapability extension (existing API gains a new option/behavior):\n\n### `ModelBuilder.add_shape_*`: per-shape color\n\nLinks: [GH-NNN](...), commit: [abcdef12](...)\nBake: 🟢 35 days in main\n\nEvery `add_shape_*` method gains a `color=` keyword argument; `Model.shape_color`\nholds the authored per-shape display color for runtime edits; mesh shapes fall\nback to `Mesh.color` when available.\n\n```diff\n- def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True)\n+ def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True, color: Vec3 | None = None)\n```\n\n**From CHANGELOG**\n> <full CHANGELOG text blockquoted>\n\nRename (Newton-specific kind, soft deprecation via DeprecationWarning):\n\n### `ModelBuilder.add_shape_ellipsoid`: parameter rename\n\nBreaking: **Yes** (source break if old names used positionally)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 28 days in main\n\n```diff\n- def add_shape_ellipsoid(self, body: int, a: float, b: float, c: float, ...)\n+ def add_shape_ellipsoid(self, body: int, rx: float, ry: float, rz: float, ...)\n```\n\nOld names `a`, `b`, `c` are still accepted as keyword arguments but emit a\n`DeprecationWarning`. Positional callers must switch to keyword form.\n\n**From CHANGELOG**\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`.\n> Old names are still accepted as keyword arguments but emit a `DeprecationWarning`.\n\nRemoved symbol:\n\n### `Model.geo_meshes`: removed\n\nLinks: [GH-NNN](...), commit: [sha](...)\nDeprecation window: Deprecated in 1.0.0; removed here.\n\n```diff\n- geo_meshes: list[Mesh]\n```\n\n**From CHANGELOG (prior deprecation in 1.0.0)**\n> Deprecate `Model.geo_meshes` in favor of `Model.shapes`. Will be removed in a\n> future release.\n\n**From CHANGELOG (removal)**\n> <full CHANGELOG text blockquoted>\n\nExperimental-softened entry (symbol was shipped as experimental in a prior release; change here is technically source-breaking but the stability bar was advertised up front):\n\n### `SensorTiledCamera`: RenderContext reorganization\n\nBreaking: **Experimental** (since 1.0.0)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 40 days in main\n\n`SensorTiledCamera` landed as an experimental sensor in 1.0.0; this release\nsplits `RenderContext` into `RenderConfig` (config types) and `utils` (runtime\naccess), deprecates the old names, and adjusts default Gaussian sorting modes.\n\n```diff\n- class SensorTiledCamera:\n-     render_context: RenderContext\n+ class SensorTiledCamera:\n+     render_config: RenderConfig\n+     utils: SensorTiledCameraUtils\n```\n\n**From CHANGELOG (1.0.0 introduction, still experimental)**\n> Add `SensorTiledCamera` (experimental): GPU-tiled camera sensor for multi-agent RL.\n\n**From CHANGELOG (this release)**\n> <full CHANGELOG text blockquoted>\n-->\n\n---\n\n## Behavioral & Support Changes\n\n<!-- Group by topic with short descriptive section headings synthesized from\n     the entry content. Use colons in headings if separation is needed.\n     Related topics should live together.\n\n     Example headings (illustrative, choose based on actual content):\n     - \"Python minimum version bumped\"\n     - \"MuJoCo / mujoco-warp dependency pins\"\n     - \"Deterministic contact ordering\"\n     - \"USD import: visibility honored\"\n     - \"Mesh SDF construction: parity path\"\n     - \"Asset pinning for reproducible builds\"\n\n     Each topic: a short paragraph summary, links, commits, bake. -->\n\n{{BEHAVIORAL_SECTIONS}}\n\n---\n\n## Dependency & License Audit\n\n{{DEPENDENCY_LICENSE_AUDIT}}\n\n<!-- Render the markdown emitted by scripts/license_audit.py. This section is\n     always present. It compares direct dependencies, resolved lockfile package\n     names, version changes, and declared license-file pathspecs across the\n     release range. Use one complete helper result; never combine a\n     `--skip-pypi` table with prose from a separate live query. Preserve \"not\n     checked\", \"not evaluated (--skip-pypi)\", and \"not declared\" license\n     metadata exactly when package-index lookup was unavailable, deferred, or\n     inconclusive. Keep the helper's Existing Resolved Package Version-Set\n     Changes table inside its closed `<details>` block so the long table is\n     collapsed by default. -->\n\n---\n\n## Schema & Importer Support\n\n{{SCHEMA_IMPORTER_SUPPORT}}\n\n<!-- Render the Phase 4h table, or state that no relevant features were found. -->\n\n---\n\n## Fixed\n\n{{FIXED_TABLE}}\n\n<!-- Columns: Fix | GH | Commits | Bake\n     Keep the full CHANGELOG text in the Fix column; no truncation.\n     Do NOT mention fixes from previously-shipped patch releases. The commit-list\n     tool scopes to <base>..<head> so those are already excluded. -->\n\n{{CALIBRATION_NOTES}}\n\n<!-- Retrospective mode only. Pre-release / RC mode must leave\n     {{CALIBRATION_NOTES}} empty (template consumers should strip the whole\n     placeholder line, not leave a stray section heading).\n\n     Retrospective mode renders a ## Calibration Notes section here, immediately\n     after Fixed and before the optional audit appendix. Shape:\n\n     ## Calibration Notes\n\n     One-paragraph headline: overall validated / invalidated / unresolved counts\n     across all flag classes, plus a one-sentence takeaway on what the calibration\n     suggests about skill precision for this release.\n\n     ### 🚨 Missing-deprecation\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `Model.foo` | Validated | No prior Deprecated entry or matching runtime warning at the base ref; symbol stayed removed through 1.1.2. |\n     | `Model.bar` | Invalidated | Deprecated in 1.0.0 under `### Deprecated` — the audit's search missed it (lowercase `model.bar` in the entry). |\n\n     ### 🕵️ Private-only\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `newton._src.utils._helper` | Validated | Re-exported as `newton.utils.helper` in [1.1.1](commit-link). |\n\n     ### ⬆️ Missing-migration-guidance\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### 🏷️ Naming-convention drift\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### Semantic-change review candidates\n\n     | File / feature | Outcome | Evidence |\n     |---|---|---|\n     | `newton/_src/solvers/xpbd.py` contact-ordering diff | Validated | [1.1.1](commit-link) fixes \"convergence regression on stacked bodies\" — consistent with the flagged change's hypothesis. |\n\n     ### Deprecation follow-through\n\n     | Deprecated in this release | Followed through | Evidence |\n     |---|---|---|\n     | `Model.geo_meshes` | Followed through in 1.2.0 | Removed entry cites `Use Model.shapes`; matches the promised migration path. |\n     | `SensorContact.net_force` | Still deprecated | Symbol remains in the public surface through 1.2.1 with DeprecationWarning. |\n\n     Closing note (one or two sentences): what the calibration tells the reader\n     about Newton's release hygiene for this specific release.\n-->\n\n---\n\n{{OPTIONAL_APPENDIX}}\n\n<!-- Render conditionally based on content and wrap each non-empty section in\n     a GFM <details> block so it collapses by default (the umbrella content is\n     reference material, not headline reading).\n\n     Three cases:\n\n     1. Both CHANGELOG-orphan list AND language-review flags are empty:\n        Render nothing. No appendix heading, no trailing section.\n\n     2. Exactly ONE is non-empty: Render that one as a top-level section\n        (no \"Audit Appendix\" umbrella) with the table inside <details>.\n\n        ## CHANGELOG Entries Without Matching Commits\n        <details>\n        <summary>N entries (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        | full entry text | ... | ... |\n\n        </details>\n\n     3. Both are non-empty: Render an umbrella section; each subsection gets\n        its own <details>.\n\n        ## Audit Appendix\n\n        <details>\n        <summary>N CHANGELOG entries without matching commits (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        ...\n\n        </details>\n\n        <details>\n        <summary>N CHANGELOG entries flagged for review (click to expand)</summary>\n\n        | Entry | Flag | Why |\n        |---|---|---|\n        ...\n\n        </details>\n\n     Column rules for BOTH tables: full entry text (no truncation).\n     Flag glyphs: 🔗 (suspected wrong GH ref), 🗣️ (internal language),\n                  📝 (too terse or missing context),\n                  🕵️ (private-only symbol not re-exported through a public module),\n                  ⬆️ (Deprecated / Removed / rename entry missing migration guidance),\n                  🏷️ (new public symbol violates Newton's prefix-first naming),\n                  🧾 (runtime deprecation shipped but the released CHANGELOG omitted it),\n                  🚨 (removed without prior CHANGELOG or runtime deprecation evidence;\n                      policy violation surfaced in Breaking Changes and listed here\n                      for auditability).\n     An entry with multiple flags appears once per flag. -->\n\n<!-- Report ends here. Do NOT append \"end of report\", a closing quote, a thanks\n     note, or any terminal marker. -->\n",".agents/skills/release-changelog/SKILL.md":"---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nPending user-facing changes live in Towncrier fragments under `changelog/`.\n`CHANGELOG.md` is generated only on a release branch. Shipped sections are\nimmutable; the assembled section for the pending release remains a rolling\ndocument until tagging. Follow `changelog/README.md` as the command and format\nauthority.\n\n## Audit pending changes\n\n1. Identify the release ref and comparison base. Audit `release-X.Y` once it\n   exists; otherwise audit the intended main ref.\n2. Protect released history. Diff `CHANGELOG.md` from the latest stable tag and\n   require explicit maintainer approval for edits to dated sections.\n3. Render a non-mutating preview, which also validates Towncrier's renderable\n   fragment filenames:\n   ```bash\n   uvx --from towncrier==25.8.0 towncrier build --draft \\\n     --version X.Y.Z --date YYYY-MM-DD\n   ```\n4. Compare the preview with the release audit and commit range from the previous\n   release. Inspect `.skip` reasons separately.\n5. Preserve information. Rephrase, split, merge, or recategorize fragments only\n   when the facts remain intact. Ask before deleting information or downgrading\n   a user-visible change.\n6. Use only `Added`, `Changed`, `Deprecated`, `Removed`, and `Fixed`, in that\n   order. Keep migration and retesting guidance in affected entries.\n7. Remove exact and semantic duplicates. When a feature and its fix both land\n   in one cycle, describe the final user-visible behavior once.\n8. Keep `Added` for new public APIs, options, features, examples, and docs. Put\n   existing-API behavior, warning, default, importer, and solver changes in\n   `Changed`, even when they expand support.\n9. Give every breaking, removed, deprecated, or default-changing entry a\n   concrete action. Never direct users to `newton._src`.\n10. A numeric fragment identifier is a GitHub issue number. Towncrier renders\n    its issue link automatically; do not rewrite it as a pull request number.\n\n## Assemble the release during RC stabilization\n\nAfter the initial release scope has been audited on `release-X.Y`, assemble the\ncurrent fragments early enough for maintainer review:\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\nuvx --from towncrier==25.8.0 towncrier build --yes \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit rm --ignore-unmatch \"changelog/*.skip\"\ngit add -A CHANGELOG.md changelog\n```\n\nReview and approve the draft before running the mutating command. Towncrier\ninserts the dated section below `[Unreleased]` and deletes rendered fragments.\nIt ignores `.skip` files, so remove those explicitly. Review the staged diff in\na changelog-only pull request labeled `release-management`.\n\nAfter assembly, apply the audit rules above to the dated section: verify\ncompleteness, grouping, deduplication, wording, categories, and migration\nguidance. Keep editorial cleanup in the changelog-management commits that will\nlater be synchronized to `main`.\n\nThe first Towncrier release requires one migration audit. The insertion marker\nsits above the legacy `[Unreleased]` entries so they remain under the first\ngenerated release title. Merge duplicate category headings without dropping or\nduplicating an entry. Later releases need no special handling.\n\nTreat the assembled section as a rolling document. For every later cherry-pick\nbefore tagging:\n\n1. Validate the new fragments and render them with `towncrier build --draft`.\n2. Fold the previewed entries into the existing dated section without creating\n   a second release heading.\n3. Delete exactly the consumed `.md` and `.skip` fragments, then stage\n   `CHANGELOG.md` and `changelog/`.\n4. Rerun the changelog cleanup and `release-audit` checks, and merge the update\n   as another changelog-only `release-management` pull request.\n\nFinal GA preparation verifies the completed section and confirms that no\nrelease-branch fragments remain. Do not postpone the full cleanup until GA.\n\n## Synchronize to main\n\nAfter tagging:\n\n1. Create a changelog-only branch from current `main`.\n2. Cherry-pick, in order, every changelog-management commit from `release-X.Y`:\n   the initial Towncrier build, editorial cleanup, and all later cherry-pick\n   additions.\n3. Confirm fragments deleted by those commits disappear while fragments added to\n   `main` after the branch cut remain under `changelog/`.\n4. Confirm the dated section matches the release tag and older history is\n   unchanged.\n5. Open a changelog-only pull request labeled `release-management`.\n\nDo not replace the whole file with the release-branch copy. The commits'\npath-level deletions are what preserve main-only fragments.\n\n## Checks\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit diff v<latest-release> -- CHANGELOG.md changelog\ngit diff --cached --name-status -- CHANGELOG.md changelog\nrg -ni \"removed|deprecated|in favor of|use .* instead|renam|replac|default|breaking\" \\\n  CHANGELOG.md changelog\n```\n\nConfirm that `[Unreleased]` is empty after the first migration, no dated history\nchanged, released entries appear exactly once, and post-cut main fragments\nsurvive synchronization.\n",".agents/skills/release-notes/SKILL.md":"---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nDraft concise GitHub Release notes that explain why a Newton release exists and\nwhat users should know. Do not reproduce the full changelog; link to it.\n\nWrite for external users moving from the previous final release to the current\nartifact without assuming they followed development or release candidates.\nFinal-release notes must not mention earlier RCs. Never mention or link internal\nrelease audits, audit gists, readiness reports, cutoff SHAs, bake durations,\naudit counts, or other audit-only metadata; use those sources as evidence only.\n\n## Workflow\n\n1. Identify the artifact, target version, and release type:\n   - **GitHub release description**: public release page. Follow Newton/Warp\n     release-page style and include user-actionable migration sections.\n   - **Internal release announcement**: short internal email/doc. Use release\n     metadata first, then grouped bullets such as `New Features`,\n     `Performance Improvements`, and `Developer Experience`.\n   - If the user wants both and the content should converge, keep one document\n     only when explicitly requested; otherwise maintain separate drafts.\n   - Patch / bugfix releases: emphasize fixes, compatibility, and stability.\n   - Minor / feature releases: emphasize major user-facing capabilities.\n   - RCs: state that this is a release candidate and what needs validation.\n     If drafting final-release text from an RC tag or release branch, do not\n     mention the RC; use the RC only as the temporary source of truth.\n2. Choose changelog source material from the authoritative release ref:\n   - After the Towncrier build or tagging, read the matching dated\n     `CHANGELOG.md` section from the release tag or release branch.\n   - Before the build, check out the release branch, validate its pending\n     fragments, and render a non-mutating preview:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Draft from the preview and legacy `[Unreleased]` entries during the first\n     Towncrier transition. Do not run a mutating build merely to draft notes.\n   Do not rely on `main` unless the release is actually cut from `main`.\n3. Determine the previous release tag:\n   - Patch release `X.Y.Z`, `Z > 0`: use the highest earlier `vX.Y.<Z'>` tag.\n   - Feature release `X.Y.0`: use the highest `vX.<Y-1>.*` tag. If `Y == 0`,\n     use the highest tag from the previous major.\n4. Compare the release range against the previous release:\n   ```bash\n   git log --no-merges --oneline --cherry-pick --right-only v<previous>...v<target>\n   git diff --name-status v<previous>..v<target>\n   ```\n   Use the symmetric-difference `...` log form for counting and scanning commits\n   when a release branch contains cherry-picks; it avoids overstating scope with\n   equivalent patches already present in the previous release. Use the normal\n   `..` diff for changed files. If the final tag does not exist yet, use the\n   latest RC tag or `upstream/release-X.Y` as the temporary target.\n5. Inspect the PRs behind candidate highlights. Commit subjects usually carry\n   `(#NNNN)`; use PR bodies when needed to understand impact and any linked\n   issues.\n6. Check prior release-note and announcement formats when available:\n   - Newton release pages, e.g. `v1.2.0`, for the local public-release shape.\n   - Warp release pages for `Announcements`, `Upcoming removals`, and\n     acknowledgement patterns.\n   - Internal announcements for short internal release-email structure.\n7. Draft a high-level overview and a short highlights list. Keep only\n   consumer-relevant items. Omit CI, workflow, README layout, release-link\n   pinning, and other internal/docs polish unless the user explicitly asks or it\n   affects library users. When a validated release review supplies the\n   highlights, preserve its release-defining conclusions, ordering, and public\n   wording unless publication rules require a change. Rewrite audit-oriented\n   framing, remove audit-only metadata, and adapt references to the release-note\n   format without weakening the user-facing claims.\n8. Keep a review-ready release-branch draft. After tagging, refresh it against\n   the final tag and inspect the workflow-created draft GitHub Release. Publish\n   only after verifying the final artifact and links per `docs/guide/release.rst`.\n\n## Linking Rules\n\n- Link the changelog to the final release tag:\n  `https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor`\n- If drafting before the final tag exists, use `release-X.Y` or the RC tag\n  temporarily, but note that the published release should use the final tag.\n- Never link the changelog to `main` for a release branch unless `main` is the\n  authoritative release ref; `main` may have newer unreleased changes.\n- Add one GitHub reference to each highlight, usually the PR. Use an issue only\n  when there is no useful PR or the issue is the canonical context.\n- Avoid linking both an issue and a PR for the same highlight unless that extra\n  context is necessary.\n- In GitHub Release notes, render same-repository references as plain `#NNNN`\n  instead of full markdown links. GitHub auto-links them on the release page, and\n  the compact form matches Warp's release-note style.\n- Link in-tree examples or docs on the release tag URL, never `main`, so links\n  do not drift after publication.\n- For dependency summaries, prefer a link to the relevant `pyproject.toml`\n  compare over listing every changed constraint:\n  `https://github.com/newton-physics/newton/compare/v<previous>...v<target>?diff=split`\n  Mention only high-signal dependency changes in bullets.\n\n## Style\n\n- Start with a short paragraph naming the version, release type, and purpose.\n- Use a `## Highlights` section with typically 3-6 grouped bullets. Retain\n  additional release-defining highlights when the user explicitly requests them\n  or a validated release review establishes that they belong; do not drop a\n  significant theme merely to meet the usual count.\n- For bugfix releases, keep notes slim: no `## New features` section unless a\n  genuinely notable capability shipped in the patch. The highlights are a\n  categorized digest of fixes.\n- For feature releases, group related features by user workflow and order by\n  impact. Lead with the most important user-facing capability, not API names.\n- Prefer user impact over implementation detail.\n- Keep bullets compact: one bold label, one or two explanatory sentences, then\n  the `#NNNN` reference.\n- Treat the changelog as source material, not prose to copy. Translate internal\n  implementation terms into user-facing impact.\n- Include `## Announcements` only for changes users must act on, such as\n  removals, deprecations, platform-support changes, or dependency constraints.\n- For public feature releases, include focused sections for:\n  - breaking changes and removals,\n  - new deprecations,\n  - upcoming removals,\n  - dependency updates,\n  - acknowledgements.\n  Keep these concise; the changelog carries the exhaustive detail.\n- Include `## Notes` only for compatibility, install, or migration information\n  users need. Drop the section when there is nothing useful to say.\n- Include `## Acknowledgments` when there are meaningful contributions from\n  outside Newton maintainers and project-member groups. Omit trivial typo-only\n  or formatting-only changes.\n- For patch releases, say whether the release is intended to be API-compatible\n  with the previous patch/minor when that is true.\n- Avoid em dashes in rendered prose.\n- Keep raw Markdown soft-wrapped: use one physical line per paragraph and list item; let viewers wrap it to their window width.\n\n## Dependency Updates\n\nDo not default to a large table. Keep dependency updates high signal:\n\n- Call out major/minor runtime baseline bumps, new extras, dependency caps that\n  affect users, and removed caps when they unblock compatibility.\n- Link to the `pyproject.toml` compare for the complete detail.\n- If the prior patch release changed dependencies, compare against the closest\n  prior release tag, not the earlier minor tag.\n\n## Acknowledgments\n\nBefore listing outside contributors, verify they are not in Newton's maintainer\nor project-member groups.\n\n1. Read `newton-governance/CONTRIBUTORS.md` or the current governance source\n   when reachable. Treat it as the authority for maintainer and project-member\n   membership.\n2. If GitHub access is available and governance points to org teams, query the\n   current team slugs from GitHub rather than relying on a hardcoded list:\n   ```bash\n   gh api orgs/newton-physics/teams --paginate --jq '.[] | [.slug, .name] | @tsv'\n   gh api orgs/newton-physics/teams/<team-slug>/members --paginate --jq '.[] | .login'\n   ```\n   Prioritize teams named by governance, or teams whose current names clearly\n   identify maintainers, TSC, project members, or project-member organizations.\n3. Cross-check candidate PR authors with `gh pr view <number> --json author`\n   and commit emails. Commit email/company is a hint, not a substitute for the\n   team/governance check.\n4. Phrase the section accurately, for example \"outside the Newton maintainer\n   and project-member groups\" when that is the filter used.\n\n## Template\n\n```markdown\n# Newton vX.Y.Z\n\nNewton vX.Y.Z is a patch release following vX.Y.W. It focuses on bug fixes and\ncompatibility updates for the X.Y release line, especially around <areas>.\n\nFor the complete list of changes, see the [changelog](https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor).\n\n## Highlights\n\n- **<User-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n- **<Another user-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n## Announcements\n\n<Only include this section when there is a removal, deprecation,\nplatform-support change, dependency constraint, or other user-actionable\nannouncement. Drop it otherwise.>\n\n## Notes\n\nThis release is intended to be API-compatible with Newton vX.Y.W. No breaking\nchanges are expected.\n```\n",".claude/skills/code-review-newton/SKILL.md":"---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/code-review-newton/SKILL.md`. If it is unavailable, stop\nwithout performing the review.\n",".claude/skills/release-audit/SKILL.md":"---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\ndisable-model-invocation: true\nargument-hint: \"[target-version]\"\nallowed-tools: Bash(git log *) Bash(git show *) Bash(git grep *) Bash(git tag *) Bash(git rev-parse *) Bash(git diff *) Bash(git ls-tree *) Bash(uvx --from towncrier==25.8.0 towncrier build --draft *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/cleanup_report.py *) Bash(gh --version) Bash(gh auth status) Bash(gh gist create *) Bash(gh gist list *) Bash(gh gist view *) Bash(gh gist edit *) Bash(gh issue view *) Bash(gh issue list *) Read Write Grep Glob\n---\n\n# Release Audit\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-audit/SKILL.md`. If it is unavailable, stop without\nstarting the audit.\n",".claude/skills/release-changelog/SKILL.md":"---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-changelog/SKILL.md`. If it is unavailable, stop\nwithout modifying the changelog.\n",".claude/skills/release-notes/SKILL.md":"---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-notes/SKILL.md`. If it is unavailable, stop without\ndrafting or revising release text.\n","AGENTS.md":"# Newton Development Guidelines\n\nRead and follow the canonical [source code and public API guidelines](CODING_GUIDELINES.rst) before changing or reviewing Newton code. This file contains agent-specific workflow instructions; the linked guide is authoritative for coding and API design.\nFor reviews, also read and apply the [review guidelines](REVIEW_GUIDELINES.rst) and follow `.agents/skills/code-review-newton/SKILL.md`.\n\n- Create a feature branch on your fork before committing—never commit directly to `main`. Give the pull request a concise, descriptive title.\n- Use imperative mood in commit messages (\"Fix X\", not \"Fixed X\"), with a roughly 50-character subject and a body wrapped at 72 characters that explains what and why.\n- Verify regression tests fail without the fix before committing.\n\nRun `uvx pre-commit run -a` to lint and format before committing. Use `uv` for all commands; fall back to `venv` or `conda` only if `uv` is unavailable.\n\n```bash\n# Examples\nuv sync --extra examples\nuv run -m newton.examples basic_pendulum\n```\n\n## Tests\n\nFollow the canonical [test organization and runtime guidelines](CODING_GUIDELINES.rst#test-organization-and-runtime) when changing or reviewing tests.\n\n```bash\nuv run --extra dev -m newton.tests\nuv run --extra dev -m newton.tests -k test_viewer_log_shapes           # specific test\nuv run --extra dev -m newton.tests -k test_basic.example_basic_shapes  # example test\nuv run --extra dev --extra torch-cu12 -m newton.tests                  # with PyTorch\n```\n\n```bash\n# Benchmarks\nuvx --with virtualenv asv run --launch-method spawn main^!\n```\n\n## PR Instructions\n\n- If opening a pull request on GitHub, use the template in `.github/PULL_REQUEST_TEMPLATE.md`.\n- Follow `changelog/README.md`: add a Towncrier fragment for user-facing changes instead of editing `CHANGELOG.md` directly. A `.skip` reason is optional for changes without user-facing impact.\n- Preview fragments with `uvx --from towncrier==25.8.0 towncrier build --draft --version X.Y.Z --date YYYY-MM-DD`.\n\n## Examples\n\n- Follow the `Example` class format.\n  - Implement `test_final()` or `test_post_step()`; an example may implement both.\n  - In test mode, `test_post_step()` runs after each simulation step and `test_final()` runs after the example completes.\n- Register the example in `README.md` with its `python -m newton.examples <name>` command and a 320x320 JPEG screenshot.\n"},"files":{".agents/skills/code-review-newton/SKILL.md":"---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nRead `REVIEW_GUIDELINES.rst` and `CODING_GUIDELINES.rst` in full. Treat the\nformer as the explicit definitions of the Fit, Requirements, and Standards\naxes, and enforce the latter during Standards review.\n\n1. Resolve the exact merge base and head. Read the complete\n   `merge-base..head` diff and commit list.\n2. Read the pull-request description, linked issue or specification, relevant\n   primary sources, and `CODING_GUIDELINES.rst`. If no separate specification\n   exists, use the pull-request description as the stated intent. Do not read\n   existing review comments yet.\n3. Perform an adversarial correctness-first Requirements pass. Trace changed\n   inputs, state, counts, offsets, ownership, and outputs through every relevant\n   supported execution mode. Check applicable zero/one/many and capacity\n   boundaries, heterogeneous inputs, toggle/reset/reuse and partial failures,\n   CPU/CUDA and backend differences, autodiff, determinism, graph capture, and\n   numerical invariants. For performance changes, examine setup and steady-state\n   complexity, allocations, synchronization, transfers, and whether benchmarks\n   exercise the changed path. Answer the Honest contract, Siblings, Tests, and\n   Cost questions in `REVIEW_GUIDELINES.rst`. Run a minimal adversarial probe\n   when feasible. Apply the guides' schema and importer checks to authorable\n   features, including behavioral equivalence and explicit acceptance of\n   deferrals.\n4. Freeze candidate findings before reading existing reviews. Record the\n   location, triggering input or condition, mechanism, observable impact,\n   evidence, and confidence for each candidate.\n5. Read the top-level discussion and review threads. Refine or deduplicate the\n   independently discovered concerns; acknowledge existing concerns when they\n   affect the verdict.\n6. Review Fit and Standards independently using their definitions in\n   `REVIEW_GUIDELINES.rst`, and answer its Simplest and Principled questions\n   as part of Fit. When independent agent contexts are available, use separate\n   passes so one conclusion does not bias another.\n7. Report Fit and architectural concerns first, but retain every supported\n   material behavioral, correctness, compatibility, and performance finding\n   even when Fit fails. Do not let missing tests, documentation, or measurements\n   replace the search for an underlying behavioral defect.\n8. For each remaining concern, state its priority, location, problem, impact,\n   and evidence. Distinguish demonstrated defects from questions, evidence\n   requests, requirements, and judgment calls. Do not prescribe a correction\n   unless the user asks for one.\n\nAggregate the three axes without suppressing a finding merely because another\naxis passes. Give the explicit Fit verdict defined by the review guide.\n",".agents/skills/release-audit/SKILL.md":"---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\n---\n\n# Release Audit\n\nGenerates a markdown audit of a Newton release for keep/defer decisions (or, in retrospective mode, for skill calibration). Three modes, auto-detected in Phase 1:\n\nRead `CODING_GUIDELINES.rst` and `REVIEW_GUIDELINES.rst` from the\nrepository root before auditing. They define the canonical coding, API, and\nreview policies. This skill performs the final cross-release reconciliation;\nit does not replace pull-request review, and a prior review pass does not make\nany audit phase optional. In retrospective mode, using the current guides is\nintentional: calibrate the current audit policy against evidence pinned to the\ntarget tag. Do not claim historical noncompliance unless the requirement also\nexisted at that tag.\n\n- **Pre-release**: spot-check while work is still landing on main. No release branch cut. Version string is `X.Y.Z.devN`.\n- **Release-candidate**: readiness review after the release branch is cut. Version string is `X.Y.ZrcN` or head is `release-X.Y`.\n- **Retrospective**: audit an already-shipped release (e.g., `v1.1.0`) against its predecessor, with a Calibration Notes section (Phase 7) that checks the audit's flags against what subsequent patch/minor releases actually did. Triggered by passing a bare released-version argument that matches an existing git tag.\n\n**Output:** a single markdown report, filed according to the destination chosen in Phase 1:\n- **Secret gist** (default when `gh` is available and authenticated): stable filename `newton-<version-string>-<prerelease|rc|retrospective>-report.md`, stable description `Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report`. Later runs against the same version revise the same gist in place; prior versions are preserved in the gist's git history.\n- **Local markdown file** (fallback when `gh` unavailable, or opt-in when `gh` available): dated path at `$(git rev-parse --show-toplevel)/newton-<version-string>-<prerelease|rc|retrospective>-report-<YYYY-MM-DD>.md`. Not auto-committed; user moves, shares, or deletes as desired.\n\n**Inputs inferred from repo state:**\n- Pre-release / RC: target version from `pyproject.toml` (`version = \"...\"`). `newton/_version.py` reads from installed metadata at runtime and is not a static source.\n- Retrospective: target version from the user's argument. `pyproject.toml` is ignored.\n- Base = latest tag matching previous minor's line (`vX.Y-prev.*`, latest patch).\n- Head (pre-release / RC) = `upstream/release-<target>` if it exists, else `upstream/main`. Head (retrospective) = the `vX.Y.Z` tag itself.\n\n**Reference documents to load on demand** (via `Read`):\n- `references/report-template.md` — fill this in during Phase 7b (the `{{HEADLINE_SUMMARY}}` placeholder is drafted in Phase 7a).\n- `references/render-rules.md` — rendering conventions and output style hard constraints for Phase 7b.\n- `references/classification-rules.md` — path/symbol rules used in Phases 3-5.\n- `references/language-review-examples.md` — Phase 5 language-review calibration.\n\n## Phase 1 — Align on scope\n\n1. **Determine the mode.** Look at any target-version argument supplied with the invocation:\n\n   - **Argument present AND matches an existing tag** (`git rev-parse --verify v<arg>` or `git rev-parse --verify <arg>` succeeds, AND the resolved name looks like `vX.Y.Z` / `vX.Y.ZrcN`): **Retrospective mode**. The argument is the already-shipped target version. Skip `pyproject.toml` entirely; the tag is authoritative. Do not run the pre-release / RC reconciliation in step 4.\n   - **Argument present but does NOT match any tag**: treat as a version override for the upcoming release. Use it as if it came from `pyproject.toml`, then fall through to the pre-release / RC detection below.\n   - **No argument**: read the version string from `pyproject.toml` — the top-level `[project]` table's `version = \"...\"` line.\n\n   Normalize the selected version by removing one leading `v`, if present. Before using it in a title, filename, or path, require the normalized value to match `^[0-9]+\\.[0-9]+\\.[0-9]+(?:rc[0-9]+|\\.dev[0-9]+)?$`. If it does not match, stop and report the unsupported version. Do not construct an output path from an unvalidated version string.\n\n   Record the report date at the same time. In retrospective mode, use the target tag's creator date:\n   ```bash\n   git for-each-ref --format='%(creatordate:short)' refs/tags/v<version>\n   ```\n   This returns the tagger date for an annotated tag and the commit date for a lightweight tag. For pre-release and RC modes, use the current date (`date +%F`).\n\n   For the non-retrospective path, parse the version string to extract the target minor (e.g., `1.2.0.dev0` → target `1.2`) and pre-classify mode:\n   - If the version string contains `\"rc\"` (e.g., `1.2.0rc1`) → **RC mode candidate**: this is a release-candidate readiness report.\n   - If the version string contains `\"dev\"` (e.g., `1.2.0.dev0`) → **Pre-release mode candidate**: this is an early-stage audit of unreleased work.\n   - Otherwise → pre-release mode (default), but record the raw version string so the header can show it as-is.\n\n2. **Enumerate previous-minor tags** (applies to all modes):\n   ```bash\n   git tag --list 'v<prev-major>.<prev-minor>.*' --sort=-v:refname\n   ```\n   where `<prev-major>.<prev-minor>` is `target - 0.1` (e.g., for target `1.2`, previous minor is `1.1`). Retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`; release-candidate and other prerelease tags are not release baselines. Take the first remaining result as the base candidate. Ignore pre-1.0 `beta-*` tags when a stable `vX.Y.Z` line exists.\n\n   **Major-boundary fallback.** When `target.minor == 0` (e.g., `2.0.0`), the `target - 0.1` computation yields a minor line that never existed (`1.9`), and the tag list comes back empty. In that case, enumerate the highest minor line of the previous major instead:\n   ```bash\n   git tag --list 'v<target-major - 1>.*' --sort=-v:refname\n   ```\n   Apply the same exact stable-release filter, then take the first result (the last-patch of the last-minor of the previous major) as the base candidate. If both the primary and fallback searches return empty (which should only happen on a never-released line), surface that to the user in step 6 rather than silently proceeding.\n\n   For **retrospective mode** with target `X.Y.Z`: the base is the last `vX.Y-prev.*` tag strictly before `vX.Y.Z`. Also check whether `X.Y.Z` is itself a patch release (`.Z > 0`): if so, the \"base\" could be either the previous patch on the same minor (`vX.Y.<Z-1>`) OR the previous minor's latest. Present both in step 6 and let the user pick — a patch retrospective usually wants patch-on-patch; a minor-release retrospective wants previous-minor's last patch.\n\n3. **Probe for the head**:\n   - **Retrospective mode**: head is the `vX.Y.Z` tag directly. Resolve with `git rev-parse --verify v<target>`.\n   - **Pre-release / RC**:\n     ```bash\n     git rev-parse --verify upstream/release-<target>\n     ```\n     If this succeeds, head = `upstream/release-<target>` and this is also a strong signal for **RC mode** (the branch-cut has happened). Otherwise try `origin/release-<target>`; otherwise head = `upstream/main` (falling back to `origin/main`, then `main`) which is **pre-release mode**. Record whichever fallback was used for the report header.\n\n4. **Reconcile mode** from version string and head (skipped for retrospective mode; its mode is already fixed):\n   - Version says RC AND head is a release branch → **RC report** (strong match).\n   - Version says RC but head is main (branch not cut yet) → **RC report** (version is authoritative; note the mismatch in the header).\n   - Version says dev AND head is a release branch → **RC report** (branch cut implies we're past the dev window).\n   - Version says dev AND head is main → **Pre-release report**.\n\n5. **Probe `gh` availability and look up any existing matching gist.**\n\n   First run:\n   ```bash\n   gh --version && gh auth status\n   ```\n   If either fails → `gh` unavailable; destination will be a local markdown file only; skip the rest of this step.\n\n   Both succeeded → compute the stable gist title for this report:\n   ```text\n   Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report\n   ```\n   (e.g., `Newton 1.2.0rc1 Release Candidate Report`, `Newton 1.2.0.dev0 Pre-Release Report`, `Newton 1.1.0 Retrospective Report`). No date. The gist filename and description are stable so later runs can find the same gist and revise it; gist git history preserves prior versions automatically.\n\n   Run `gh gist list --limit 1000` and filter rows whose description exactly matches that stable title. Capture the matching gist IDs; display URLs are `https://gist.github.com/<id>`. Record the match count (0, 1, or N ≥ 2) for step 6.\n\n6. Present proposal in chat and **wait for explicit user confirmation** of refs AND output destination. Mandatory pause.\n\n   Lead with the mode-specific intro line:\n   - Pre-release: `Generating **pre-release report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>**. **<N>** commits in range.`\n   - RC: `Generating **release-candidate report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>** (release branch cut). **<N>** commits in range.`\n   - Retrospective: `Generating **retrospective report** for Newton **<version>** (already shipped). Base **<base-ref>** → Head **v<version>**. **<N>** commits in range. Calibration pass will cross-reference the audit's flags against subsequent patch / minor releases.`\n\n   For retrospective mode with a patch-target (when `.Z > 0`), also present the base choice explicitly:\n   > Base candidates for retrospective of `vX.Y.Z`:\n   > 1. `vX.Y.<Z-1>` (patch-on-patch: what changed since the previous patch on the same minor)\n   > 2. `v<prev-major>.<prev-minor>.<latest-patch>` (minor-boundary: what changed since the previous minor)\n   >\n   > Pick (1) or (2), or specify a different base.\n\n   Append the output block for the current `gh` / match state:\n\n   **`gh` unavailable:**\n   > Output: markdown file at repo root (`gh` not available). Confirm, or specify different refs?\n\n   **`gh` available, 0 matches:**\n   > Output: (a) new secret gist [default], (b) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, 1 match:**\n   > Output: (a) revise existing gist `<url>` [default], (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, N matches (N ≥ 2):**\n   > Multiple existing gists share the stable title:\n   > 1. `<url-1>` — updated `<time-1>`\n   > 2. `<url-2>` — updated `<time-2>`\n   > ...\n   >\n   > Output: (a) revise gist by number, (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   Do not run any further phase until the user confirms refs and (when `gh` is available) chooses destination. Translate the user's reply into exactly one of the destination tokens `local`, `new-gist`, `revise-gist:<id>` and record it for Phase 7c. Letters `(a)`, `(b)`, `(c)` are positional within the current branch's prompt, not global: resolve them against the option list you just showed the user. For the N-match branch, the user picks a gist by the number you listed (e.g., \"revise 2\" → `revise-gist:<id-of-listed-row-2>`), or says new / local.\n\n## Phase 2 — Gather ground truth\n\n1. Run the commit-list tool:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n     --base <base-ref> \\\n     --head <head-ref> \\\n     --report-date \"<report-date>\" \\\n     --main-ref <resolved-main-ref>\n   ```\n   from the repo root (`$(git rev-parse --show-toplevel)`). Use the date recorded in Phase 1 so retrospective bake time is measured as of the audited release rather than as of today. Capture stdout as the `commit_list_json`.\n\n2. Run the dependency and license audit helper:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py \\\n     --base <base-ref> \\\n     --head <head-ref>\n   ```\n   from the repo root. The helper requires Python 3.11+ for stdlib TOML parsing and exits with a clear preflight error on older Python versions. Capture stdout as `dependency_license_audit_md`. The helper compares:\n   - Direct requirements in `pyproject.toml`, grouped by runtime and optional extra.\n   - Resolved package names, duplicate variants, and version sets in `uv.lock` when present.\n   - `project.license` and `project.license-files` metadata in `pyproject.toml`.\n   - In-tree notice files matched by the `project.license-files` pathspecs declared at the base or head ref.\n   - Version-specific PyPI license metadata for newly introduced package names and changed locked package versions when network access is available. If metadata lookup fails, keep the helper's \"not checked\" text and surface that uncertainty rather than filling in a guessed license. If the helper was run with `--skip-pypi`, treat package-index metadata as deliberately deferred, not as per-package review failures.\n\n   Use one helper invocation as the source of the entire dependency/license section. Do not splice prose from a live metadata check onto tables produced by `--skip-pypi`. If a sandboxed or deferred run used `--skip-pypi` and a later host-side run can reach package indexes, replace the complete section with the default host-side output. Use `--skip-pypi` only as a fallback when a live metadata pass cannot be completed.\n\n   In Existing Resolved Package Version-Set Changes, the helper keeps standard license expressions and review statuses inline. Legacy or verbose nonstandard license text is rendered as a compact package-metadata link rather than copied into the report. The helper wraps this potentially long table in a closed `<details>` block; keep it collapsed by default so it does not dominate report scrolling.\n\n   The helper is intentionally stdlib-only. Do not replace it with a dependency inventory tool during the audit run: Newton avoids new release-only dependencies, and this script needs deterministic comparisons across arbitrary git refs without installing the target environment. External tools such as `pip-licenses`, `cyclonedx-py`, `pip-audit`, or `syft` can supplement a deeper investigation, but they do not replace this git-ref diff over `pyproject.toml`, `uv.lock`, declared license files, and version-specific PyPI metadata.\n\n   Interpretation rules for `dependency_license_audit_md`:\n   - A newly introduced external direct dependency or new resolved package name is license-relevant even when it lives behind an optional extra. Do not dismiss optional dependencies; state the extra or install path that pulls them in.\n   - A package that first appears in the lockfile only beneath a direct dependency already declared at the base is resolved-set churn, not a new dependency. The helper renders it in Existing Resolved Package Version-Set Changes with `(not resolved)` as the base and attributes the existing direct root. Reserve New Resolved Packages for packages introduced by a new direct dependency root or packages whose root cannot be established.\n   - A new optional extra whose dependencies are all already present is a support/install-surface change, but not a new package-license change.\n   - Existing package version bumps are not new licenses by themselves. The helper separates direct requirement moves from transitive-only churn; only elevate version bumps to release highlights or Behavioral & Support Changes when the package pin or compatibility constraint is user-visible.\n   - In-tree notice-file additions, removals, or modifications under the declared `project.license-files` pathspecs always appear in the dependency/license section. If a notice file is missing for a new bundled asset or vendored component, flag it in CHANGELOG Review Notes.\n   - If the helper reports license metadata as \"not checked\" due to lookup failure or \"not declared\" for a new package, keep that wording and mark it as needing release-manager review. Do not infer a license from package authorship or project name.\n   - If the helper reports \"not evaluated (--skip-pypi)\", say that package-index metadata was deferred and should be checked before final release sign-off. Do not turn that into a per-package review list.\n   - If a new package is proprietary, copyleft, commercial, unknown, not declared, or not checked due to lookup failure, mention that in the release highlights only when users can install it through a published extra or documented workflow.\n\n3. Load the pending or released changelog source by mode:\n   - **Pre-release / RC**: user-facing release scope is the rolling\n     `## [<target-version>]` section in `CHANGELOG.md`, when already assembled,\n     plus any later `.md` fragments on the resolved head. Before the first\n     Towncrier build, use the fragments plus legacy `[Unreleased]` entries.\n     Enumerate `changelog/*.md` with\n     `git ls-tree -r --name-only <head> -- changelog`, exclude `README.md`,\n     and read each file with `git show <head>:<path>`. Inventory `.skip` files\n     separately. Read `CHANGELOG.md` with `git show <head>:CHANGELOG.md`. If the\n     target's dated section exists, collect it through the next dated heading\n     and treat it as the assembled baseline. Otherwise, legacy entries are\n     between `<!-- towncrier release notes start -->` and the next dated `##`\n     heading.\n     If the audited head is the checked-out clean working tree, also run:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Use the draft output as the canonical preview for fragments not yet folded\n     into the rolling section; it does not modify `CHANGELOG.md` or delete\n     fragments. Audit the assembled baseline and draft additions together.\n   - **Retrospective**: read the target tag's changelog with\n     `git show v<target>:CHANGELOG.md`. Locate the `## [<target-version>]`\n     header and collect content up to the next dated `##` heading.\n\n4. Parse entries. Infer a fragment's section from its filename type (`added`,\n   `changed`, `deprecated`, `removed`, or `fixed`); the file content is one\n   entry without a leading bullet. Parse legacy or dated Markdown under the\n   corresponding five `###` headings. For every entry, extract:\n   - **Raw text (FULL — never truncate)**: the full bullet content (may span multiple lines).\n   - **Section**: one of the five names above.\n   - **Source path**: the fragment path or `CHANGELOG.md`.\n   - **Fragment identifier**: the numeric issue or leading-`+` orphan prefix\n     from the filename. Same-category counters do not change the identifier.\n   - **GH refs**: regex `GH-(\\d+)` over the bullet text. Dedup. (Newton commits and CHANGELOG entries sometimes also reference `#NNNN` as a bare PR number; capture these too.)\n   - **Migration hint**: does the prose contain a migration phrase (`use <new>`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`)? Record a boolean.\n\n   **Newton does NOT use a `**Breaking:**` literal marker in CHANGELOG** (unlike Warp). Do not rely on its presence. Breaking-change detection in Newton comes from: (a) the `### Removed` section (implicitly breaking), (b) signature-diff AST analysis (Phase 4e), and (c) reading `### Changed` prose for rename / parameter-reorder / signature-shift language (Phase 4d).\n\n## Phase 3 — Cross-reference\n\n1. **Build the commit ↔ CHANGELOG join** on GH-ref overlap:\n   - For each CHANGELOG entry with at least one GH ref, find commits (from `commit_list_json`) whose `gh_refs` intersect.\n   - For each pending fragment, find the commit that added its exact path:\n     ```bash\n     git log --reverse --diff-filter=A --format='%H|%s|%cs' \\\n       <base-ref>..<head-ref> -- changelog/<fragment-filename>\n     ```\n     Numeric identifiers link to issues, not necessarily to the implementing\n     pull request, so the fragment-addition commit is the authoritative join.\n   - For legacy entries and any fragment still lacking a backing commit, put\n     the distinctive substring in `entry_text` without interpolating it into\n     shell source, then search exact text across both storage forms:\n     ```bash\n     git log --reverse -S\"$entry_text\" \\\n       --format='%H|%s|%cs' <base-ref>..<head-ref> -- CHANGELOG.md changelog\n     ```\n     The first commit that is not a Towncrier build, synchronization, or another\n     changelog-only edit usually is the code change associated with the entry.\n     Record that as the backing commit.\n   - After these two passes, any CHANGELOG entry still with no matching commit is a genuine orphan case (deferred/dropped). Keep full entry text; do not truncate in the report.\n\n2. **Do NOT build an audit trace of unmatched commits.** The old \"commits without CHANGELOG entries\" appendix adds noise without value. Commits that don't map to a CHANGELOG entry are not surfaced in the report.\n\n## Phase 4 — Analyze API surface\n\n### 4a — Determine what is genuinely NEW API\n\nFor each CHANGELOG `Added` entry, extract the named symbol(s) — text in backticks matching `newton.*`, bare `ClassName`, bare `snake_case_name()`, or `ClassName.method()` patterns.\n\nFor EACH named symbol, check if it existed at base. Newton exposes user-facing symbols through multiple public re-export modules (not a single `__init__.py`). See `references/classification-rules.md` → \"Public API surface\" for the discovery rules. `docs/generate_api.py::api_modules()` discovers top-level public modules from module-valued names in `newton.__all__`; `solver_submodule_pages()` adds public solver module trees. There is no fixed `MODULES` constant. Inspect this discovery code plus `newton/__init__.py` and `newton/solvers.py` at both refs because the exported module set may grow or shrink between releases.\n\nTo check presence at base, run `git show <base>:<path>` for each relevant public module and grep its imported names. For method additions on an existing class (e.g., `SolverXPBD.update_contacts()`), inspect the class body at base in its real source (resolved via `_src/`). For retrospective mode, \"HEAD\" in the symbol-resolution text below means the `v<target>` tag, not the working tree. Use `git show v<target>:<path>` everywhere the pre-release / RC flow uses the working tree.\n\nClassification:\n- **Genuinely new** (symbol was not present at base) → **New API** section.\n- **Existed at base** (entry is adding a new parameter, option, or capability to something that already existed) → **Changes to Existing API** section with a \"capability extension\" or \"new parameter\" kind. Cite the backing commit's signature diff.\n- **Does not name a single symbol** (e.g., \"Interactive example browser in the GL viewer with tree-view navigation\") and describes a cross-cutting capability → **Behavioral & Support Changes** section unless one of the mentioned symbols is genuinely new (in which case split: put the new symbol in New API, the capability description in Behavioral).\n\n**If an entry mentions multiple symbols where some are new and some pre-existed** (e.g., \"Add `newton.geometry.compute_offset_mesh()` and a viewer toggle\"), split: the genuinely new symbols each get a New API entry; the extensions to existing symbols each get a Changes entry.\n\n**Public-API declaration and exposure check.** At HEAD, inspect every public\nmodule discovered by `api_modules()` and `solver_submodule_pages()`. Each module\nmust define `__all__` as a list or tuple containing only strings; a missing or\ninvalid declaration is a policy finding in \"CHANGELOG Review Notes\". For every\nsymbol that passes the \"genuinely new\" test, collect its memberships across\nthose declarations:\n\n- No memberships: report 🕵️ Private-only. The symbol exists only under\n  `newton._src.*` and was not re-exported through a public module.\n- One membership: the symbol has a canonical public import path.\n- More than one membership: report a duplicate-public-export policy finding\n  and list every public module that exports it.\n\n`CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one\npublic module's `__all__` and forbids examples/docs from importing\n`newton._src`. Do not treat the private-only finding as a hard block on the\nentry; surface it so the release manager can confirm the symbol was intended\nto be public. Treat missing or invalid declarations and duplicate exports as\npolicy findings that require an explicit release decision.\n\n### 4b — Resolve New API signatures + docstrings\n\nFor each symbol confirmed as new:\n\n1. Find its real source module by following the re-export in the public module (e.g., `newton/solvers.py` → `newton/_src/solvers/xpbd.py`).\n2. `ast.parse` the source module; find the `FunctionDef` / `ClassDef` / `AsyncFunctionDef`.\n3. Extract the signature by re-stringifying the args (preserve type annotations).\n4. Extract the docstring verbatim via `ast.get_docstring(node)`.\n5. Render as shown in the template.\n\nNewton has no kernel-scope builtins layer to extract (no `add_builtin()` registry like Warp). All user-facing symbols live in Python modules and `ast` resolves them directly.\n\n### 4c — Symbol resolution fallbacks\n\n- **Symbol in backticks doesn't resolve at HEAD**: render the entry with a ⚠️ note: \"Couldn't resolve `<symbol>` in source — verify entry names a real public symbol.\" Do not fabricate a header like `newton.*(no symbol)*`. Use the entry's natural subject as the section title.\n- **Entry describes a topic, not a symbol** (e.g., \"Interactive example browser in the GL viewer\"): use a short descriptive title summarized from the entry (e.g., \"Interactive example browser\"), not a synthetic `newton.*` name.\n- **Header naming rule**: section headers in the report should be either real fully-qualified symbols (`newton.solvers.SolverXPBD.update_contacts`) OR short descriptive titles extracted from the entry. Never `newton.*`, `newton.(something)`, or similar stub patterns.\n\n### 4d — Changed / Removed / Deprecated signature diffs\n\nFor each CHANGELOG entry in Changed / Removed / Deprecated (plus any \"capability extension\" entries routed here from 4a):\n\n- Compute signatures at base and HEAD (same resolution as 4b).\n- For signature-shape changes: render a fenced `diff` block showing `-` and `+` lines.\n- For semantic-only changes (no signature shift) where the prose describes a rename / reorder / behavioral flip: skip the diff block; include the backing commit's URL and the full CHANGELOG text.\n- For Removed entries: show the old signature on a `-` line; omit `+`.\n\n**Deprecation-window lookup for Removed entries.** Newton's policy (per `CODING_GUIDELINES.rst`) is: *breaking changes require a deprecation first*. Every Removed entry needs evidence of a deprecation in a prior release. Start with the released CHANGELOG, then fall back to code-level runtime-warning evidence at the base ref. For every Removed entry (and every Changed entry whose prose describes a removal), search CHANGELOG.md for the matching prior Deprecated entry:\n\n1. Extract distinctive tokens from the Removed entry: the named symbol(s) in backticks and, if the entry carries a GH ref, that ref number.\n2. Scan the appropriate released-version sections of CHANGELOG.md for a `### Deprecated` bullet that names the same symbol(s) OR the same GH ref. The search scope depends on mode:\n   - **Pre-release / RC**: scan all dated sections, top-down. Pending fragments and legacy current-cycle entries do not prove a prior shipped deprecation.\n   - **Retrospective** (current target is `X.Y.Z`): scan ONLY the sections strictly below `## [X.Y.Z]` in CHANGELOG.md — the prior-release sections. Do NOT consider `## [Unreleased]` or later-version sections; they were written after `X.Y.Z` shipped and cannot have preceded it. Top-down within the allowed range.\n   The FIRST such entry (highest version, since CHANGELOG is reverse-chronological) is the deprecation introduction.\n3. If a matching CHANGELOG entry is found, record: (a) the release version heading that contains the Deprecated entry (e.g., `1.0.0`), (b) the full Deprecated entry text.\n4. If no matching prior CHANGELOG entry is found, check for a code-level runtime deprecation at the base ref. Resolve candidate source paths using the removed symbol, legacy parameter, or literal value, then grep those paths for deprecation warnings and inspect the surrounding source:\n   ```bash\n   git grep -n -F '<distinctive-symbol-or-legacy-value>' <base-ref> -- newton\n   git grep -n -E 'DeprecationWarning|deprecated' <base-ref> -- <candidate-paths>\n   git show <base-ref>:<candidate-path>\n   ```\n   If the candidate uses a shared deprecation helper or decorator, resolve the imported name and inspect its definition at the base ref too:\n   ```bash\n   git grep -n -F '<helper-or-decorator-name>' <base-ref> -- newton\n   git show <base-ref>:<helper-definition-path>\n   ```\n   Count this as prior-deprecation evidence when a runtime `DeprecationWarning` at the base ref clearly applies to the exact removed symbol or behavior, either through a direct `warnings.warn(...)` call or through a shared helper / decorator. For helper-mediated evidence, verify both sides of the connection: the candidate path applies or calls the helper for the removed API, and the helper definition emits `DeprecationWarning` for the calling mode or behavior being removed. For example, `@deprecate_nonkeyword_arguments` is evidence for removing positional-argument support only when it decorates that callable at the base ref; it is not evidence that the callable itself was deprecated. A generic helper that merely exists or is imported, a warning elsewhere in the same file, a docstring without a runtime warning, or a warning added only after the base release does not count. Record the warning text, the helper application path, and the warning-emission path. The base ref proves the deprecation shipped by that release; only claim an earlier introduction version if the same connected evidence is verified at that earlier tag.\n5. In the rendered Removed entry, include one of these deprecation-window lines:\n   - CHANGELOG evidence: `Deprecated in X.Y.Z; removed here.`\n   - Runtime-only evidence: `Runtime deprecation present in <base-ref>; removed here. No matching prior CHANGELOG Deprecated entry was found.`\n   - No evidence: `No prior deprecation found in released CHANGELOG sections or in code at <base-ref> — Newton's policy requires deprecation before removal.`\n   Do NOT fabricate a version.\n\nThe deprecation window belongs in BOTH the Breaking Changes entry for the removal AND the Changes-to-Existing-API row (in the Description cell or as an appended sentence in the detail block). A reader should never have to ask \"was this deprecated first, and for how long?\"\n\n**Missing-deprecation flag.** Surface `🚨 Policy: removed without prior deprecation` only when BOTH checks fail: no prior Deprecated entry exists in a previously-released CHANGELOG section, and no matching direct or helper-mediated runtime `DeprecationWarning` exists at the base ref. This fires whether or not the current release's own `### Deprecated` section also names the symbol because a warning added only in the removal release did not ship in a prior release. The release manager needs this to block the release or add migration tooling.\n\nIf a matching runtime warning exists at the base ref but the released CHANGELOG has no corresponding Deprecated entry, the deprecation window is real. Do not emit a policy violation. Instead, add a non-blocking `🧾 Deprecation omitted from CHANGELOG` review note with the base ref, warning text, and the direct source path or connected helper application / emission paths so the release-note gap remains visible.\n\n**Exception: `1.0.0` pre-stable cleanup.** Removed entries in the `1.0.0` release (and `1.0.0rcN`) are exempt from the deprecation-first policy — PRs labeled `1.0-release` are the pre-stable API cleanup and were not required to go through a prior deprecation window. When the target version is `1.0.0` or `1.0.0rcN`, do not emit the `🚨 Policy` flag or the \"No prior **Deprecated** entry found\" line for its Removed entries. Still render the deprecation-window line if a matching Deprecated entry happens to exist; otherwise note `1.0 pre-stable cleanup; no prior deprecation required.`\n\n### 4e — Signature-AST diff for unlabeled migration-required changes\n\nIndependently of CHANGELOG content, compute the public API surface at base vs. HEAD by walking every symbol re-exported from the public modules in 4a:\n\n- Base: `git show <base-ref>:<module.py>` for each public module and for every real-source module it re-exports from → parse with `ast`. Resolve each re-export's real signature at base.\n- Target: same as Base, but at the target ref — the working tree in pre-release / RC mode, or `git show v<target>:<module.py>` in retrospective mode. Do NOT read the working tree in retrospective mode; later commits on `main` would otherwise be falsely attributed to `vX.Y.Z`.\n- For each symbol whose signature shape changed AND whose matching CHANGELOG entry (if any) doesn't indicate a rename / parameter shift / removal → add to Breaking Changes section as \"unlabeled signature change — please verify\".\n\n**Exception: Removed symbols are breaking by definition.** A symbol that appears in CHANGELOG's `Removed` section does NOT need prose hedging to be valid. Do NOT flag Removed entries as \"unlabeled breaking\" — the section name itself communicates the breakage. Removed entries surface in the Breaking Changes callout and in the Changes-to-Existing-API section (as \"removed\" kind), but the report must not whinge about missing Breaking labels on them.\n\n**Exception: additive keyword-only parameters with defaults are not migration-required.** A signature change that only adds new kwargs with defaults after `*` is additive; do not surface in Breaking Changes. It belongs in Changes-to-Existing-API with Kind `new parameter` and Breaking `No`.\n\n### 4f — Semantic-change candidates from solver / integrator commits\n\nNewton has no native C++/CUDA code (unlike Warp); there is no build-and-run verification step. However, changes to solver internals, integrators, collision pipelines, and math helpers can still change observable numerical behavior without altering any signature.\n\nFor each commit in `commit_list_json` that touches paths under `newton/_src/solvers/**`, `newton/_src/sim/**` (integrator / collision code), or `newton/_src/math/**`:\n\n1. Skip if the commit is already mapped to a CHANGELOG entry explicitly describing the semantic shift.\n2. Read the commit's diff: `git show --stat <sha>` then `git show <sha>` for small diffs, or read specific hunks for large ones.\n3. **Triage** into one of three buckets:\n   - **Clearly not semantic-breaking** → drop. Examples: renaming internal symbols, comment / format changes, pure internal refactors, performance optimizations that preserve output, test-only changes, bug fixes where the pre-fix behavior was itself a bug.\n   - **Clearly semantic-shifting** with an obvious user-observable numerical / behavioral change visible from the diff alone → include in Breaking Changes with a short \"Before / After\" explanation derived from the diff and commit message.\n   - **Ambiguous** — the diff suggests the change could affect numerical output but the audit cannot establish from reading alone whether users would notice → add a concise entry in a \"Review candidates\" subsection of CHANGELOG Review Notes (NOT Breaking Changes). Include the commit, the touched file(s), and a one-sentence hypothesis. Do not speculate in Breaking Changes.\n\n**Do NOT attempt to build and run Newton at base vs. HEAD.** Newton's solver outputs depend on Warp, MuJoCo, and GPU state; reproducing a numerical diff in a one-shot audit is not reliable and not worth the setup cost. When in doubt, route to the review-candidates list and leave verification to the release manager.\n\n### 4g — Experimental-marker cross-reference\n\nSome Newton features ship with an explicit `experimental` note in the CHANGELOG entry that introduced them (e.g., \"Add differentiable rigid contacts (experimental)\") or in docstrings. Changes to those features do NOT carry the same stability contract as changes to stable APIs. The report must reflect that so the release manager does not over-weight the concern.\n\nFor each entry in Breaking Changes, Changes to Existing API, and Removed (as collected through 4a–4f), determine whether the affected symbol or feature area is currently experimental:\n\n1. Collect candidate symbols / feature-area phrases from the entry: backticked identifiers, class names, and (for topic-style entries) the most distinctive descriptive noun phrase.\n2. Search CHANGELOG.md in released-version sections for bullets that name one of the candidates AND contain the literal substring `experimental` (case-insensitive). Also match via GH ref if the current entry and a prior experimental entry share a GH number. Scope:\n   - **Pre-release / RC**: all dated sections.\n   - **Retrospective** (current target is `X.Y.Z`): everything below `## [X.Y.Z]`. The stability-promotion check (step 3 below) likewise only considers versions strictly before `X.Y.Z`.\n3. If a match exists AND there is no subsequent CHANGELOG bullet in a later released version explicitly promoting the symbol to stable (e.g., \"Promote X out of experimental\", \"Stabilize Y\"), the symbol is still experimental. Record: (a) the release version that introduced the symbol as experimental, (b) the full text of that introduction bullet.\n4. Also check the module source at HEAD for an in-code `.. experimental` / `Experimental:` / `experimental_api` / `@experimental` annotation on the symbol's declaration. If present, treat as experimental regardless of CHANGELOG signal.\n\nTag every matched entry internally as `experimental=True`. Do not alter the CHANGELOG text itself.\n\n**How the tag changes rendering:**\n- Breaking Changes heading for the entry: prefix with `Experimental:` and do not use a warning emoji. Include a short sentence reminding readers that the symbol is opt-in and has a looser stability contract, with the release where the experimental marker was introduced.\n- Changes-to-Existing-API table: the Breaking column shows `Experimental` rather than `Yes`.\n- Release Highlights bullet (Phase 7a): if the item independently clears the significance bar, use a neutral `Experimental:` label without a warning emoji. Experimental status alone does not make an item a highlight.\n\n**Never drop the entry from the detailed audit.** Experimental status changes the stability interpretation, not the underlying API diff. A removed or signature-changed experimental symbol still appears in Breaking Changes and Changes to Existing API, but it is not presented as a release-manager warning.\n\n### 4h — Schema and importer completeness\n\nApply the guides' schema/importer policy to new or substantially changed\nauthorable features across the audited range, including existing-API extensions\nand commits without changelog entries. Inspect schema definitions/proposal\nrevisions, parsing, compatible schema-package versions, and behavioral tests at\nthe audited ref; schema representation alone is not complete support.\n\nRender **Schema & Importer Support** with columns\n`Feature | Disposition | Evidence / remaining work`:\n\n- **Supported**: record the supported subset and cite schema-to-builder-to-runtime\n  evidence, tests against equivalent builder-created models, and verified schema\n  semantics.\n- **Explicitly deferred**: cite review acceptance, reason, issue, owner, and\n  target milestone, plus the remaining limitation.\n- **Not applicable**: explain why the feature is runtime-only or non-authorable.\n- **Gap / decision required**: identify missing support, evidence, or accepted\n  deferral details for a keep/defer decision.\n\nFor retrospective audits, distinguish current-policy gaps from violations of\nrequirements in force at the target tag.\n\n## Phase 5 — Review CHANGELOG language and bake\n\n### 5a — Language review\n\nRead `references/language-review-examples.md`. For EACH CHANGELOG entry, apply LLM judgment:\n\n- **🔗 Wrong ref (tier-1)**: for every GH ref in the entry, fetch the mapped commits' subjects and paths. If the entry topic doesn't match the commits' actual scope, flag.\n- **🔗 Wrong ref (tier-2)**: if `gh --version` and `gh auth status` both succeed, run `gh issue view <num> --json title,body` per ref and compare issue title to entry topic. Skip silently if `gh` unavailable.\n- **🗣️ Internal language**: internal module paths (`newton._src.*`), private identifiers with a leading underscore, Warp-internal types (`wp.types.*` that are not documented user types), implementation-detail verbs (\"refactor\", \"reorganize\", \"rewrite\") without a user-visible outcome.\n- **📝 Too terse**: under ~10 words with no context, or missing migration guidance in a Deprecated / Changed entry that names a rename or removal.\n- **🕵️ Private-only symbol**: the CHANGELOG `### Added` entry names a symbol that exists only in `newton._src.*` at HEAD and is not re-exported through a public module. See Phase 4a.\n- **⬆️ Missing migration guidance** (Newton-specific): entries in `### Deprecated`, `### Removed`, or `### Changed` (where the prose indicates rename / reorder / removal) MUST include migration guidance per `changelog/README.md` (\"Use `Y` instead\", \"in favor of `Y`\", \"switch to `Y`\"). Flag entries that rename or remove symbols without pointing to the replacement.\n- **🏷️ Naming-convention drift** (Newton-specific): new public symbols in `### Added` whose names violate Newton's prefix-first convention (e.g., `PDActuator` should be `ActuatorPD`; `add_sphere_shape()` should be `add_shape_sphere()`). See `CODING_GUIDELINES.rst`.\n\nRecord flagged entries. Keep the FULL entry text in the audit table — do not truncate.\n\n### 5b — Bake aggregation\n\nFrom `commit_list_json`:\n- Bucket each commit's `days_in_main` into **🟢 (>14 days)**, **🟡 (7–14 days)**, **🟠 (<7 days)**. Commits whose `days_in_main` is `null` (no main equivalent) skip bucketing — do NOT coerce `null` to `0` or compare it to a numeric threshold; those commits are accounted for in the next bullet instead.\n- Count anomalies: commits with `main_equivalent_sha == null`. If non-zero, prepare the ⚠️ banner for the report header.\n\n### 5c — Dependency and license audit\n\nUse `dependency_license_audit_md` from Phase 2 as the report's `{{DEPENDENCY_LICENSE_AUDIT}}` section. Apply the interpretation rules listed with the helper invocation in Phase 2.\n\n## Phase 6 — Calibration Notes (retrospective mode only)\n\n**Skip this phase entirely in pre-release / RC mode.** There is no shipped history to calibrate against.\n\nIn retrospective mode, the Phase 3–5 output is a set of flags and classifications that would have surfaced had the skill been run *before* `X.Y.Z` shipped. The point of calibration is to check those flags against what *actually* happened after the release — did the concerns hold up? The output of this phase is a \"Calibration Notes\" section in the report (Phase 7b renders it).\n\n### 6a — Enumerate post-target history\n\nIdentify releases that shipped strictly after `X.Y.Z`:\n\n```bash\ngit tag --list 'v*' --sort=v:refname\n```\n\nBefore selecting post-target history, retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`. Exclude release-candidate and other prerelease suffixes. From that filtered, sorted list, drop everything up to and including `vX.Y.Z` and keep the rest. Typical post-target history for a minor release `vX.Y.0` is:\n- `vX.Y.1`, `vX.Y.2`, ... (patch releases on the same minor)\n- `vX.Y+1.0`, `vX.Y+1.1`, ... (the next minor and its patches)\n\nFor each post-target tag, read its CHANGELOG section (the `## [<version>]` block in `CHANGELOG.md` at HEAD, or via `git show <tag>:CHANGELOG.md` if the section has since been edited). Parse the five subsections (`Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`) the same way Phase 2 does.\n\nAlso collect the commits in each post-target range (`<prior-tag>..<tag>`) — one full `list_commits.py` invocation per range, with the same required args as Phase 2. `--main-ref` reuses the main ref resolved in Phase 1 (don't rely on the script's `upstream/main` default; Phase 1 may have fallen back to a different remote):\n\nFor each retained post-target tag, derive `<post-target-release-date>` with the same `git for-each-ref --format='%(creatordate:short)'` command used in Phase 1. This keeps any soak-time metadata relative to that release rather than the day the retrospective audit happens.\n\n```bash\nuv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n  --base <prior-tag> \\\n  --head <tag> \\\n  --report-date \"<post-target-release-date>\" \\\n  --main-ref <resolved-main-ref>\n```\n\nThese commits become the evidence pool for validating the Phase 4f semantic-change candidates.\n\n### 6b — Cross-reference audit flags against post-target history\n\nFor each flag class, run the check below and record one of three outcomes per flag:\n- **Validated** — subsequent history confirms the audit concern was real.\n- **Invalidated** — subsequent history contradicts the audit concern (false positive).\n- **Unresolved** — no post-target evidence either way (flag stands as-is, but the reader can treat it as lower-confidence).\n\nThe calibration section groups results by flag class and, within each, by outcome. Never drop a flag from the original report body because of calibration — the calibration is a separate layer of commentary.\n\n**🚨 Missing-deprecation (Removed without prior evidence):**\n- Validated if: (a) no prior released CHANGELOG section names the deprecation, (b) no matching direct or helper-mediated runtime `DeprecationWarning` exists at the retrospective base ref, and (c) the symbol stays removed. Users actually lost the API without a deprecation window.\n- Invalidated if: a prior Deprecated entry existed that the audit missed. Re-scan CHANGELOG scope with fuzzier matching (different casing, plural / singular, alternate backtick placement). Report the missed entry with its version.\n- Invalidated if: the base ref contains a matching direct or helper-mediated runtime `DeprecationWarning`. Report the warning text and the direct source path or connected helper application / emission paths, and classify the missing CHANGELOG bullet as a documentation gap rather than a deprecation-policy violation.\n- Invalidated if: a later patch (`vX.Y.<Z+1>`) added the symbol *back* (revert). Name the revert commit and note \"removal reverted in vX.Y.<Z+1>\".\n\n**🕵️ Private-only (new public API with `_src`-only reachability):**\n- Validated if: a later release adds a re-export for the symbol through a public module (`newton.<module>.py`). Cite the release and the re-export commit.\n- Invalidated if: the symbol stays reachable only via `_src` in every post-target release AND no issues reference it — it was probably intentional internal-only despite its position in the Added section. Note this as \"intended internal; CHANGELOG language could have been clearer\".\n- Unresolved if: the symbol was removed / renamed before re-export resolution.\n\n**⬆️ Missing-migration-guidance:**\n- Validated if: a later release's CHANGELOG bullet (in `### Changed` or `### Fixed`) retroactively points to the replacement, OR a subsequent issue references users stuck on the migration. The second signal is only available if `gh issue list` returns matches for the symbol name; probe with `gh issue list --search \"<symbol>\" --state all --json number,title`.\n- Invalidated if: the migration was handled by a runtime `DeprecationWarning` with a clear message (grep the code at `v<target>` for the warning text).\n- Unresolved: default.\n\n**🏷️ Naming-convention drift:**\n- Validated if: a later release renames the symbol to match Newton's prefix-first rule, typically with a DeprecationWarning on the old name. Cite the rename commit and the release.\n- Invalidated if: the symbol stays and matches the *local* module convention rather than the global prefix-first rule (e.g., a module of siblings that all use `<Kind>Foo`). Note which convention it actually follows.\n- Unresolved: default.\n\n**Phase 4f semantic-change candidates** (the ones routed to \"Review Candidates\", not Breaking Changes):\n- Validated if: a later patch release's `### Fixed` entry touches the same file(s) and describes a symptom consistent with the candidate's hypothesis (e.g., \"Fix convergence regression in SolverXPBD step ordering\" after a candidate about solver step ordering). Cite the fix commit and the release.\n- Invalidated if: the file stayed stable for the rest of the minor line with no related bug reports. Probe `gh issue list --search \"<file-or-feature>\" --state all --json number,title,createdAt` if `gh` is authenticated — only count issues created after `v<target>`'s release date. Skip the probe silently if `gh` is unavailable.\n- Unresolved: default.\n\n**Deprecation-follow-through (new check, retrospective-only):** for every entry in `X.Y.Z`'s own `### Deprecated` section, check subsequent minor releases for the corresponding `### Removed` entry.\n- **Followed through** — a later minor removed the symbol as promised. Cite the release.\n- **Still deprecated** — symbol remains in the public surface with the deprecation warning in all later minors. No action required; just a fact.\n- **Silently dropped** — symbol was removed but no `### Removed` entry cites it (CHANGELOG hygiene bug in the later release). Flag this as a separate concern.\n\n### 6c — Compose the calibration narrative\n\nAggregate the per-flag outcomes into a short section with this shape:\n- One-paragraph headline: how many flags were validated / invalidated / unresolved overall, a\n\n<!-- [TRUNCATED AT 50KB] -->",".agents/skills/release-audit/agents/openai.yaml":"policy:\n  allow_implicit_invocation: false\n",".agents/skills/release-audit/references/classification-rules.md":"# Classification Helpers\n\nThis reference is loaded during Phases 3, 4, and 5 of the skill. It defines concrete path and naming rules the audit relies on when analyzing commits and CHANGELOG entries.\n\n## Public API surface (Phase 4a, 4e)\n\nUsed to decide whether a symbol is \"genuinely new\" vs. \"pre-existed and got extended\":\n\nNewton exposes its public surface through per-topic re-export modules discovered dynamically by `docs/generate_api.py`:\n\n- `api_modules()` imports `newton`, starts with the top-level module, and adds every module-valued name exported through `newton.__all__`.\n- Each discovered module's own `__all__` list or tuple defines its public symbols. `public_symbols()` rejects missing declarations, invalid containers, and non-string entries.\n- `solver_submodule_pages()` adds public solver submodules and recursively exposed module trees under `newton.solvers`.\n- There is no fixed `MODULES` constant. Inspect `docs/generate_api.py`, `newton/__init__.py`, and `newton/solvers.py` at both refs so additions such as a new top-level public module or nested experimental solver namespace are included.\n\nRepresentative modules include `newton.geometry`, `newton.solvers`, and `newton.viewer`. Each public module re-exports from `newton/_src/<topic>/...`. `newton._src` is internal (`CODING_GUIDELINES.rst`: examples and docs must not import from `newton._src`).\n\n**To determine if `newton.X` existed at base**:\n- Inspect module-valued exports in `newton.__all__` at base and target using the `api_modules()` rules above.\n- For top-level symbols: `git show <base>:newton/__init__.py` and check `from ._src.<submodule> import X` / `__all__`.\n- For submodule public attributes (e.g., `newton.geometry.Mesh`): `git show <base>:newton/geometry.py` and check imports / `__all__`.\n- For nested solver modules: apply `solver_submodule_pages()` reachability rules to `newton.solvers` at the relevant ref.\n- For method additions on an existing class (e.g., `SolverXPBD.update_contacts`): resolve the class's real source file (e.g., `newton/_src/solvers/xpbd.py`) and `ast`-walk it at base.\n\n**Public-API declaration and exposure check (Phase 4a addition)**: inspect every discovered public module at HEAD. Its `__all__` must be a list or tuple containing only strings. For every genuinely new symbol, collect all public-module `__all__` declarations that contain it. Zero memberships raise a 🕵️ Private-only flag; one establishes the canonical public import path; more than one raises a duplicate-public-export policy finding listing all paths. Reason: `CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one public module's `__all__` and forbids examples/docs from importing `newton._src`.\n\n## No kernel-scope builtin registry\n\nNewton has no separate builtin registry to audit. All user-facing symbols are ordinary Python classes, functions, enums, and constants defined in `newton/_src/**` and re-exported through the public modules above. Skip kernel-scope symbol extraction.\n\n## Paths that trigger Phase 4f semantic-change review\n\nCommits touching these paths get per-commit judgment (Phase 4f). Not every change in them is a semantic shift — the audit reads the diff and decides:\n\n- `newton/_src/solvers/**` — solver implementations (XPBD, MuJoCo, Featherstone, VBD, implicit MPM). Changes can alter convergence, contact handling, step semantics.\n- `newton/_src/sim/**` — integrators, collision pipeline, model building, state transfer. Changes can alter per-step dynamics or contact ordering.\n- `newton/_src/math/**` — math helpers, raycast, quaternion utilities. Changes can shift numerical output.\n- `newton/_src/geometry/**` — geometry primitives, SDF / mesh representations, support functions. Changes can shift contact normals, distances, or inside/outside tests.\n\nTypical NOT-SEMANTIC-SHIFTING signals in these paths:\n- Pure internal refactors, renames of internal identifiers.\n- Comment or formatting changes.\n- Performance optimizations that preserve observable output (e.g., vectorization, precomputed AABBs).\n- Caching / memoization where the cached value is equivalent.\n- Test-only changes.\n- Build-system touches.\n- Bug fixes where the previous behavior was demonstrably wrong.\n\nTypical SEMANTIC-SHIFTING signals:\n- Algorithm swaps that produce different numerical results (e.g., switching SDF construction from winding-number to parity).\n- Default parameter value changes that affect physics (e.g., changing MPM quadrature, contact stiffness, solver iteration defaults).\n- Ordering / determinism changes that affect contact reduction or constraint solving.\n- Convergence criteria changes (different tolerance, different iteration bound behavior).\n- Unit / frame-of-reference changes for authored values (e.g., \"stop multiplying joint damping by 180/π\").\n- Control-flow changes that alter when callbacks / registered hooks / user kernels are invoked.\n\n**Never attempt to build and run Newton at base vs. HEAD for verification.** Newton's output depends on Warp codegen, MuJoCo, and GPU state; reliable head-to-head numerical verification in a one-shot audit is out of scope. When in doubt, route the commit to a \"Review candidates\" section in the report's review notes rather than speculating in Breaking Changes.\n\n## Heuristic paths commonly relevant (reference only)\n\nThese are noted here so the audit can pattern-match when reading commits, but the skill does NOT use them to produce an appendix-style commit audit. Purpose is recognition, not bucketing:\n\n- `.github/**`, `.pre-commit-config.yaml`, `uv.lock`, `.python-version` — infrastructure, not user-facing.\n- `asv.conf.json`, `asv/**`, root-level `_bench_*.py` — benchmark harness.\n- `docs/**`, root-level `*.md`, `CHANGELOG.md`, `changelog/**` — documentation.\n- `newton/examples/**` — example scripts. New files here are user-facing (a new example is a release-notable addition). Changes to existing examples are typically not release-notable unless they change the example's registered name or behavior.\n- `newton/_src/**` other than the solver / sim / math / geometry paths above — internal Python implementation.\n- `pyproject.toml`, `uv.lock`, and files matched by `project.license-files` — dependency and license-audit inputs. New external dependency names, direct requirement scope changes, new resolved package names, and notice-file changes belong in \"Dependency & License Audit\". Version bumps are not release-notable on their own; dependency changes may also belong in \"Behavioral & Support Changes\" if a user-visible pin moves (e.g., `mujoco-warp ~=3.7.0`).\n\n## Newton-specific rename and parameter-reorder recognition (Phase 4d, 5a)\n\nNewton's CHANGELOG does NOT use the `**Breaking:**` literal marker. Instead, migration-required changes appear in `### Changed` with prose like:\n\n- \"Rename `X.old_name` to `X.new_name`. Old name still accepted as keyword argument but emits a `DeprecationWarning`.\"\n- \"Reorder `X()` parameters so `a` precedes `b`.\"\n- \"Migrate all Y logic to Z, all Y functions now return ...\"\n\nWhen Phase 4d / 5a encounter these patterns, treat them as migration-required changes (Kind `rename` or `parameter reorder` in the Changes-to-Existing-API table). Check that the entry includes migration guidance (`Use ...`, `in favor of ...`, `prefer ...`). If guidance is missing, raise a ⬆️ flag in the language review.\n\n## Deprecation policy (Phase 4d)\n\n`CODING_GUIDELINES.rst`: breaking changes require a deprecation first. A prior released `### Deprecated` entry is the preferred evidence. A matching runtime `DeprecationWarning` at the base ref also proves that users received a deprecation window, even if the released CHANGELOG omitted it. The warning may be emitted directly or by a shared helper / decorator that clearly applies to the removed API or behavior.\n\nWhen Phase 4d cannot find the prior Deprecated entry:\n- Resolve the symbol or legacy behavior in code at the base ref.\n- Run a targeted `git grep` for `DeprecationWarning` / `deprecated` in the candidate path and inspect the warning context.\n- If the candidate calls or applies a shared deprecation helper / decorator, resolve that name and inspect its definition at the base ref. Verify that the candidate's call site connects the helper to the exact removed API or behavior and that the helper emits `DeprecationWarning`. A generic helper's existence or import alone is not evidence.\n- If a matching direct or helper-mediated runtime warning exists, record the base ref, warning text, and the direct source path or connected helper application / emission paths. Do not emit a policy violation; flag the missing released CHANGELOG entry as a documentation gap.\n- If no matching warning exists, surface `🚨 Policy: removed without prior deprecation` in the Breaking Changes section and cite the Removed entry in full.\n- Note whether the current CHANGELOG's own `### Deprecated` section also names the same symbol. Deprecating and removing in the same release is a policy violation because the warning did not ship in a prior release.\n\nA release manager reading the report should see one of three resolved outcomes:\n1. Prior CHANGELOG entry found: report its release version.\n2. Runtime `DeprecationWarning` found at base: deprecation policy satisfied, with a non-blocking CHANGELOG documentation flag.\n3. Neither found: block the release or add a deprecation shim for one more release cycle.\n\nDo not infer a policy violation from CHANGELOG evidence alone. The code-level check is mandatory before raising the blocking flag.\n",".agents/skills/release-audit/references/language-review-examples.md":"# CHANGELOG Language Review Examples\n\nLoaded during Phase 5 of the skill. Use these examples to calibrate the language-review pass: flagging entries whose language would confuse end users, whose refs look wrong, or whose content violates Newton's conventions.\n\n## What to flag\n\n### 🗣️ Internal / implementation language\n\nFlag entries that reference:\n\n- **Internal module paths**: `newton._src.foo`, `newton._src.solvers.xpbd.internal_helper`.\n- **Warp-internal helpers** that leaked into user-facing prose: e.g. `warp.fem.geometry.closest_point` (a Newton internal refactor may cite this; it is internal to Warp).\n- **Private identifiers** with leading underscores: `_foo`, `Model._finalize`.\n- **Implementation-detail verbs** without a user-visible outcome: \"Refactor internal dispatch path\", \"Reorganize private helpers\", \"Rewrite foo bar\".\n\nGood examples (user-facing):\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes from any collision shape, and a viewer toggle to visualize gap + margin wireframes in the GL viewer.\n>\n> Use pre-computed local AABB for `CONVEX_MESH` shapes in `compute_shape_aabbs`, avoiding a per-frame support-function AABB computation.\n\nFlag these:\n\n> Inline a `wp.vec3`-specialized point-to-triangle squared-distance helper in the implicit-MPM rasterized collider, removing the dependency on Warp's internal `warp.fem.geometry.closest_point`.\n> *Reason:* references `warp.fem.geometry.closest_point`, which is Warp-internal. User-facing rewrite: \"Inline point-to-triangle distance in the implicit-MPM collider so it no longer depends on Warp's `warp.fem` module.\"\n>\n> Refactor `newton._src.solvers.xpbd._update_constraints` to unify storage path.\n> *Reason:* references internal module + private method. Implementation detail with no user-observable effect. Candidate for deletion from CHANGELOG, not rewording.\n\n### 📝 Too terse\n\nFlag entries that are too short to convey meaning or that omit enough context for a user to act on:\n\n- Under ~10 words AND no linked issue for context.\n- Entries like \"Fix bug in XPBD solver\" without specifying which bug or what the fix does.\n\nFlag:\n\n> Fix bug.\n> *Reason:* insufficient — user can't tell what was fixed.\n>\n> Improve solver performance.\n> *Reason:* no specifics; which solver, how much, under what conditions?\n\nDon't flag (long but load-bearing):\n\n> Fix MJCF importer in `compiler.angle=\"degree\"` mode: (1) stop multiplying joint `damping`/`stiffness` by `180/π` (MuJoCo stores these in `N·m·s/rad` and `N·m/rad` regardless of `angle`); (2) stop `deg2rad`-scaling the default `±MAXVAL` sentinel for joints without an explicit `range=`.\n\n### 🔗 Suspected wrong GH reference\n\nFlag when the CHANGELOG entry's topic doesn't match the commits that cite that GH number.\n\n**Tier-1 heuristic (always on, fully local):**\n\nFor entry \"Add support for Gaussian splats (GH-NNNN)\", fetch commits tagged `GH-NNNN` and look at their subjects and file paths. If every commit only touches `.github/**` or `docs/**`, the GH ref is likely wrong — the entry describes a model-builder API change, but nothing in those commits modifies the builder or geometry. Flag.\n\nDon't flag if:\n- Commits touch `newton/_src/geometry/**` or `newton/_src/sim/builder.py` for a geometry-addition entry → topic matches.\n- Commits touch `docs/**` and the `Added` or `Changed` entry describes that documentation → topic matches.\n- Commits touch `newton/_src/solvers/**` for a solver-capability entry → topic matches.\n\n**Tier-2 heuristic (only if `gh` CLI is installed + authenticated):**\n\nFor each GH ref, run `gh issue view <num> --json title,body`. Compare the issue's title/topic to the entry's description. If clearly unrelated (e.g., issue is \"Improve MuJoCo solver performance\", entry is \"Add USD tetmesh import\"), flag.\n\nSkip tier-2 silently if `gh` is absent or auth fails.\n\n### 🕵️ Private-only symbol\n\nFlag `### Added` entries whose named public symbol exists only under `newton._src.*` at HEAD and is not re-exported through a public module (see `classification-rules.md` for the module list).\n\nExample flag:\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes.\n> *Check:* grep `newton/geometry.py` at HEAD. If `compute_offset_mesh` is not re-exported, raise 🕵️. If it is (the expected case), no flag.\n\nRationale: `CODING_GUIDELINES.rst` forbids examples and docs from importing `newton._src`. A user-facing symbol that lives only in `_src` cannot be used by Newton's own examples and is a maintenance liability.\n\n### ⬆️ Missing migration guidance (Newton-specific)\n\n`changelog/README.md`: for `Deprecated`, `Changed`, and `Removed` entries, include migration guidance such as \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n\nFlag `### Deprecated`, `### Removed`, and `### Changed` entries that name a rename / removal / reorder but do NOT express migration direction. Direction can be expressed with one of these phrases (case-insensitive): `use`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`, `prefer`. The phrase must identify a non-empty replacement target, normally as a backtick-delimited symbol. Direction can also be expressed structurally — an imperative `Rename X to Y`, an arrow `X → Y`, or a parameter-rename table — which counts as migration guidance even when none of the listed phrases appear verbatim (see the `ModelBuilder.add_shape_ellipsoid` example below).\n\nFlag:\n\n> Remove `SolverXPBD.legacy_substep()`.\n> *Reason:* no migration guidance. User does not know which method replaces it.\n>\n> Deprecate `Model.geo_meshes`.\n> *Reason:* no replacement named. Should read \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n>\n> Remove `Model.foo`; switch to improve performance.\n> *Reason:* \"switch to\" does not name a replacement target.\n\nDon't flag:\n\n> Deprecate `SensorContact.net_force` in favor of `SensorContact.total_force` and `SensorContact.force_matrix`\n> *Reason:* migration guidance present (\"in favor of ...\").\n>\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`. Old names are still accepted as keyword arguments but emit a `DeprecationWarning`\n> *Reason:* rename is explicit and the old-name behavior is documented.\n\n### 🏷️ Naming-convention drift (Newton-specific)\n\n`CODING_GUIDELINES.rst`: \"Prefix-first naming for autocomplete: `ActuatorPD` (not `PDActuator`), `add_shape_sphere()` (not `add_sphere_shape()`).\"\n\nFlag `### Added` entries whose newly-named public symbol puts the discriminator before the prefix. Examples of names to flag:\n\n- `PDActuator`, `VelocityActuator` → should be `ActuatorPD`, `ActuatorVelocity`\n- `SphereShape`, `CapsuleShape` → should be `ShapeSphere`, `ShapeCapsule`\n- `add_sphere_shape()`, `add_mesh_shape()` → should be `add_shape_sphere()`, `add_shape_mesh()`\n\nBefore flagging, cross-check against existing sibling symbols in the same module. If the rest of the module uses `Foo<Kind>` rather than `<Kind>Foo`, the new symbol should match the established pattern whichever direction it goes. Prefer consistency over a mechanical reading of the rule when the module has an entrenched local convention; call out the exception to `CODING_GUIDELINES.rst` explicitly.\n\n## Judgment philosophy\n\n**Err on \"mention, don't block\"**: flagging should raise a question for human review, not gate the report. The audit appendix shows flagged entries and a one-line reason; a human decides.\n\n**Don't auto-rewrite**: The audit flags the entry, never modifies it. Before the\nTowncrier build, the release manager updates pending fragments during changelog\nmaintenance; after release, corrections to dated history require explicit\nmaintainer approval.\n\n**Prefer false positives over false negatives**: a flag that turns out to be fine costs a 5-second eyeball. A missed wrong-ref or jargon-leak ships to users.\n\n**Exception for 🚨 policy flags.** The `🚨 Policy: removed without prior deprecation` flag (Phase 4d) is NOT a false-positive-tolerant flag. Only raise it after both an exhaustive search of prior released CHANGELOG sections and a targeted code search at the base ref fail to find deprecation evidence. A matching runtime `DeprecationWarning` satisfies the deprecation-window policy even when the CHANGELOG entry was forgotten; flag that case as `🧾 Deprecation omitted from CHANGELOG` instead.\n\n## Row format (for the report)\n\n| Entry (excerpt) | Flag | Why |\n|---|---|---|\n| \"Inline a `wp.vec3`-specialized ...\" | 🗣️ Internal language | References `warp.fem.geometry.closest_point` in user-facing prose |\n| \"Fix crash\" | 📝 Too terse | 2 words, no context link |\n| \"Add `newton.foo.bar` (GH-NNNN)\" | 🔗 Wrong ref? | Commits tagged GH-NNNN touch only CI files |\n| \"Deprecate `Model.foo`\" | ⬆️ Missing migration guidance | No \"in favor of\" replacement named |\n| \"Add `PDActuator`\" | 🏷️ Naming-convention drift | Should be `ActuatorPD` per prefix-first rule |\n| \"Add `newton.utils._x`\" | 🕵️ Private-only | Named symbol lives only in `newton._src`, not re-exported |\n| \"Remove deprecated `Model.foo`\" | 🧾 Deprecation omitted from CHANGELOG | Runtime warning exists at the base ref, but no released Deprecated entry records it |\n\nEntry excerpt should be ~60-80 chars so the table stays scannable. Keep the full entry text in the detail sections (never truncate there).\n",".agents/skills/release-audit/references/render-rules.md":"# Rendering Rules\n\nThis reference is loaded during Phase 7b of the release-audit skill. It defines the hard constraints and conventions for how the report is formatted when the template is filled in. Phase-flow logic lives in `SKILL.md`; this file is pure reference material.\n\n## Key rendering rules\n\n- Full commit URLs: `https://github.com/newton-physics/newton/commit/<full-sha>`.\n- Full issue URLs: `https://github.com/newton-physics/newton/issues/<num>`.\n- Preserve `diff` fence blocks for signature diffs.\n- Anomaly banner appears ONLY if any commit has `main_equivalent_sha: null`.\n- **Table of contents** sits immediately after the Release Highlights section (so the front matter reads: scope → version control → counts → bake → highlights → TOC → body). Link every top-level `##` section and every per-symbol / per-topic `###` heading under them.\n- **Document Version Control** appears near the top after the report scope metadata. For gist revisions, summarize the immediately preceding revision's audited head and commit count, list only materially changed report sections, and direct prior reviewers to those sections. Keep the report body current by replacing superseded conclusions rather than retaining them as history. For first publication, label it as the initial report. Include the section in the table of contents.\n- **Behavioral & Support Changes** section: group by topic with short descriptive titles (e.g., \"Deterministic contact ordering\", \"Dependency pins\", \"Build requirements\"). The audit synthesizes the titles from the entry content.\n- **Dependency & License Audit** section: render immediately after Behavioral & Support Changes and before Fixed. Use one complete `scripts/license_audit.py` output as-is except for global output-style cleanup. Never combine tables from a `--skip-pypi` run with prose from a separate live query. If a live host-side run succeeds, it replaces the entire deferred result. Keep uncertainty text such as \"not checked\", \"not evaluated (--skip-pypi)\", or \"not declared\"; do not replace it with guessed license metadata.\n- **Existing resolved package license cells stay concise.** Preserve standard license expressions and review statuses emitted by the helper. For legacy or verbose nonstandard values, keep the helper's package-metadata link instead of copying full license text into the report.\n- **Existing resolved package changes stay collapsed.** Keep the Existing Resolved Package Version-Set Changes table inside the helper's closed GFM `<details>` block. Leave the subsection heading and row-count summary visible, but do not add the `open` attribute; readers expand the long table only when needed.\n- **Experimental is a neutral stability label.** Never attach a warning emoji merely because an API is experimental. In Breaking Changes, use `Experimental:` without an emoji. Reserve `⚠️` for stable API or behavior changes that need an explicit acceptability review, and `🚨` for policy violations. The mixed Breaking Changes section heading itself has no warning emoji.\n- **Release highlights are significance-gated.** Keep 3-6 release-defining capabilities, workflows, broad behavioral shifts, or material compatibility decisions. Breaking or experimental status alone is not enough; omit routine deprecation cleanup, narrow signature changes, and minor dependency metadata follow-ups from highlights.\n\n## Output style — hard constraints on the generated report\n\n1. **No em dashes (`—`) anywhere in the report output.** Use colons, parentheses, or rewrite the sentence. This includes headings, bullet points, table cells, prose. Check every line before writing.\n\n2. **No internal skill terminology in the output.** The reader does not know what \"Phase 4f\", \"Phase 5a\", \"tier-1 heuristic\", or similar skill-internal names refer to. If a section needs explanation of how flags were produced, write it in plain user terms (e.g., \"Flagged because commits tagged with this GH ref don't touch any solver code\" instead of \"Tier-1 topic mismatch from Phase 5a\").\n\n3. **No mention of previously-shipped patch-release fixes.** The commit-list tool already scopes to `<base>..<head>`, so patch-release content is excluded automatically; do not manufacture a comparison to it.\n\n4. **No \"end of report\" or similar terminal markers.** The last section is the last section. No \"— end —\", no \"Thanks for reading\", no concluding paragraph, no closing quote.\n\n5. **Every GH ref is a markdown hyperlink** to `https://github.com/newton-physics/newton/issues/NNNN`. Plain-text `GH-NNNN` tokens, paren-grouped lists like `(GH-1287, GH-1298, ...)`, and shorthand like `(multiple GHs)` / `(see CHANGELOG)` are NOT acceptable, even when many refs bunch into one bullet or cell.\n\n6. **Signature and docstring render as a single fenced code block**, shaped like Python source so users see them in one glance. The exact shape depends on the kind of symbol.\n\n   **Functions and methods:**\n\n   ```python\n   newton.geometry.compute_offset_mesh(shape: ShapeFlags, offset: float) -> Mesh\n   \"\"\"Extract the offset surface mesh of a collision shape.\n\n   Longer description if present in the real docstring.\n   \"\"\"\n   ```\n\n   **Classes with only a constructor** (simple data holders or context managers):\n\n   ```python\n   class TetMesh:\n       \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n       Longer description if present.\n       \"\"\"\n\n       def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n   ```\n\n   **Classes with additional public methods**: list EVERY public (non-dunder, non-leading-underscore) method with its signature, plus the class docstring and each method's docstring if present. Do not just show `__init__`.\n\n   ```python\n   class SolverXPBD:\n       \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n       Short description of the solver's scope and typical use.\n       \"\"\"\n\n       def __init__(self, model: Model, iterations: int = 10)\n\n       def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n       \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n       def update_contacts(self, contacts: Contacts) -> None\n       \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n   ```\n\n   **Enum / IntEnum / IntFlag classes:** list every member with its integer value and its attribute docstring or comment, plus the class docstring. Do not show a constructor for enums.\n\n   ```python\n   class ShapeFlags(IntFlag):\n       \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n       VISIBLE = 1 << 0\n       \"\"\"Shape is rendered by viewers.\"\"\"\n\n       COLLIDE_SHAPES = 1 << 1\n       \"\"\"Shape participates in shape-shape collision.\"\"\"\n   ```\n\n   Extract member docstrings from the source using `ast` attribute-docstring form (`\"\"\"...\"\"\"` immediately following the assignment). If the member uses a `#:` comment or a trailing `#` comment, preserve that instead. If there is no per-member doc, show the member without one.\n\n   Do NOT separate \"Signature\" and \"Docstring\" into two headed subsections. Do NOT blockquote the docstring line by line; it lives inside the code block as Python source.\n\n7. **API summary tables** include a Description column AND a short-form signature in the Symbol cell. The Symbol cell shows the call shape WITHOUT type annotations so readers can skim the args at a glance. Defaults ARE included. The column order for New API tables is: `Symbol | Description | GH | Bake`. Examples of Symbol cells:\n\n   - Function: `newton.geometry.compute_offset_mesh(shape, offset)`\n   - Method: `SolverXPBD.update_contacts(contacts)`\n   - Class with constructor: `newton.TetMesh(vertices, tets)`\n   - Enum / flag (no call form): `newton.ShapeFlags`\n   - Decorator: `@newton.experimental`\n\n   Description is a short (≤ 10 word) phrase summarizing what the symbol does, pulled from the first sentence of its docstring or the CHANGELOG entry.\n\n8. **New API tables are grouped by Kind.** Render one table per Kind (\"Functions\", \"Classes\", \"Methods on existing classes\", \"Enums / flags\", \"Examples\"). Newton's \"Examples\" kind specifically covers additions under `newton/examples/**` that ship a user-runnable `python -m newton.examples <name>` entry.\n\n9. **Changes-to-Existing-API table columns**: `API | Kind | Breaking | Description | GH | Commits | Bake`. The API cell uses the same short-form call-shape convention as rule 7 (parameter names + defaults, no annotations). Description is a short phrase. Kind values include: `signature change`, `new parameter`, `capability extension`, `rename` (Newton-specific), `parameter reorder` (Newton-specific), `removed`, `deprecated`, `semantic change`. For any entry tagged experimental in Phase 4g, the Breaking cell reads `Experimental`. For any Removed entry, the Description also includes the deprecation-window fact from Phase 4d, using either the released CHANGELOG version (for example, \"Deprecated in 1.0.0; removed here.\") or the base-ref runtime-warning evidence.\n\n   **Bake-cell format (tables only).** Render the Bake column as `🟢 47d`, `🟡 12d`, `🟠 4d` — emoji, space, number-and-`d` joined with no intervening space. The joined `<N>d` form keeps the bucket/duration pair on one line when a narrow Markdown table wraps. For per-symbol detail blocks and prose, continue to spell out `🟢 47 days in main`; the compact form is for table cells only.\n\n10. **Audit appendix rendering is conditional.** If only one of the audit sections (CHANGELOG-orphan entries / language-review flags / Phase 4f semantic-review candidates) has any content, do not render an \"Audit Appendix\" umbrella heading. Just render the non-empty sections with their own top-level headings (e.g., `## CHANGELOG Review Notes`, `## Semantic-Change Review Candidates`). Only use an umbrella when two or more subsections are non-empty.\n\n11. **No Phase names anywhere.** If the report needs to explain a flag, write it in user-facing terms. Never write \"Phase 4e\", \"Phase 5\", etc.\n\n12. **Dependency/license section is always rendered.** If there are no package-name changes or in-tree notice changes, keep the helper's no-change sentence. Do not drop the section, because release managers use it as evidence that the audit ran.\n",".agents/skills/release-audit/references/report-template.md":"# Newton {{VERSION_STRING}} {{REPORT_KIND}} Report\nGenerated: {{REPORT_DATE}}\n\n<!-- {{REPORT_KIND}} is \"Pre-Release\", \"Release Candidate\", or \"Retrospective\",\n     chosen in Phase 1 from the argument, version string, and head ref.\n     {{VERSION_STRING}} is the raw version (e.g. \"1.2.0.dev0\" for pre-release,\n     \"1.2.0rc1\" for RC, \"1.1.0\" for retrospective). -->\n\n- Mode: {{MODE_DESCRIPTION}}\n- Head: {{HEAD_REF}} @ `{{HEAD_SHA_SHORT}}`\n- Base: {{BASE_REF}} @ `{{BASE_SHA_SHORT}}`\n- Commits in range: {{N_COMMITS}}\n\n<!-- {{MODE_DESCRIPTION}} is a one-liner:\n     Pre-release: \"Pre-release audit of unreleased work on main\"\n     RC: \"Release candidate readiness review (release branch cut)\"\n     Retrospective: \"Retrospective audit of shipped release v<version>; calibration\n                     pass cross-references the audit's flags against post-target history\" -->\n\n## Document Version Control\n\n{{DOCUMENT_VERSION_CONTROL}}\n\n<!-- Keep this section short and reviewer-oriented.\n\n     For a first publication, state that this is the initial report and name the\n     audited head and commit count.\n\n     For a revised gist, compare the prior report's audited head and commit count\n     with the current values, then list only the report sections whose conclusions\n     materially changed. Tell prior reviewers where to focus. End by stating that\n     every other finding was revalidated and that the report body contains only\n     current conclusions rather than retaining superseded text.\n\n     Do not use this section as a historical changelog. Gist history preserves old\n     revisions; this section is a compact review map for the immediately preceding\n     revision. -->\n\n\n**Headline counts**\n\n- {{N_NEW_API}} new public APIs\n- {{N_BREAKING}} breaking changes\n- {{N_CHANGED}} changes to existing API\n- {{N_BEHAVIORAL}} behavioral / support changes\n- {{N_FIXED}} fixes\n- {{N_EXAMPLES}} new examples\n\n**Bake distribution**\n\n| Bucket | Commits |\n|---|---:|\n| 🟢 > 14 days in main | {{N_BAKE_GREEN}} |\n| 🟡 7 to 14 days | {{N_BAKE_YELLOW}} |\n| 🟠 < 7 days | {{N_BAKE_ORANGE}} |\n\n{{ANOMALY_BANNER_IF_ANY}}\n\n<!-- Anomaly banner appears ONLY when any commit has main_equivalent_sha: null. Example:\n     > ⚠️ **N commits in the release have no equivalent on main. Investigate: these\n     > shipped without nightly/main-branch bake.**\n-->\n\n---\n\n## Release highlights\n\n{{HEADLINE_SUMMARY}}\n\n<!-- The audit's qualitative synthesis of what would land in the official release\n     notes. Drafted in Phase 7a. NOT release notes: a reviewer's preview so the\n     release manager can see at a glance whether the real release notes will\n     match expectations and spot items that need a keep/defer decision.\n\n     Shape: one short intro paragraph (2-3 sentences) followed by 3-6 bulleted\n     highlight items. Each bullet starts with a bold 2-6 word headline, then a\n     colon and a one-sentence rationale (what it is and why it matters).\n\n     Include status/risk markers inline only when they apply:\n       - 🟠 `N days` bake (if the headline item's minimum bake is < 7 days)\n       - Experimental (neutral label, no warning emoji, and only when the item\n         independently clears the significance bar)\n       - ⚠️ Stable change (a non-experimental API or behavior change that needs\n         a deeper release-manager acceptability decision)\n\n     Do NOT include counts (\"4 new APIs were added\"): that's already in the\n     headline counts block above. Highlights are qualitative.\n     Do NOT promote an item only because it is breaking or experimental. Routine\n     compatibility removals after a valid deprecation window, narrow signature\n     shifts, and dependency metadata follow-ups belong in the detailed sections.\n\n     Example shape (do NOT copy verbatim; pick items that are actually headline\n     material in THIS release):\n\n     Newton 1.2 lands Gaussian splat geometry, deterministic contact ordering, and\n     a new texture-based SDF pipeline that replaces NanoVDB for mesh-mesh collision.\n     One stable default change needs an explicit acceptability decision before cut.\n\n     - **Gaussian splat geometry** ([GH-NNN](...)): `Gaussian`, `ModelBuilder.add_shape_gaussian()`,\n       and USD import unlock radiance-field-style rendering as a first-class shape.\n       🟢 30 days bake.\n     - **Deterministic contact ordering** ([GH-NNN](...)): `deterministic` flag on\n       `CollisionPipeline` and `NarrowPhase` makes contact output GPU-thread-schedule\n       independent via radix sort and fingerprint tiebreaking. Required for reproducible\n       RL training. 🟢 22 days bake.\n     - **Texture-based mesh SDF** ([GH-NNN](...), [GH-NNN](...)): replaces NanoVDB\n       volumes in the mesh-mesh collision pipeline; faster and CPU-compatible. Every\n       GH ref is an individual hyperlink; never collapse to \"(multiple GHs)\" or a\n       plain-text comma list.\n     - **⚠️ Stable change: particle contacts enabled by default** ([GH-NNN](...)):\n       existing scenes can change trajectories, so the release manager should confirm\n       the new default and preservation path are acceptable.\n     - **Experimental: differentiable rigid contacts** ([GH-NNN](...)): gradients\n       with respect to body poses via `CollisionPipeline` when `requires_grad=True`;\n       contact-pipeline API may change in 1.3.\n     - **RJ45 plug-socket insertion example**: demonstrates SDF contacts, latch joint,\n       and interactive gizmo; release notes should lead with the showcase.\n-->\n\n---\n\n## Contents\n\n{{CONTENTS_BULLETS}}\n\n<!--\nExpand the TOC to include every `###` heading rendered in the body, not\njust the `##` top-level sections. List each per-symbol / per-topic heading\nas a sub-bullet under its parent section. Example shape (replace with the\nreal symbols / topics present in this specific report):\n\n- [Document Version Control](#document-version-control)\n- [New API](#new-api)\n  - [`newton.<symbol>`](#newtonsymbol)\n  - [`newton.<submodule>.<symbol>`](#newtonsubmodulesymbol)\n  - ...\n- [Breaking Changes](#breaking-changes)\n  - per-entry heading as sub-bullet\n- [Changes to Existing API](#changes-to-existing-api)\n  - per-entry heading as sub-bullet\n- [Behavioral & Support Changes](#behavioral--support-changes)\n  - per-topic heading as sub-bullet\n- [Dependency & License Audit](#dependency--license-audit)\n- [Schema & Importer Support](#schema--importer-support)\n- [Fixed](#fixed)\n- [Calibration Notes](#calibration-notes) (retrospective mode only)\n  - per-flag-class sub-bullet\n- [CHANGELOG Review Notes](#changelog-review-notes) (only if the conditional\n  appendix renders content)\n\nThe sample symbol names above are illustrative placeholders; do NOT ship them\nas-is. GitHub auto-renders a floating outline panel, but an explicit TOC\nstill helps raw-text readers.\n-->\n\n---\n\n## New API\n\n{{NEW_API_TABLES_BY_KIND}}\n\n<!-- Render one summary table per Kind. Columns: Symbol | Description | GH | Bake.\n     Kind groupings for Newton: \"Functions\", \"Classes\", \"Methods on existing classes\",\n     \"Enums / flags\", \"Constants\", \"Examples\". If only one Kind has entries, one\n     table is fine.\n\n     The Symbol cell uses a short-form call shape (no type annotations; defaults\n     included). Examples:\n     - `newton.geometry.compute_offset_mesh(shape, offset)`\n     - `newton.TetMesh(vertices, tets)`\n     - `SolverXPBD.update_contacts(contacts)`  (method on existing class)\n     - `newton.ShapeFlags`  (no parens for enums, decorators)\n     - `newton.examples.basic_pendulum`  (example module; the Symbol cell links to\n       the runnable name `python -m newton.examples basic_pendulum`). -->\n\n{{NEW_API_DETAIL_BLOCKS}}\n\n<!-- Per-symbol block template. Headings use the symbol name alone (no colons/em dashes).\n     The single fenced code block underneath holds signature-shaped content and\n     the docstring.\n\nSimple data class (constructor-only rendering):\n\n### `newton.TetMesh`\n\nLinks: [GH-NNN](...), commits: [abc1234](...), [def5678](...)\nSource: `newton/_src/geometry/tetmesh.py`\nBake: 🟢 47 days in main\n\n```python\nclass TetMesh:\n    \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n    Holds per-vertex positions and per-tet index quads; builders accept this\n    shape via ModelBuilder.add_shape_tetmesh.\n    \"\"\"\n\n    def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n```\n\nClass with multiple public methods (interface-style): list every public method\nwith its signature and docstring, not just __init__.\n\n### `newton.solvers.SolverXPBD`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 30 days in main\n\n```python\nclass SolverXPBD:\n    \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n    Supports rigid bodies, particles, cloth, and soft-body elements with a\n    common substepping loop.\n    \"\"\"\n\n    def __init__(self, model: Model, iterations: int = 10)\n\n    def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n    \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n    def update_contacts(self, contacts: Contacts) -> None\n    \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n```\n\nEnum / IntFlag: list every member with its value and per-member doc.\n\n### `newton.ShapeFlags`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/geometry/flags.py`\nBake: 🟡 12 days in main\n\n```python\nclass ShapeFlags(IntFlag):\n    \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n    VISIBLE = 1 << 0\n    \"\"\"Shape is rendered by viewers.\"\"\"\n\n    COLLIDE_SHAPES = 1 << 1\n    \"\"\"Shape participates in shape-shape collision.\"\"\"\n\n    COLLIDE_GROUND = 1 << 2\n    \"\"\"Shape participates in ground-plane collision.\"\"\"\n```\n\nMethod added to an existing class: the heading names the fully-qualified\nmethod path. The fenced block shows only that method, not the whole class.\n\n### `newton.solvers.SolverXPBD.update_contacts`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 21 days in main\n\n```python\ndef update_contacts(self, contacts: Contacts) -> None\n\"\"\"Populate contacts.force with per-contact spatial forces.\n\nDerives linear force and torque [N, N·m] from XPBD constraint impulses\naccumulated during the most recent step. Call after step().\n\"\"\"\n```\n\nExample (runnable under `python -m newton.examples <name>`): the Source cell\npoints to the example module; list the one-liner user invocation and the\nheadline simulation topic.\n\n### `newton.examples.robot.example_robot_humanoid`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/examples/robot/example_robot_humanoid.py`\nBake: 🟢 19 days in main\n\nRun:\n\n```\npython -m newton.examples example_robot_humanoid\n```\n\nShort paragraph explaining what the example demonstrates (the solver used,\nwhat the user will see, any dependencies like MuJoCo assets).\n-->\n\n---\n\n## Breaking Changes\n\n{{BREAKING_ENTRIES}}\n\n<!-- Flat list. Do NOT group under \"Author-labeled\" / \"Unlabeled\" / \"Semantic\"\n     subheadings. Every entry is simply a confirmed breaking change, regardless\n     of how it was identified. The audit collects entries from four sources:\n     (1) CHANGELOG Changed entries whose prose describes a rename / parameter\n         reorder / signature shift (Newton does not use a **Breaking:** marker;\n         recognition is prose-based),\n     (2) CHANGELOG Removed entries (implicitly breaking; flag as 🚨 Policy only\n         if neither a prior Deprecated entry nor a matching runtime warning at\n         the base ref is found),\n     (3) public-surface AST diffs between base and HEAD that aren't covered by\n         a CHANGELOG Changed / Removed entry,\n     (4) solver / integrator / math / geometry commits whose diff the audit reads\n         as clearly semantic-shifting (a numerical-output shift that a user\n         would observe). Ambiguous candidates go to \"Semantic-Change Review\n         Candidates\" in the review notes, NOT here.\n\n     Warning semantics:\n     - Prefix a non-experimental entry heading with `⚠️` when the stable API or\n       behavior change needs a deeper acceptability decision (for example, a\n       changed default, output semantics, or unshimmed signature shift).\n     - Prefix experimental entry headings with `Experimental:` and no warning\n       emoji. Their looser compatibility contract is context, not an alarm.\n     - Planned removals after a valid shipped deprecation window need no warning\n       emoji unless their breadth or remaining migration risk warrants review.\n     - Keep `🚨 Policy` for removals with no prior deprecation evidence.\n\n     Per-entry render format:\n\n     ### <heading: symbol name or short descriptive title>\n\n     Links: [GH-NNN](...), commit(s): [sha](...). 🟢 N days baked in main.\n\n     [If signature diff applies, a fenced diff block.]\n     [If behavior shift, a before/after code snippet synthesized from the diff\n      and the commit message.]\n\n     [1-3 sentences of explanatory prose in plain user-facing language.]\n\n     [Full CHANGELOG text blockquoted, if the entry came from CHANGELOG.]\n\n     [For removals backed only by a runtime warning at the base ref: a one-line\n      deprecation-window note plus a non-blocking CHANGELOG documentation flag.]\n\n     [For 🚨 Policy: removed without prior deprecation entries: a one-line\n      callout stating that neither released CHANGELOG nor base-ref code contains\n      deprecation evidence and what the release manager should do about it.]\n\n     Illustrative example (do not copy verbatim):\n\n     ### `ModelBuilder.add_shape_gaussian` parameter reorder\n\n     Links: [GH-NNN](https://github.com/newton-physics/newton/issues/NNN),\n     commit: [abc1234](https://github.com/newton-physics/newton/commit/abc1234). 🟢 22 days baked in main.\n\n     The `xform` argument now precedes `gaussian` to match every other\n     `add_shape_*` method on `ModelBuilder`. Callers that relied on positional\n     arguments must switch to keyword form. Passing a `Gaussian` as the second\n     positional argument still works but emits a `DeprecationWarning`.\n\n     Before:\n     ```python\n     builder.add_shape_gaussian(body_idx, gaussian, xform=my_xform)\n     ```\n\n     After:\n     ```python\n     builder.add_shape_gaussian(body_idx, xform=my_xform, gaussian=gaussian)\n     ```\n-->\n\n---\n\n## Changes to Existing API\n\n<!-- Covers CHANGELOG Changed, Removed, Deprecated, plus capability extensions\n     routed here from the new-API classification pass (e.g., \"Add support for X\n     in existing Y\"). -->\n\n{{CHANGED_SUMMARY_TABLE}}\n\n<!-- Columns: API | Kind | Breaking | Description | GH | Commits | Bake\n     Kind values: signature change, new parameter, capability extension, rename,\n     parameter reorder, removed, deprecated, semantic change. Description is a\n     short phrase (≤ 10 words). Breaking cell values: Yes / No / Experimental. -->\n\n{{CHANGED_DETAIL_BLOCKS}}\n\n<!-- Per-entry template (signature change). Use a colon in the heading, not an em dash.\n\n### `SolverMuJoCo`: new `enable_multiccd` parameter\n\nBreaking: **No** (additive keyword-only default)\nLinks: [GH-NNN](...), commit: [5c5f67e9](...)\nBake: 🟢 38 days in main\n\n```diff\n- def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True)\n+ def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True, enable_multiccd: bool = False)\n```\n\n**From CHANGELOG**\n> Add `enable_multiccd` parameter to `SolverMuJoCo` for multi-CCD contact generation\n> (up to 4 contact points per geom pair).\n\nCapability extension (existing API gains a new option/behavior):\n\n### `ModelBuilder.add_shape_*`: per-shape color\n\nLinks: [GH-NNN](...), commit: [abcdef12](...)\nBake: 🟢 35 days in main\n\nEvery `add_shape_*` method gains a `color=` keyword argument; `Model.shape_color`\nholds the authored per-shape display color for runtime edits; mesh shapes fall\nback to `Mesh.color` when available.\n\n```diff\n- def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True)\n+ def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True, color: Vec3 | None = None)\n```\n\n**From CHANGELOG**\n> <full CHANGELOG text blockquoted>\n\nRename (Newton-specific kind, soft deprecation via DeprecationWarning):\n\n### `ModelBuilder.add_shape_ellipsoid`: parameter rename\n\nBreaking: **Yes** (source break if old names used positionally)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 28 days in main\n\n```diff\n- def add_shape_ellipsoid(self, body: int, a: float, b: float, c: float, ...)\n+ def add_shape_ellipsoid(self, body: int, rx: float, ry: float, rz: float, ...)\n```\n\nOld names `a`, `b`, `c` are still accepted as keyword arguments but emit a\n`DeprecationWarning`. Positional callers must switch to keyword form.\n\n**From CHANGELOG**\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`.\n> Old names are still accepted as keyword arguments but emit a `DeprecationWarning`.\n\nRemoved symbol:\n\n### `Model.geo_meshes`: removed\n\nLinks: [GH-NNN](...), commit: [sha](...)\nDeprecation window: Deprecated in 1.0.0; removed here.\n\n```diff\n- geo_meshes: list[Mesh]\n```\n\n**From CHANGELOG (prior deprecation in 1.0.0)**\n> Deprecate `Model.geo_meshes` in favor of `Model.shapes`. Will be removed in a\n> future release.\n\n**From CHANGELOG (removal)**\n> <full CHANGELOG text blockquoted>\n\nExperimental-softened entry (symbol was shipped as experimental in a prior release; change here is technically source-breaking but the stability bar was advertised up front):\n\n### `SensorTiledCamera`: RenderContext reorganization\n\nBreaking: **Experimental** (since 1.0.0)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 40 days in main\n\n`SensorTiledCamera` landed as an experimental sensor in 1.0.0; this release\nsplits `RenderContext` into `RenderConfig` (config types) and `utils` (runtime\naccess), deprecates the old names, and adjusts default Gaussian sorting modes.\n\n```diff\n- class SensorTiledCamera:\n-     render_context: RenderContext\n+ class SensorTiledCamera:\n+     render_config: RenderConfig\n+     utils: SensorTiledCameraUtils\n```\n\n**From CHANGELOG (1.0.0 introduction, still experimental)**\n> Add `SensorTiledCamera` (experimental): GPU-tiled camera sensor for multi-agent RL.\n\n**From CHANGELOG (this release)**\n> <full CHANGELOG text blockquoted>\n-->\n\n---\n\n## Behavioral & Support Changes\n\n<!-- Group by topic with short descriptive section headings synthesized from\n     the entry content. Use colons in headings if separation is needed.\n     Related topics should live together.\n\n     Example headings (illustrative, choose based on actual content):\n     - \"Python minimum version bumped\"\n     - \"MuJoCo / mujoco-warp dependency pins\"\n     - \"Deterministic contact ordering\"\n     - \"USD import: visibility honored\"\n     - \"Mesh SDF construction: parity path\"\n     - \"Asset pinning for reproducible builds\"\n\n     Each topic: a short paragraph summary, links, commits, bake. -->\n\n{{BEHAVIORAL_SECTIONS}}\n\n---\n\n## Dependency & License Audit\n\n{{DEPENDENCY_LICENSE_AUDIT}}\n\n<!-- Render the markdown emitted by scripts/license_audit.py. This section is\n     always present. It compares direct dependencies, resolved lockfile package\n     names, version changes, and declared license-file pathspecs across the\n     release range. Use one complete helper result; never combine a\n     `--skip-pypi` table with prose from a separate live query. Preserve \"not\n     checked\", \"not evaluated (--skip-pypi)\", and \"not declared\" license\n     metadata exactly when package-index lookup was unavailable, deferred, or\n     inconclusive. Keep the helper's Existing Resolved Package Version-Set\n     Changes table inside its closed `<details>` block so the long table is\n     collapsed by default. -->\n\n---\n\n## Schema & Importer Support\n\n{{SCHEMA_IMPORTER_SUPPORT}}\n\n<!-- Render the Phase 4h table, or state that no relevant features were found. -->\n\n---\n\n## Fixed\n\n{{FIXED_TABLE}}\n\n<!-- Columns: Fix | GH | Commits | Bake\n     Keep the full CHANGELOG text in the Fix column; no truncation.\n     Do NOT mention fixes from previously-shipped patch releases. The commit-list\n     tool scopes to <base>..<head> so those are already excluded. -->\n\n{{CALIBRATION_NOTES}}\n\n<!-- Retrospective mode only. Pre-release / RC mode must leave\n     {{CALIBRATION_NOTES}} empty (template consumers should strip the whole\n     placeholder line, not leave a stray section heading).\n\n     Retrospective mode renders a ## Calibration Notes section here, immediately\n     after Fixed and before the optional audit appendix. Shape:\n\n     ## Calibration Notes\n\n     One-paragraph headline: overall validated / invalidated / unresolved counts\n     across all flag classes, plus a one-sentence takeaway on what the calibration\n     suggests about skill precision for this release.\n\n     ### 🚨 Missing-deprecation\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `Model.foo` | Validated | No prior Deprecated entry or matching runtime warning at the base ref; symbol stayed removed through 1.1.2. |\n     | `Model.bar` | Invalidated | Deprecated in 1.0.0 under `### Deprecated` — the audit's search missed it (lowercase `model.bar` in the entry). |\n\n     ### 🕵️ Private-only\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `newton._src.utils._helper` | Validated | Re-exported as `newton.utils.helper` in [1.1.1](commit-link). |\n\n     ### ⬆️ Missing-migration-guidance\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### 🏷️ Naming-convention drift\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### Semantic-change review candidates\n\n     | File / feature | Outcome | Evidence |\n     |---|---|---|\n     | `newton/_src/solvers/xpbd.py` contact-ordering diff | Validated | [1.1.1](commit-link) fixes \"convergence regression on stacked bodies\" — consistent with the flagged change's hypothesis. |\n\n     ### Deprecation follow-through\n\n     | Deprecated in this release | Followed through | Evidence |\n     |---|---|---|\n     | `Model.geo_meshes` | Followed through in 1.2.0 | Removed entry cites `Use Model.shapes`; matches the promised migration path. |\n     | `SensorContact.net_force` | Still deprecated | Symbol remains in the public surface through 1.2.1 with DeprecationWarning. |\n\n     Closing note (one or two sentences): what the calibration tells the reader\n     about Newton's release hygiene for this specific release.\n-->\n\n---\n\n{{OPTIONAL_APPENDIX}}\n\n<!-- Render conditionally based on content and wrap each non-empty section in\n     a GFM <details> block so it collapses by default (the umbrella content is\n     reference material, not headline reading).\n\n     Three cases:\n\n     1. Both CHANGELOG-orphan list AND language-review flags are empty:\n        Render nothing. No appendix heading, no trailing section.\n\n     2. Exactly ONE is non-empty: Render that one as a top-level section\n        (no \"Audit Appendix\" umbrella) with the table inside <details>.\n\n        ## CHANGELOG Entries Without Matching Commits\n        <details>\n        <summary>N entries (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        | full entry text | ... | ... |\n\n        </details>\n\n     3. Both are non-empty: Render an umbrella section; each subsection gets\n        its own <details>.\n\n        ## Audit Appendix\n\n        <details>\n        <summary>N CHANGELOG entries without matching commits (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        ...\n\n        </details>\n\n        <details>\n        <summary>N CHANGELOG entries flagged for review (click to expand)</summary>\n\n        | Entry | Flag | Why |\n        |---|---|---|\n        ...\n\n        </details>\n\n     Column rules for BOTH tables: full entry text (no truncation).\n     Flag glyphs: 🔗 (suspected wrong GH ref), 🗣️ (internal language),\n                  📝 (too terse or missing context),\n                  🕵️ (private-only symbol not re-exported through a public module),\n                  ⬆️ (Deprecated / Removed / rename entry missing migration guidance),\n                  🏷️ (new public symbol violates Newton's prefix-first naming),\n                  🧾 (runtime deprecation shipped but the released CHANGELOG omitted it),\n                  🚨 (removed without prior CHANGELOG or runtime deprecation evidence;\n                      policy violation surfaced in Breaking Changes and listed here\n                      for auditability).\n     An entry with multiple flags appears once per flag. -->\n\n<!-- Report ends here. Do NOT append \"end of report\", a closing quote, a thanks\n     note, or any terminal marker. -->\n",".agents/skills/release-changelog/SKILL.md":"---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nPending user-facing changes live in Towncrier fragments under `changelog/`.\n`CHANGELOG.md` is generated only on a release branch. Shipped sections are\nimmutable; the assembled section for the pending release remains a rolling\ndocument until tagging. Follow `changelog/README.md` as the command and format\nauthority.\n\n## Audit pending changes\n\n1. Identify the release ref and comparison base. Audit `release-X.Y` once it\n   exists; otherwise audit the intended main ref.\n2. Protect released history. Diff `CHANGELOG.md` from the latest stable tag and\n   require explicit maintainer approval for edits to dated sections.\n3. Render a non-mutating preview, which also validates Towncrier's renderable\n   fragment filenames:\n   ```bash\n   uvx --from towncrier==25.8.0 towncrier build --draft \\\n     --version X.Y.Z --date YYYY-MM-DD\n   ```\n4. Compare the preview with the release audit and commit range from the previous\n   release. Inspect `.skip` reasons separately.\n5. Preserve information. Rephrase, split, merge, or recategorize fragments only\n   when the facts remain intact. Ask before deleting information or downgrading\n   a user-visible change.\n6. Use only `Added`, `Changed`, `Deprecated`, `Removed`, and `Fixed`, in that\n   order. Keep migration and retesting guidance in affected entries.\n7. Remove exact and semantic duplicates. When a feature and its fix both land\n   in one cycle, describe the final user-visible behavior once.\n8. Keep `Added` for new public APIs, options, features, examples, and docs. Put\n   existing-API behavior, warning, default, importer, and solver changes in\n   `Changed`, even when they expand support.\n9. Give every breaking, removed, deprecated, or default-changing entry a\n   concrete action. Never direct users to `newton._src`.\n10. A numeric fragment identifier is a GitHub issue number. Towncrier renders\n    its issue link automatically; do not rewrite it as a pull request number.\n\n## Assemble the release during RC stabilization\n\nAfter the initial release scope has been audited on `release-X.Y`, assemble the\ncurrent fragments early enough for maintainer review:\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\nuvx --from towncrier==25.8.0 towncrier build --yes \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit rm --ignore-unmatch \"changelog/*.skip\"\ngit add -A CHANGELOG.md changelog\n```\n\nReview and approve the draft before running the mutating command. Towncrier\ninserts the dated section below `[Unreleased]` and deletes rendered fragments.\nIt ignores `.skip` files, so remove those explicitly. Review the staged diff in\na changelog-only pull request labeled `release-management`.\n\nAfter assembly, apply the audit rules above to the dated section: verify\ncompleteness, grouping, deduplication, wording, categories, and migration\nguidance. Keep editorial cleanup in the changelog-management commits that will\nlater be synchronized to `main`.\n\nThe first Towncrier release requires one migration audit. The insertion marker\nsits above the legacy `[Unreleased]` entries so they remain under the first\ngenerated release title. Merge duplicate category headings without dropping or\nduplicating an entry. Later releases need no special handling.\n\nTreat the assembled section as a rolling document. For every later cherry-pick\nbefore tagging:\n\n1. Validate the new fragments and render them with `towncrier build --draft`.\n2. Fold the previewed entries into the existing dated section without creating\n   a second release heading.\n3. Delete exactly the consumed `.md` and `.skip` fragments, then stage\n   `CHANGELOG.md` and `changelog/`.\n4. Rerun the changelog cleanup and `release-audit` checks, and merge the update\n   as another changelog-only `release-management` pull request.\n\nFinal GA preparation verifies the completed section and confirms that no\nrelease-branch fragments remain. Do not postpone the full cleanup until GA.\n\n## Synchronize to main\n\nAfter tagging:\n\n1. Create a changelog-only branch from current `main`.\n2. Cherry-pick, in order, every changelog-management commit from `release-X.Y`:\n   the initial Towncrier build, editorial cleanup, and all later cherry-pick\n   additions.\n3. Confirm fragments deleted by those commits disappear while fragments added to\n   `main` after the branch cut remain under `changelog/`.\n4. Confirm the dated section matches the release tag and older history is\n   unchanged.\n5. Open a changelog-only pull request labeled `release-management`.\n\nDo not replace the whole file with the release-branch copy. The commits'\npath-level deletions are what preserve main-only fragments.\n\n## Checks\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit diff v<latest-release> -- CHANGELOG.md changelog\ngit diff --cached --name-status -- CHANGELOG.md changelog\nrg -ni \"removed|deprecated|in favor of|use .* instead|renam|replac|default|breaking\" \\\n  CHANGELOG.md changelog\n```\n\nConfirm that `[Unreleased]` is empty after the first migration, no dated history\nchanged, released entries appear exactly once, and post-cut main fragments\nsurvive synchronization.\n",".agents/skills/release-notes/SKILL.md":"---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nDraft concise GitHub Release notes that explain why a Newton release exists and\nwhat users should know. Do not reproduce the full changelog; link to it.\n\nWrite for external users moving from the previous final release to the current\nartifact without assuming they followed development or release candidates.\nFinal-release notes must not mention earlier RCs. Never mention or link internal\nrelease audits, audit gists, readiness reports, cutoff SHAs, bake durations,\naudit counts, or other audit-only metadata; use those sources as evidence only.\n\n## Workflow\n\n1. Identify the artifact, target version, and release type:\n   - **GitHub release description**: public release page. Follow Newton/Warp\n     release-page style and include user-actionable migration sections.\n   - **Internal release announcement**: short internal email/doc. Use release\n     metadata first, then grouped bullets such as `New Features`,\n     `Performance Improvements`, and `Developer Experience`.\n   - If the user wants both and the content should converge, keep one document\n     only when explicitly requested; otherwise maintain separate drafts.\n   - Patch / bugfix releases: emphasize fixes, compatibility, and stability.\n   - Minor / feature releases: emphasize major user-facing capabilities.\n   - RCs: state that this is a release candidate and what needs validation.\n     If drafting final-release text from an RC tag or release branch, do not\n     mention the RC; use the RC only as the temporary source of truth.\n2. Choose changelog source material from the authoritative release ref:\n   - After the Towncrier build or tagging, read the matching dated\n     `CHANGELOG.md` section from the release tag or release branch.\n   - Before the build, check out the release branch, validate its pending\n     fragments, and render a non-mutating preview:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Draft from the preview and legacy `[Unreleased]` entries during the first\n     Towncrier transition. Do not run a mutating build merely to draft notes.\n   Do not rely on `main` unless the release is actually cut from `main`.\n3. Determine the previous release tag:\n   - Patch release `X.Y.Z`, `Z > 0`: use the highest earlier `vX.Y.<Z'>` tag.\n   - Feature release `X.Y.0`: use the highest `vX.<Y-1>.*` tag. If `Y == 0`,\n     use the highest tag from the previous major.\n4. Compare the release range against the previous release:\n   ```bash\n   git log --no-merges --oneline --cherry-pick --right-only v<previous>...v<target>\n   git diff --name-status v<previous>..v<target>\n   ```\n   Use the symmetric-difference `...` log form for counting and scanning commits\n   when a release branch contains cherry-picks; it avoids overstating scope with\n   equivalent patches already present in the previous release. Use the normal\n   `..` diff for changed files. If the final tag does not exist yet, use the\n   latest RC tag or `upstream/release-X.Y` as the temporary target.\n5. Inspect the PRs behind candidate highlights. Commit subjects usually carry\n   `(#NNNN)`; use PR bodies when needed to understand impact and any linked\n   issues.\n6. Check prior release-note and announcement formats when available:\n   - Newton release pages, e.g. `v1.2.0`, for the local public-release shape.\n   - Warp release pages for `Announcements`, `Upcoming removals`, and\n     acknowledgement patterns.\n   - Internal announcements for short internal release-email structure.\n7. Draft a high-level overview and a short highlights list. Keep only\n   consumer-relevant items. Omit CI, workflow, README layout, release-link\n   pinning, and other internal/docs polish unless the user explicitly asks or it\n   affects library users. When a validated release review supplies the\n   highlights, preserve its release-defining conclusions, ordering, and public\n   wording unless publication rules require a change. Rewrite audit-oriented\n   framing, remove audit-only metadata, and adapt references to the release-note\n   format without weakening the user-facing claims.\n8. Keep a review-ready release-branch draft. After tagging, refresh it against\n   the final tag and inspect the workflow-created draft GitHub Release. Publish\n   only after verifying the final artifact and links per `docs/guide/release.rst`.\n\n## Linking Rules\n\n- Link the changelog to the final release tag:\n  `https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor`\n- If drafting before the final tag exists, use `release-X.Y` or the RC tag\n  temporarily, but note that the published release should use the final tag.\n- Never link the changelog to `main` for a release branch unless `main` is the\n  authoritative release ref; `main` may have newer unreleased changes.\n- Add one GitHub reference to each highlight, usually the PR. Use an issue only\n  when there is no useful PR or the issue is the canonical context.\n- Avoid linking both an issue and a PR for the same highlight unless that extra\n  context is necessary.\n- In GitHub Release notes, render same-repository references as plain `#NNNN`\n  instead of full markdown links. GitHub auto-links them on the release page, and\n  the compact form matches Warp's release-note style.\n- Link in-tree examples or docs on the release tag URL, never `main`, so links\n  do not drift after publication.\n- For dependency summaries, prefer a link to the relevant `pyproject.toml`\n  compare over listing every changed constraint:\n  `https://github.com/newton-physics/newton/compare/v<previous>...v<target>?diff=split`\n  Mention only high-signal dependency changes in bullets.\n\n## Style\n\n- Start with a short paragraph naming the version, release type, and purpose.\n- Use a `## Highlights` section with typically 3-6 grouped bullets. Retain\n  additional release-defining highlights when the user explicitly requests them\n  or a validated release review establishes that they belong; do not drop a\n  significant theme merely to meet the usual count.\n- For bugfix releases, keep notes slim: no `## New features` section unless a\n  genuinely notable capability shipped in the patch. The highlights are a\n  categorized digest of fixes.\n- For feature releases, group related features by user workflow and order by\n  impact. Lead with the most important user-facing capability, not API names.\n- Prefer user impact over implementation detail.\n- Keep bullets compact: one bold label, one or two explanatory sentences, then\n  the `#NNNN` reference.\n- Treat the changelog as source material, not prose to copy. Translate internal\n  implementation terms into user-facing impact.\n- Include `## Announcements` only for changes users must act on, such as\n  removals, deprecations, platform-support changes, or dependency constraints.\n- For public feature releases, include focused sections for:\n  - breaking changes and removals,\n  - new deprecations,\n  - upcoming removals,\n  - dependency updates,\n  - acknowledgements.\n  Keep these concise; the changelog carries the exhaustive detail.\n- Include `## Notes` only for compatibility, install, or migration information\n  users need. Drop the section when there is nothing useful to say.\n- Include `## Acknowledgments` when there are meaningful contributions from\n  outside Newton maintainers and project-member groups. Omit trivial typo-only\n  or formatting-only changes.\n- For patch releases, say whether the release is intended to be API-compatible\n  with the previous patch/minor when that is true.\n- Avoid em dashes in rendered prose.\n- Keep raw Markdown soft-wrapped: use one physical line per paragraph and list item; let viewers wrap it to their window width.\n\n## Dependency Updates\n\nDo not default to a large table. Keep dependency updates high signal:\n\n- Call out major/minor runtime baseline bumps, new extras, dependency caps that\n  affect users, and removed caps when they unblock compatibility.\n- Link to the `pyproject.toml` compare for the complete detail.\n- If the prior patch release changed dependencies, compare against the closest\n  prior release tag, not the earlier minor tag.\n\n## Acknowledgments\n\nBefore listing outside contributors, verify they are not in Newton's maintainer\nor project-member groups.\n\n1. Read `newton-governance/CONTRIBUTORS.md` or the current governance source\n   when reachable. Treat it as the authority for maintainer and project-member\n   membership.\n2. If GitHub access is available and governance points to org teams, query the\n   current team slugs from GitHub rather than relying on a hardcoded list:\n   ```bash\n   gh api orgs/newton-physics/teams --paginate --jq '.[] | [.slug, .name] | @tsv'\n   gh api orgs/newton-physics/teams/<team-slug>/members --paginate --jq '.[] | .login'\n   ```\n   Prioritize teams named by governance, or teams whose current names clearly\n   identify maintainers, TSC, project members, or project-member organizations.\n3. Cross-check candidate PR authors with `gh pr view <number> --json author`\n   and commit emails. Commit email/company is a hint, not a substitute for the\n   team/governance check.\n4. Phrase the section accurately, for example \"outside the Newton maintainer\n   and project-member groups\" when that is the filter used.\n\n## Template\n\n```markdown\n# Newton vX.Y.Z\n\nNewton vX.Y.Z is a patch release following vX.Y.W. It focuses on bug fixes and\ncompatibility updates for the X.Y release line, especially around <areas>.\n\nFor the complete list of changes, see the [changelog](https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor).\n\n## Highlights\n\n- **<User-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n- **<Another user-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n## Announcements\n\n<Only include this section when there is a removal, deprecation,\nplatform-support change, dependency constraint, or other user-actionable\nannouncement. Drop it otherwise.>\n\n## Notes\n\nThis release is intended to be API-compatible with Newton vX.Y.W. No breaking\nchanges are expected.\n```\n",".claude/skills/code-review-newton/SKILL.md":"---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/code-review-newton/SKILL.md`. If it is unavailable, stop\nwithout performing the review.\n",".claude/skills/release-audit/SKILL.md":"---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\ndisable-model-invocation: true\nargument-hint: \"[target-version]\"\nallowed-tools: Bash(git log *) Bash(git show *) Bash(git grep *) Bash(git tag *) Bash(git rev-parse *) Bash(git diff *) Bash(git ls-tree *) Bash(uvx --from towncrier==25.8.0 towncrier build --draft *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/cleanup_report.py *) Bash(gh --version) Bash(gh auth status) Bash(gh gist create *) Bash(gh gist list *) Bash(gh gist view *) Bash(gh gist edit *) Bash(gh issue view *) Bash(gh issue list *) Read Write Grep Glob\n---\n\n# Release Audit\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-audit/SKILL.md`. If it is unavailable, stop without\nstarting the audit.\n",".claude/skills/release-changelog/SKILL.md":"---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-changelog/SKILL.md`. If it is unavailable, stop\nwithout modifying the changelog.\n",".claude/skills/release-notes/SKILL.md":"---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-notes/SKILL.md`. If it is unavailable, stop without\ndrafting or revising release text.\n","AGENTS.md":"# Newton Development Guidelines\n\nRead and follow the canonical [source code and public API guidelines](CODING_GUIDELINES.rst) before changing or reviewing Newton code. This file contains agent-specific workflow instructions; the linked guide is authoritative for coding and API design.\nFor reviews, also read and apply the [review guidelines](REVIEW_GUIDELINES.rst) and follow `.agents/skills/code-review-newton/SKILL.md`.\n\n- Create a feature branch on your fork before committing—never commit directly to `main`. Give the pull request a concise, descriptive title.\n- Use imperative mood in commit messages (\"Fix X\", not \"Fixed X\"), with a roughly 50-character subject and a body wrapped at 72 characters that explains what and why.\n- Verify regression tests fail without the fix before committing.\n\nRun `uvx pre-commit run -a` to lint and format before committing. Use `uv` for all commands; fall back to `venv` or `conda` only if `uv` is unavailable.\n\n```bash\n# Examples\nuv sync --extra examples\nuv run -m newton.examples basic_pendulum\n```\n\n## Tests\n\nFollow the canonical [test organization and runtime guidelines](CODING_GUIDELINES.rst#test-organization-and-runtime) when changing or reviewing tests.\n\n```bash\nuv run --extra dev -m newton.tests\nuv run --extra dev -m newton.tests -k test_viewer_log_shapes           # specific test\nuv run --extra dev -m newton.tests -k test_basic.example_basic_shapes  # example test\nuv run --extra dev --extra torch-cu12 -m newton.tests                  # with PyTorch\n```\n\n```bash\n# Benchmarks\nuvx --with virtualenv asv run --launch-method spawn main^!\n```\n\n## PR Instructions\n\n- If opening a pull request on GitHub, use the template in `.github/PULL_REQUEST_TEMPLATE.md`.\n- Follow `changelog/README.md`: add a Towncrier fragment for user-facing changes instead of editing `CHANGELOG.md` directly. A `.skip` reason is optional for changes without user-facing impact.\n- Preview fragments with `uvx --from towncrier==25.8.0 towncrier build --draft --version X.Y.Z --date YYYY-MM-DD`.\n\n## Examples\n\n- Follow the `Example` class format.\n  - Implement `test_final()` or `test_post_step()`; an example may implement both.\n  - In test mode, `test_post_step()` runs after each simulation step and `test_final()` runs after the example completes.\n- Register the example in `README.md` with its `python -m newton.examples <name>` command and a 320x320 JPEG screenshot.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Newton Development Guidelines\n\nRead and follow the canonical [source code and public API guidelines](CODING_GUIDELINES.rst) before changing or reviewing Newton code. This file contains agent-specific workflow instructions; the linked guide is authoritative for coding and API design.\nFor reviews, also read and apply the [review guidelines](REVIEW_GUIDELINES.rst) and follow `.agents/skills/code-review-newton/SKILL.md`.\n\n- Create a feature branch on your fork before committing—never commit directly to `main`. Give the pull request a concise, descriptive title.\n- Use imperative mood in commit messages (\"Fix X\", not \"Fixed X\"), with a roughly 50-character subject and a body wrapped at 72 characters that explains what and why.\n- Verify regression tests fail without the fix before committing.\n\nRun `uvx pre-commit run -a` to lint and format before committing. Use `uv` for all commands; fall back to `venv` or `conda` only if `uv` is unavailable.\n\n```bash\n# Examples\nuv sync --extra examples\nuv run -m newton.examples basic_pendulum\n```\n\n## Tests\n\nFollow the canonical [test organization and runtime guidelines](CODING_GUIDELINES.rst#test-organization-and-runtime) when changing or reviewing tests.\n\n```bash\nuv run --extra dev -m newton.tests\nuv run --extra dev -m newton.tests -k test_viewer_log_shapes           # specific test\nuv run --extra dev -m newton.tests -k test_basic.example_basic_shapes  # example test\nuv run --extra dev --extra torch-cu12 -m newton.tests                  # with PyTorch\n```\n\n```bash\n# Benchmarks\nuvx --with virtualenv asv run --launch-method spawn main^!\n```\n\n## PR Instructions\n\n- If opening a pull request on GitHub, use the template in `.github/PULL_REQUEST_TEMPLATE.md`.\n- Follow `changelog/README.md`: add a Towncrier fragment for user-facing changes instead of editing `CHANGELOG.md` directly. A `.skip` reason is optional for changes without user-facing impact.\n- Preview fragments with `uvx --from towncrier==25.8.0 towncrier build --draft --version X.Y.Z --date YYYY-MM-DD`.\n\n## Examples\n\n- Follow the `Example` class format.\n  - Implement `test_final()` or `test_post_step()`; an example may implement both.\n  - In test mode, `test_post_step()` runs after each simulation step and `test_final()` runs after the example completes.\n- Register the example in `README.md` with its `python -m newton.examples <name>` command and a 320x320 JPEG screenshot.\n","isInternal":false,"tokens":566,"sizeBytes":2401},{"name":"SKILL.md","path":".agents/skills/code-review-newton/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/code-review-newton/SKILL.md","title":"code-review-newton","category":"anthropic-skill","format":"markdown","content":"---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nRead `REVIEW_GUIDELINES.rst` and `CODING_GUIDELINES.rst` in full. Treat the\nformer as the explicit definitions of the Fit, Requirements, and Standards\naxes, and enforce the latter during Standards review.\n\n1. Resolve the exact merge base and head. Read the complete\n   `merge-base..head` diff and commit list.\n2. Read the pull-request description, linked issue or specification, relevant\n   primary sources, and `CODING_GUIDELINES.rst`. If no separate specification\n   exists, use the pull-request description as the stated intent. Do not read\n   existing review comments yet.\n3. Perform an adversarial correctness-first Requirements pass. Trace changed\n   inputs, state, counts, offsets, ownership, and outputs through every relevant\n   supported execution mode. Check applicable zero/one/many and capacity\n   boundaries, heterogeneous inputs, toggle/reset/reuse and partial failures,\n   CPU/CUDA and backend differences, autodiff, determinism, graph capture, and\n   numerical invariants. For performance changes, examine setup and steady-state\n   complexity, allocations, synchronization, transfers, and whether benchmarks\n   exercise the changed path. Answer the Honest contract, Siblings, Tests, and\n   Cost questions in `REVIEW_GUIDELINES.rst`. Run a minimal adversarial probe\n   when feasible. Apply the guides' schema and importer checks to authorable\n   features, including behavioral equivalence and explicit acceptance of\n   deferrals.\n4. Freeze candidate findings before reading existing reviews. Record the\n   location, triggering input or condition, mechanism, observable impact,\n   evidence, and confidence for each candidate.\n5. Read the top-level discussion and review threads. Refine or deduplicate the\n   independently discovered concerns; acknowledge existing concerns when they\n   affect the verdict.\n6. Review Fit and Standards independently using their definitions in\n   `REVIEW_GUIDELINES.rst`, and answer its Simplest and Principled questions\n   as part of Fit. When independent agent contexts are available, use separate\n   passes so one conclusion does not bias another.\n7. Report Fit and architectural concerns first, but retain every supported\n   material behavioral, correctness, compatibility, and performance finding\n   even when Fit fails. Do not let missing tests, documentation, or measurements\n   replace the search for an underlying behavioral defect.\n8. For each remaining concern, state its priority, location, problem, impact,\n   and evidence. Distinguish demonstrated defects from questions, evidence\n   requests, requirements, and judgment calls. Do not prescribe a correction\n   unless the user asks for one.\n\nAggregate the three axes without suppressing a finding merely because another\naxis passes. Give the explicit Fit verdict defined by the review guide.\n","frontmatter":{"name":"code-review-newton","description":"Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards."},"isInternal":false,"tokens":619,"sizeBytes":3059},{"name":"openai.yaml","path":".agents/skills/release-audit/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-audit/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"policy:\n  allow_implicit_invocation: false\n","isInternal":false,"tokens":11,"sizeBytes":43},{"name":"classification-rules.md","path":".agents/skills/release-audit/references/classification-rules.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-audit/references/classification-rules.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Classification Helpers\n\nThis reference is loaded during Phases 3, 4, and 5 of the skill. It defines concrete path and naming rules the audit relies on when analyzing commits and CHANGELOG entries.\n\n## Public API surface (Phase 4a, 4e)\n\nUsed to decide whether a symbol is \"genuinely new\" vs. \"pre-existed and got extended\":\n\nNewton exposes its public surface through per-topic re-export modules discovered dynamically by `docs/generate_api.py`:\n\n- `api_modules()` imports `newton`, starts with the top-level module, and adds every module-valued name exported through `newton.__all__`.\n- Each discovered module's own `__all__` list or tuple defines its public symbols. `public_symbols()` rejects missing declarations, invalid containers, and non-string entries.\n- `solver_submodule_pages()` adds public solver submodules and recursively exposed module trees under `newton.solvers`.\n- There is no fixed `MODULES` constant. Inspect `docs/generate_api.py`, `newton/__init__.py`, and `newton/solvers.py` at both refs so additions such as a new top-level public module or nested experimental solver namespace are included.\n\nRepresentative modules include `newton.geometry`, `newton.solvers`, and `newton.viewer`. Each public module re-exports from `newton/_src/<topic>/...`. `newton._src` is internal (`CODING_GUIDELINES.rst`: examples and docs must not import from `newton._src`).\n\n**To determine if `newton.X` existed at base**:\n- Inspect module-valued exports in `newton.__all__` at base and target using the `api_modules()` rules above.\n- For top-level symbols: `git show <base>:newton/__init__.py` and check `from ._src.<submodule> import X` / `__all__`.\n- For submodule public attributes (e.g., `newton.geometry.Mesh`): `git show <base>:newton/geometry.py` and check imports / `__all__`.\n- For nested solver modules: apply `solver_submodule_pages()` reachability rules to `newton.solvers` at the relevant ref.\n- For method additions on an existing class (e.g., `SolverXPBD.update_contacts`): resolve the class's real source file (e.g., `newton/_src/solvers/xpbd.py`) and `ast`-walk it at base.\n\n**Public-API declaration and exposure check (Phase 4a addition)**: inspect every discovered public module at HEAD. Its `__all__` must be a list or tuple containing only strings. For every genuinely new symbol, collect all public-module `__all__` declarations that contain it. Zero memberships raise a 🕵️ Private-only flag; one establishes the canonical public import path; more than one raises a duplicate-public-export policy finding listing all paths. Reason: `CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one public module's `__all__` and forbids examples/docs from importing `newton._src`.\n\n## No kernel-scope builtin registry\n\nNewton has no separate builtin registry to audit. All user-facing symbols are ordinary Python classes, functions, enums, and constants defined in `newton/_src/**` and re-exported through the public modules above. Skip kernel-scope symbol extraction.\n\n## Paths that trigger Phase 4f semantic-change review\n\nCommits touching these paths get per-commit judgment (Phase 4f). Not every change in them is a semantic shift — the audit reads the diff and decides:\n\n- `newton/_src/solvers/**` — solver implementations (XPBD, MuJoCo, Featherstone, VBD, implicit MPM). Changes can alter convergence, contact handling, step semantics.\n- `newton/_src/sim/**` — integrators, collision pipeline, model building, state transfer. Changes can alter per-step dynamics or contact ordering.\n- `newton/_src/math/**` — math helpers, raycast, quaternion utilities. Changes can shift numerical output.\n- `newton/_src/geometry/**` — geometry primitives, SDF / mesh representations, support functions. Changes can shift contact normals, distances, or inside/outside tests.\n\nTypical NOT-SEMANTIC-SHIFTING signals in these paths:\n- Pure internal refactors, renames of internal identifiers.\n- Comment or formatting changes.\n- Performance optimizations that preserve observable output (e.g., vectorization, precomputed AABBs).\n- Caching / memoization where the cached value is equivalent.\n- Test-only changes.\n- Build-system touches.\n- Bug fixes where the previous behavior was demonstrably wrong.\n\nTypical SEMANTIC-SHIFTING signals:\n- Algorithm swaps that produce different numerical results (e.g., switching SDF construction from winding-number to parity).\n- Default parameter value changes that affect physics (e.g., changing MPM quadrature, contact stiffness, solver iteration defaults).\n- Ordering / determinism changes that affect contact reduction or constraint solving.\n- Convergence criteria changes (different tolerance, different iteration bound behavior).\n- Unit / frame-of-reference changes for authored values (e.g., \"stop multiplying joint damping by 180/π\").\n- Control-flow changes that alter when callbacks / registered hooks / user kernels are invoked.\n\n**Never attempt to build and run Newton at base vs. HEAD for verification.** Newton's output depends on Warp codegen, MuJoCo, and GPU state; reliable head-to-head numerical verification in a one-shot audit is out of scope. When in doubt, route the commit to a \"Review candidates\" section in the report's review notes rather than speculating in Breaking Changes.\n\n## Heuristic paths commonly relevant (reference only)\n\nThese are noted here so the audit can pattern-match when reading commits, but the skill does NOT use them to produce an appendix-style commit audit. Purpose is recognition, not bucketing:\n\n- `.github/**`, `.pre-commit-config.yaml`, `uv.lock`, `.python-version` — infrastructure, not user-facing.\n- `asv.conf.json`, `asv/**`, root-level `_bench_*.py` — benchmark harness.\n- `docs/**`, root-level `*.md`, `CHANGELOG.md`, `changelog/**` — documentation.\n- `newton/examples/**` — example scripts. New files here are user-facing (a new example is a release-notable addition). Changes to existing examples are typically not release-notable unless they change the example's registered name or behavior.\n- `newton/_src/**` other than the solver / sim / math / geometry paths above — internal Python implementation.\n- `pyproject.toml`, `uv.lock`, and files matched by `project.license-files` — dependency and license-audit inputs. New external dependency names, direct requirement scope changes, new resolved package names, and notice-file changes belong in \"Dependency & License Audit\". Version bumps are not release-notable on their own; dependency changes may also belong in \"Behavioral & Support Changes\" if a user-visible pin moves (e.g., `mujoco-warp ~=3.7.0`).\n\n## Newton-specific rename and parameter-reorder recognition (Phase 4d, 5a)\n\nNewton's CHANGELOG does NOT use the `**Breaking:**` literal marker. Instead, migration-required changes appear in `### Changed` with prose like:\n\n- \"Rename `X.old_name` to `X.new_name`. Old name still accepted as keyword argument but emits a `DeprecationWarning`.\"\n- \"Reorder `X()` parameters so `a` precedes `b`.\"\n- \"Migrate all Y logic to Z, all Y functions now return ...\"\n\nWhen Phase 4d / 5a encounter these patterns, treat them as migration-required changes (Kind `rename` or `parameter reorder` in the Changes-to-Existing-API table). Check that the entry includes migration guidance (`Use ...`, `in favor of ...`, `prefer ...`). If guidance is missing, raise a ⬆️ flag in the language review.\n\n## Deprecation policy (Phase 4d)\n\n`CODING_GUIDELINES.rst`: breaking changes require a deprecation first. A prior released `### Deprecated` entry is the preferred evidence. A matching runtime `DeprecationWarning` at the base ref also proves that users received a deprecation window, even if the released CHANGELOG omitted it. The warning may be emitted directly or by a shared helper / decorator that clearly applies to the removed API or behavior.\n\nWhen Phase 4d cannot find the prior Deprecated entry:\n- Resolve the symbol or legacy behavior in code at the base ref.\n- Run a targeted `git grep` for `DeprecationWarning` / `deprecated` in the candidate path and inspect the warning context.\n- If the candidate calls or applies a shared deprecation helper / decorator, resolve that name and inspect its definition at the base ref. Verify that the candidate's call site connects the helper to the exact removed API or behavior and that the helper emits `DeprecationWarning`. A generic helper's existence or import alone is not evidence.\n- If a matching direct or helper-mediated runtime warning exists, record the base ref, warning text, and the direct source path or connected helper application / emission paths. Do not emit a policy violation; flag the missing released CHANGELOG entry as a documentation gap.\n- If no matching warning exists, surface `🚨 Policy: removed without prior deprecation` in the Breaking Changes section and cite the Removed entry in full.\n- Note whether the current CHANGELOG's own `### Deprecated` section also names the same symbol. Deprecating and removing in the same release is a policy violation because the warning did not ship in a prior release.\n\nA release manager reading the report should see one of three resolved outcomes:\n1. Prior CHANGELOG entry found: report its release version.\n2. Runtime `DeprecationWarning` found at base: deprecation policy satisfied, with a non-blocking CHANGELOG documentation flag.\n3. Neither found: block the release or add a deprecation shim for one more release cycle.\n\nDo not infer a policy violation from CHANGELOG evidence alone. The code-level check is mandatory before raising the blocking flag.\n","isInternal":false,"tokens":2121,"sizeBytes":9557},{"name":"language-review-examples.md","path":".agents/skills/release-audit/references/language-review-examples.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-audit/references/language-review-examples.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# CHANGELOG Language Review Examples\n\nLoaded during Phase 5 of the skill. Use these examples to calibrate the language-review pass: flagging entries whose language would confuse end users, whose refs look wrong, or whose content violates Newton's conventions.\n\n## What to flag\n\n### 🗣️ Internal / implementation language\n\nFlag entries that reference:\n\n- **Internal module paths**: `newton._src.foo`, `newton._src.solvers.xpbd.internal_helper`.\n- **Warp-internal helpers** that leaked into user-facing prose: e.g. `warp.fem.geometry.closest_point` (a Newton internal refactor may cite this; it is internal to Warp).\n- **Private identifiers** with leading underscores: `_foo`, `Model._finalize`.\n- **Implementation-detail verbs** without a user-visible outcome: \"Refactor internal dispatch path\", \"Reorganize private helpers\", \"Rewrite foo bar\".\n\nGood examples (user-facing):\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes from any collision shape, and a viewer toggle to visualize gap + margin wireframes in the GL viewer.\n>\n> Use pre-computed local AABB for `CONVEX_MESH` shapes in `compute_shape_aabbs`, avoiding a per-frame support-function AABB computation.\n\nFlag these:\n\n> Inline a `wp.vec3`-specialized point-to-triangle squared-distance helper in the implicit-MPM rasterized collider, removing the dependency on Warp's internal `warp.fem.geometry.closest_point`.\n> *Reason:* references `warp.fem.geometry.closest_point`, which is Warp-internal. User-facing rewrite: \"Inline point-to-triangle distance in the implicit-MPM collider so it no longer depends on Warp's `warp.fem` module.\"\n>\n> Refactor `newton._src.solvers.xpbd._update_constraints` to unify storage path.\n> *Reason:* references internal module + private method. Implementation detail with no user-observable effect. Candidate for deletion from CHANGELOG, not rewording.\n\n### 📝 Too terse\n\nFlag entries that are too short to convey meaning or that omit enough context for a user to act on:\n\n- Under ~10 words AND no linked issue for context.\n- Entries like \"Fix bug in XPBD solver\" without specifying which bug or what the fix does.\n\nFlag:\n\n> Fix bug.\n> *Reason:* insufficient — user can't tell what was fixed.\n>\n> Improve solver performance.\n> *Reason:* no specifics; which solver, how much, under what conditions?\n\nDon't flag (long but load-bearing):\n\n> Fix MJCF importer in `compiler.angle=\"degree\"` mode: (1) stop multiplying joint `damping`/`stiffness` by `180/π` (MuJoCo stores these in `N·m·s/rad` and `N·m/rad` regardless of `angle`); (2) stop `deg2rad`-scaling the default `±MAXVAL` sentinel for joints without an explicit `range=`.\n\n### 🔗 Suspected wrong GH reference\n\nFlag when the CHANGELOG entry's topic doesn't match the commits that cite that GH number.\n\n**Tier-1 heuristic (always on, fully local):**\n\nFor entry \"Add support for Gaussian splats (GH-NNNN)\", fetch commits tagged `GH-NNNN` and look at their subjects and file paths. If every commit only touches `.github/**` or `docs/**`, the GH ref is likely wrong — the entry describes a model-builder API change, but nothing in those commits modifies the builder or geometry. Flag.\n\nDon't flag if:\n- Commits touch `newton/_src/geometry/**` or `newton/_src/sim/builder.py` for a geometry-addition entry → topic matches.\n- Commits touch `docs/**` and the `Added` or `Changed` entry describes that documentation → topic matches.\n- Commits touch `newton/_src/solvers/**` for a solver-capability entry → topic matches.\n\n**Tier-2 heuristic (only if `gh` CLI is installed + authenticated):**\n\nFor each GH ref, run `gh issue view <num> --json title,body`. Compare the issue's title/topic to the entry's description. If clearly unrelated (e.g., issue is \"Improve MuJoCo solver performance\", entry is \"Add USD tetmesh import\"), flag.\n\nSkip tier-2 silently if `gh` is absent or auth fails.\n\n### 🕵️ Private-only symbol\n\nFlag `### Added` entries whose named public symbol exists only under `newton._src.*` at HEAD and is not re-exported through a public module (see `classification-rules.md` for the module list).\n\nExample flag:\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes.\n> *Check:* grep `newton/geometry.py` at HEAD. If `compute_offset_mesh` is not re-exported, raise 🕵️. If it is (the expected case), no flag.\n\nRationale: `CODING_GUIDELINES.rst` forbids examples and docs from importing `newton._src`. A user-facing symbol that lives only in `_src` cannot be used by Newton's own examples and is a maintenance liability.\n\n### ⬆️ Missing migration guidance (Newton-specific)\n\n`changelog/README.md`: for `Deprecated`, `Changed`, and `Removed` entries, include migration guidance such as \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n\nFlag `### Deprecated`, `### Removed`, and `### Changed` entries that name a rename / removal / reorder but do NOT express migration direction. Direction can be expressed with one of these phrases (case-insensitive): `use`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`, `prefer`. The phrase must identify a non-empty replacement target, normally as a backtick-delimited symbol. Direction can also be expressed structurally — an imperative `Rename X to Y`, an arrow `X → Y`, or a parameter-rename table — which counts as migration guidance even when none of the listed phrases appear verbatim (see the `ModelBuilder.add_shape_ellipsoid` example below).\n\nFlag:\n\n> Remove `SolverXPBD.legacy_substep()`.\n> *Reason:* no migration guidance. User does not know which method replaces it.\n>\n> Deprecate `Model.geo_meshes`.\n> *Reason:* no replacement named. Should read \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n>\n> Remove `Model.foo`; switch to improve performance.\n> *Reason:* \"switch to\" does not name a replacement target.\n\nDon't flag:\n\n> Deprecate `SensorContact.net_force` in favor of `SensorContact.total_force` and `SensorContact.force_matrix`\n> *Reason:* migration guidance present (\"in favor of ...\").\n>\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`. Old names are still accepted as keyword arguments but emit a `DeprecationWarning`\n> *Reason:* rename is explicit and the old-name behavior is documented.\n\n### 🏷️ Naming-convention drift (Newton-specific)\n\n`CODING_GUIDELINES.rst`: \"Prefix-first naming for autocomplete: `ActuatorPD` (not `PDActuator`), `add_shape_sphere()` (not `add_sphere_shape()`).\"\n\nFlag `### Added` entries whose newly-named public symbol puts the discriminator before the prefix. Examples of names to flag:\n\n- `PDActuator`, `VelocityActuator` → should be `ActuatorPD`, `ActuatorVelocity`\n- `SphereShape`, `CapsuleShape` → should be `ShapeSphere`, `ShapeCapsule`\n- `add_sphere_shape()`, `add_mesh_shape()` → should be `add_shape_sphere()`, `add_shape_mesh()`\n\nBefore flagging, cross-check against existing sibling symbols in the same module. If the rest of the module uses `Foo<Kind>` rather than `<Kind>Foo`, the new symbol should match the established pattern whichever direction it goes. Prefer consistency over a mechanical reading of the rule when the module has an entrenched local convention; call out the exception to `CODING_GUIDELINES.rst` explicitly.\n\n## Judgment philosophy\n\n**Err on \"mention, don't block\"**: flagging should raise a question for human review, not gate the report. The audit appendix shows flagged entries and a one-line reason; a human decides.\n\n**Don't auto-rewrite**: The audit flags the entry, never modifies it. Before the\nTowncrier build, the release manager updates pending fragments during changelog\nmaintenance; after release, corrections to dated history require explicit\nmaintainer approval.\n\n**Prefer false positives over false negatives**: a flag that turns out to be fine costs a 5-second eyeball. A missed wrong-ref or jargon-leak ships to users.\n\n**Exception for 🚨 policy flags.** The `🚨 Policy: removed without prior deprecation` flag (Phase 4d) is NOT a false-positive-tolerant flag. Only raise it after both an exhaustive search of prior released CHANGELOG sections and a targeted code search at the base ref fail to find deprecation evidence. A matching runtime `DeprecationWarning` satisfies the deprecation-window policy even when the CHANGELOG entry was forgotten; flag that case as `🧾 Deprecation omitted from CHANGELOG` instead.\n\n## Row format (for the report)\n\n| Entry (excerpt) | Flag | Why |\n|---|---|---|\n| \"Inline a `wp.vec3`-specialized ...\" | 🗣️ Internal language | References `warp.fem.geometry.closest_point` in user-facing prose |\n| \"Fix crash\" | 📝 Too terse | 2 words, no context link |\n| \"Add `newton.foo.bar` (GH-NNNN)\" | 🔗 Wrong ref? | Commits tagged GH-NNNN touch only CI files |\n| \"Deprecate `Model.foo`\" | ⬆️ Missing migration guidance | No \"in favor of\" replacement named |\n| \"Add `PDActuator`\" | 🏷️ Naming-convention drift | Should be `ActuatorPD` per prefix-first rule |\n| \"Add `newton.utils._x`\" | 🕵️ Private-only | Named symbol lives only in `newton._src`, not re-exported |\n| \"Remove deprecated `Model.foo`\" | 🧾 Deprecation omitted from CHANGELOG | Runtime warning exists at the base ref, but no released Deprecated entry records it |\n\nEntry excerpt should be ~60-80 chars so the table stays scannable. Keep the full entry text in the detail sections (never truncate there).\n","isInternal":false,"tokens":2258,"sizeBytes":9399},{"name":"render-rules.md","path":".agents/skills/release-audit/references/render-rules.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-audit/references/render-rules.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Rendering Rules\n\nThis reference is loaded during Phase 7b of the release-audit skill. It defines the hard constraints and conventions for how the report is formatted when the template is filled in. Phase-flow logic lives in `SKILL.md`; this file is pure reference material.\n\n## Key rendering rules\n\n- Full commit URLs: `https://github.com/newton-physics/newton/commit/<full-sha>`.\n- Full issue URLs: `https://github.com/newton-physics/newton/issues/<num>`.\n- Preserve `diff` fence blocks for signature diffs.\n- Anomaly banner appears ONLY if any commit has `main_equivalent_sha: null`.\n- **Table of contents** sits immediately after the Release Highlights section (so the front matter reads: scope → version control → counts → bake → highlights → TOC → body). Link every top-level `##` section and every per-symbol / per-topic `###` heading under them.\n- **Document Version Control** appears near the top after the report scope metadata. For gist revisions, summarize the immediately preceding revision's audited head and commit count, list only materially changed report sections, and direct prior reviewers to those sections. Keep the report body current by replacing superseded conclusions rather than retaining them as history. For first publication, label it as the initial report. Include the section in the table of contents.\n- **Behavioral & Support Changes** section: group by topic with short descriptive titles (e.g., \"Deterministic contact ordering\", \"Dependency pins\", \"Build requirements\"). The audit synthesizes the titles from the entry content.\n- **Dependency & License Audit** section: render immediately after Behavioral & Support Changes and before Fixed. Use one complete `scripts/license_audit.py` output as-is except for global output-style cleanup. Never combine tables from a `--skip-pypi` run with prose from a separate live query. If a live host-side run succeeds, it replaces the entire deferred result. Keep uncertainty text such as \"not checked\", \"not evaluated (--skip-pypi)\", or \"not declared\"; do not replace it with guessed license metadata.\n- **Existing resolved package license cells stay concise.** Preserve standard license expressions and review statuses emitted by the helper. For legacy or verbose nonstandard values, keep the helper's package-metadata link instead of copying full license text into the report.\n- **Existing resolved package changes stay collapsed.** Keep the Existing Resolved Package Version-Set Changes table inside the helper's closed GFM `<details>` block. Leave the subsection heading and row-count summary visible, but do not add the `open` attribute; readers expand the long table only when needed.\n- **Experimental is a neutral stability label.** Never attach a warning emoji merely because an API is experimental. In Breaking Changes, use `Experimental:` without an emoji. Reserve `⚠️` for stable API or behavior changes that need an explicit acceptability review, and `🚨` for policy violations. The mixed Breaking Changes section heading itself has no warning emoji.\n- **Release highlights are significance-gated.** Keep 3-6 release-defining capabilities, workflows, broad behavioral shifts, or material compatibility decisions. Breaking or experimental status alone is not enough; omit routine deprecation cleanup, narrow signature changes, and minor dependency metadata follow-ups from highlights.\n\n## Output style — hard constraints on the generated report\n\n1. **No em dashes (`—`) anywhere in the report output.** Use colons, parentheses, or rewrite the sentence. This includes headings, bullet points, table cells, prose. Check every line before writing.\n\n2. **No internal skill terminology in the output.** The reader does not know what \"Phase 4f\", \"Phase 5a\", \"tier-1 heuristic\", or similar skill-internal names refer to. If a section needs explanation of how flags were produced, write it in plain user terms (e.g., \"Flagged because commits tagged with this GH ref don't touch any solver code\" instead of \"Tier-1 topic mismatch from Phase 5a\").\n\n3. **No mention of previously-shipped patch-release fixes.** The commit-list tool already scopes to `<base>..<head>`, so patch-release content is excluded automatically; do not manufacture a comparison to it.\n\n4. **No \"end of report\" or similar terminal markers.** The last section is the last section. No \"— end —\", no \"Thanks for reading\", no concluding paragraph, no closing quote.\n\n5. **Every GH ref is a markdown hyperlink** to `https://github.com/newton-physics/newton/issues/NNNN`. Plain-text `GH-NNNN` tokens, paren-grouped lists like `(GH-1287, GH-1298, ...)`, and shorthand like `(multiple GHs)` / `(see CHANGELOG)` are NOT acceptable, even when many refs bunch into one bullet or cell.\n\n6. **Signature and docstring render as a single fenced code block**, shaped like Python source so users see them in one glance. The exact shape depends on the kind of symbol.\n\n   **Functions and methods:**\n\n   ```python\n   newton.geometry.compute_offset_mesh(shape: ShapeFlags, offset: float) -> Mesh\n   \"\"\"Extract the offset surface mesh of a collision shape.\n\n   Longer description if present in the real docstring.\n   \"\"\"\n   ```\n\n   **Classes with only a constructor** (simple data holders or context managers):\n\n   ```python\n   class TetMesh:\n       \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n       Longer description if present.\n       \"\"\"\n\n       def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n   ```\n\n   **Classes with additional public methods**: list EVERY public (non-dunder, non-leading-underscore) method with its signature, plus the class docstring and each method's docstring if present. Do not just show `__init__`.\n\n   ```python\n   class SolverXPBD:\n       \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n       Short description of the solver's scope and typical use.\n       \"\"\"\n\n       def __init__(self, model: Model, iterations: int = 10)\n\n       def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n       \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n       def update_contacts(self, contacts: Contacts) -> None\n       \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n   ```\n\n   **Enum / IntEnum / IntFlag classes:** list every member with its integer value and its attribute docstring or comment, plus the class docstring. Do not show a constructor for enums.\n\n   ```python\n   class ShapeFlags(IntFlag):\n       \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n       VISIBLE = 1 << 0\n       \"\"\"Shape is rendered by viewers.\"\"\"\n\n       COLLIDE_SHAPES = 1 << 1\n       \"\"\"Shape participates in shape-shape collision.\"\"\"\n   ```\n\n   Extract member docstrings from the source using `ast` attribute-docstring form (`\"\"\"...\"\"\"` immediately following the assignment). If the member uses a `#:` comment or a trailing `#` comment, preserve that instead. If there is no per-member doc, show the member without one.\n\n   Do NOT separate \"Signature\" and \"Docstring\" into two headed subsections. Do NOT blockquote the docstring line by line; it lives inside the code block as Python source.\n\n7. **API summary tables** include a Description column AND a short-form signature in the Symbol cell. The Symbol cell shows the call shape WITHOUT type annotations so readers can skim the args at a glance. Defaults ARE included. The column order for New API tables is: `Symbol | Description | GH | Bake`. Examples of Symbol cells:\n\n   - Function: `newton.geometry.compute_offset_mesh(shape, offset)`\n   - Method: `SolverXPBD.update_contacts(contacts)`\n   - Class with constructor: `newton.TetMesh(vertices, tets)`\n   - Enum / flag (no call form): `newton.ShapeFlags`\n   - Decorator: `@newton.experimental`\n\n   Description is a short (≤ 10 word) phrase summarizing what the symbol does, pulled from the first sentence of its docstring or the CHANGELOG entry.\n\n8. **New API tables are grouped by Kind.** Render one table per Kind (\"Functions\", \"Classes\", \"Methods on existing classes\", \"Enums / flags\", \"Examples\"). Newton's \"Examples\" kind specifically covers additions under `newton/examples/**` that ship a user-runnable `python -m newton.examples <name>` entry.\n\n9. **Changes-to-Existing-API table columns**: `API | Kind | Breaking | Description | GH | Commits | Bake`. The API cell uses the same short-form call-shape convention as rule 7 (parameter names + defaults, no annotations). Description is a short phrase. Kind values include: `signature change`, `new parameter`, `capability extension`, `rename` (Newton-specific), `parameter reorder` (Newton-specific), `removed`, `deprecated`, `semantic change`. For any entry tagged experimental in Phase 4g, the Breaking cell reads `Experimental`. For any Removed entry, the Description also includes the deprecation-window fact from Phase 4d, using either the released CHANGELOG version (for example, \"Deprecated in 1.0.0; removed here.\") or the base-ref runtime-warning evidence.\n\n   **Bake-cell format (tables only).** Render the Bake column as `🟢 47d`, `🟡 12d`, `🟠 4d` — emoji, space, number-and-`d` joined with no intervening space. The joined `<N>d` form keeps the bucket/duration pair on one line when a narrow Markdown table wraps. For per-symbol detail blocks and prose, continue to spell out `🟢 47 days in main`; the compact form is for table cells only.\n\n10. **Audit appendix rendering is conditional.** If only one of the audit sections (CHANGELOG-orphan entries / language-review flags / Phase 4f semantic-review candidates) has any content, do not render an \"Audit Appendix\" umbrella heading. Just render the non-empty sections with their own top-level headings (e.g., `## CHANGELOG Review Notes`, `## Semantic-Change Review Candidates`). Only use an umbrella when two or more subsections are non-empty.\n\n11. **No Phase names anywhere.** If the report needs to explain a flag, write it in user-facing terms. Never write \"Phase 4e\", \"Phase 5\", etc.\n\n12. **Dependency/license section is always rendered.** If there are no package-name changes or in-tree notice changes, keep the helper's no-change sentence. Do not drop the section, because release managers use it as evidence that the audit ran.\n","isInternal":false,"tokens":2260,"sizeBytes":10255},{"name":"report-template.md","path":".agents/skills/release-audit/references/report-template.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-audit/references/report-template.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Newton {{VERSION_STRING}} {{REPORT_KIND}} Report\nGenerated: {{REPORT_DATE}}\n\n<!-- {{REPORT_KIND}} is \"Pre-Release\", \"Release Candidate\", or \"Retrospective\",\n     chosen in Phase 1 from the argument, version string, and head ref.\n     {{VERSION_STRING}} is the raw version (e.g. \"1.2.0.dev0\" for pre-release,\n     \"1.2.0rc1\" for RC, \"1.1.0\" for retrospective). -->\n\n- Mode: {{MODE_DESCRIPTION}}\n- Head: {{HEAD_REF}} @ `{{HEAD_SHA_SHORT}}`\n- Base: {{BASE_REF}} @ `{{BASE_SHA_SHORT}}`\n- Commits in range: {{N_COMMITS}}\n\n<!-- {{MODE_DESCRIPTION}} is a one-liner:\n     Pre-release: \"Pre-release audit of unreleased work on main\"\n     RC: \"Release candidate readiness review (release branch cut)\"\n     Retrospective: \"Retrospective audit of shipped release v<version>; calibration\n                     pass cross-references the audit's flags against post-target history\" -->\n\n## Document Version Control\n\n{{DOCUMENT_VERSION_CONTROL}}\n\n<!-- Keep this section short and reviewer-oriented.\n\n     For a first publication, state that this is the initial report and name the\n     audited head and commit count.\n\n     For a revised gist, compare the prior report's audited head and commit count\n     with the current values, then list only the report sections whose conclusions\n     materially changed. Tell prior reviewers where to focus. End by stating that\n     every other finding was revalidated and that the report body contains only\n     current conclusions rather than retaining superseded text.\n\n     Do not use this section as a historical changelog. Gist history preserves old\n     revisions; this section is a compact review map for the immediately preceding\n     revision. -->\n\n\n**Headline counts**\n\n- {{N_NEW_API}} new public APIs\n- {{N_BREAKING}} breaking changes\n- {{N_CHANGED}} changes to existing API\n- {{N_BEHAVIORAL}} behavioral / support changes\n- {{N_FIXED}} fixes\n- {{N_EXAMPLES}} new examples\n\n**Bake distribution**\n\n| Bucket | Commits |\n|---|---:|\n| 🟢 > 14 days in main | {{N_BAKE_GREEN}} |\n| 🟡 7 to 14 days | {{N_BAKE_YELLOW}} |\n| 🟠 < 7 days | {{N_BAKE_ORANGE}} |\n\n{{ANOMALY_BANNER_IF_ANY}}\n\n<!-- Anomaly banner appears ONLY when any commit has main_equivalent_sha: null. Example:\n     > ⚠️ **N commits in the release have no equivalent on main. Investigate: these\n     > shipped without nightly/main-branch bake.**\n-->\n\n---\n\n## Release highlights\n\n{{HEADLINE_SUMMARY}}\n\n<!-- The audit's qualitative synthesis of what would land in the official release\n     notes. Drafted in Phase 7a. NOT release notes: a reviewer's preview so the\n     release manager can see at a glance whether the real release notes will\n     match expectations and spot items that need a keep/defer decision.\n\n     Shape: one short intro paragraph (2-3 sentences) followed by 3-6 bulleted\n     highlight items. Each bullet starts with a bold 2-6 word headline, then a\n     colon and a one-sentence rationale (what it is and why it matters).\n\n     Include status/risk markers inline only when they apply:\n       - 🟠 `N days` bake (if the headline item's minimum bake is < 7 days)\n       - Experimental (neutral label, no warning emoji, and only when the item\n         independently clears the significance bar)\n       - ⚠️ Stable change (a non-experimental API or behavior change that needs\n         a deeper release-manager acceptability decision)\n\n     Do NOT include counts (\"4 new APIs were added\"): that's already in the\n     headline counts block above. Highlights are qualitative.\n     Do NOT promote an item only because it is breaking or experimental. Routine\n     compatibility removals after a valid deprecation window, narrow signature\n     shifts, and dependency metadata follow-ups belong in the detailed sections.\n\n     Example shape (do NOT copy verbatim; pick items that are actually headline\n     material in THIS release):\n\n     Newton 1.2 lands Gaussian splat geometry, deterministic contact ordering, and\n     a new texture-based SDF pipeline that replaces NanoVDB for mesh-mesh collision.\n     One stable default change needs an explicit acceptability decision before cut.\n\n     - **Gaussian splat geometry** ([GH-NNN](...)): `Gaussian`, `ModelBuilder.add_shape_gaussian()`,\n       and USD import unlock radiance-field-style rendering as a first-class shape.\n       🟢 30 days bake.\n     - **Deterministic contact ordering** ([GH-NNN](...)): `deterministic` flag on\n       `CollisionPipeline` and `NarrowPhase` makes contact output GPU-thread-schedule\n       independent via radix sort and fingerprint tiebreaking. Required for reproducible\n       RL training. 🟢 22 days bake.\n     - **Texture-based mesh SDF** ([GH-NNN](...), [GH-NNN](...)): replaces NanoVDB\n       volumes in the mesh-mesh collision pipeline; faster and CPU-compatible. Every\n       GH ref is an individual hyperlink; never collapse to \"(multiple GHs)\" or a\n       plain-text comma list.\n     - **⚠️ Stable change: particle contacts enabled by default** ([GH-NNN](...)):\n       existing scenes can change trajectories, so the release manager should confirm\n       the new default and preservation path are acceptable.\n     - **Experimental: differentiable rigid contacts** ([GH-NNN](...)): gradients\n       with respect to body poses via `CollisionPipeline` when `requires_grad=True`;\n       contact-pipeline API may change in 1.3.\n     - **RJ45 plug-socket insertion example**: demonstrates SDF contacts, latch joint,\n       and interactive gizmo; release notes should lead with the showcase.\n-->\n\n---\n\n## Contents\n\n{{CONTENTS_BULLETS}}\n\n<!--\nExpand the TOC to include every `###` heading rendered in the body, not\njust the `##` top-level sections. List each per-symbol / per-topic heading\nas a sub-bullet under its parent section. Example shape (replace with the\nreal symbols / topics present in this specific report):\n\n- [Document Version Control](#document-version-control)\n- [New API](#new-api)\n  - [`newton.<symbol>`](#newtonsymbol)\n  - [`newton.<submodule>.<symbol>`](#newtonsubmodulesymbol)\n  - ...\n- [Breaking Changes](#breaking-changes)\n  - per-entry heading as sub-bullet\n- [Changes to Existing API](#changes-to-existing-api)\n  - per-entry heading as sub-bullet\n- [Behavioral & Support Changes](#behavioral--support-changes)\n  - per-topic heading as sub-bullet\n- [Dependency & License Audit](#dependency--license-audit)\n- [Schema & Importer Support](#schema--importer-support)\n- [Fixed](#fixed)\n- [Calibration Notes](#calibration-notes) (retrospective mode only)\n  - per-flag-class sub-bullet\n- [CHANGELOG Review Notes](#changelog-review-notes) (only if the conditional\n  appendix renders content)\n\nThe sample symbol names above are illustrative placeholders; do NOT ship them\nas-is. GitHub auto-renders a floating outline panel, but an explicit TOC\nstill helps raw-text readers.\n-->\n\n---\n\n## New API\n\n{{NEW_API_TABLES_BY_KIND}}\n\n<!-- Render one summary table per Kind. Columns: Symbol | Description | GH | Bake.\n     Kind groupings for Newton: \"Functions\", \"Classes\", \"Methods on existing classes\",\n     \"Enums / flags\", \"Constants\", \"Examples\". If only one Kind has entries, one\n     table is fine.\n\n     The Symbol cell uses a short-form call shape (no type annotations; defaults\n     included). Examples:\n     - `newton.geometry.compute_offset_mesh(shape, offset)`\n     - `newton.TetMesh(vertices, tets)`\n     - `SolverXPBD.update_contacts(contacts)`  (method on existing class)\n     - `newton.ShapeFlags`  (no parens for enums, decorators)\n     - `newton.examples.basic_pendulum`  (example module; the Symbol cell links to\n       the runnable name `python -m newton.examples basic_pendulum`). -->\n\n{{NEW_API_DETAIL_BLOCKS}}\n\n<!-- Per-symbol block template. Headings use the symbol name alone (no colons/em dashes).\n     The single fenced code block underneath holds signature-shaped content and\n     the docstring.\n\nSimple data class (constructor-only rendering):\n\n### `newton.TetMesh`\n\nLinks: [GH-NNN](...), commits: [abc1234](...), [def5678](...)\nSource: `newton/_src/geometry/tetmesh.py`\nBake: 🟢 47 days in main\n\n```python\nclass TetMesh:\n    \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n    Holds per-vertex positions and per-tet index quads; builders accept this\n    shape via ModelBuilder.add_shape_tetmesh.\n    \"\"\"\n\n    def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n```\n\nClass with multiple public methods (interface-style): list every public method\nwith its signature and docstring, not just __init__.\n\n### `newton.solvers.SolverXPBD`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 30 days in main\n\n```python\nclass SolverXPBD:\n    \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n    Supports rigid bodies, particles, cloth, and soft-body elements with a\n    common substepping loop.\n    \"\"\"\n\n    def __init__(self, model: Model, iterations: int = 10)\n\n    def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n    \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n    def update_contacts(self, contacts: Contacts) -> None\n    \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n```\n\nEnum / IntFlag: list every member with its value and per-member doc.\n\n### `newton.ShapeFlags`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/geometry/flags.py`\nBake: 🟡 12 days in main\n\n```python\nclass ShapeFlags(IntFlag):\n    \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n    VISIBLE = 1 << 0\n    \"\"\"Shape is rendered by viewers.\"\"\"\n\n    COLLIDE_SHAPES = 1 << 1\n    \"\"\"Shape participates in shape-shape collision.\"\"\"\n\n    COLLIDE_GROUND = 1 << 2\n    \"\"\"Shape participates in ground-plane collision.\"\"\"\n```\n\nMethod added to an existing class: the heading names the fully-qualified\nmethod path. The fenced block shows only that method, not the whole class.\n\n### `newton.solvers.SolverXPBD.update_contacts`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 21 days in main\n\n```python\ndef update_contacts(self, contacts: Contacts) -> None\n\"\"\"Populate contacts.force with per-contact spatial forces.\n\nDerives linear force and torque [N, N·m] from XPBD constraint impulses\naccumulated during the most recent step. Call after step().\n\"\"\"\n```\n\nExample (runnable under `python -m newton.examples <name>`): the Source cell\npoints to the example module; list the one-liner user invocation and the\nheadline simulation topic.\n\n### `newton.examples.robot.example_robot_humanoid`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/examples/robot/example_robot_humanoid.py`\nBake: 🟢 19 days in main\n\nRun:\n\n```\npython -m newton.examples example_robot_humanoid\n```\n\nShort paragraph explaining what the example demonstrates (the solver used,\nwhat the user will see, any dependencies like MuJoCo assets).\n-->\n\n---\n\n## Breaking Changes\n\n{{BREAKING_ENTRIES}}\n\n<!-- Flat list. Do NOT group under \"Author-labeled\" / \"Unlabeled\" / \"Semantic\"\n     subheadings. Every entry is simply a confirmed breaking change, regardless\n     of how it was identified. The audit collects entries from four sources:\n     (1) CHANGELOG Changed entries whose prose describes a rename / parameter\n         reorder / signature shift (Newton does not use a **Breaking:** marker;\n         recognition is prose-based),\n     (2) CHANGELOG Removed entries (implicitly breaking; flag as 🚨 Policy only\n         if neither a prior Deprecated entry nor a matching runtime warning at\n         the base ref is found),\n     (3) public-surface AST diffs between base and HEAD that aren't covered by\n         a CHANGELOG Changed / Removed entry,\n     (4) solver / integrator / math / geometry commits whose diff the audit reads\n         as clearly semantic-shifting (a numerical-output shift that a user\n         would observe). Ambiguous candidates go to \"Semantic-Change Review\n         Candidates\" in the review notes, NOT here.\n\n     Warning semantics:\n     - Prefix a non-experimental entry heading with `⚠️` when the stable API or\n       behavior change needs a deeper acceptability decision (for example, a\n       changed default, output semantics, or unshimmed signature shift).\n     - Prefix experimental entry headings with `Experimental:` and no warning\n       emoji. Their looser compatibility contract is context, not an alarm.\n     - Planned removals after a valid shipped deprecation window need no warning\n       emoji unless their breadth or remaining migration risk warrants review.\n     - Keep `🚨 Policy` for removals with no prior deprecation evidence.\n\n     Per-entry render format:\n\n     ### <heading: symbol name or short descriptive title>\n\n     Links: [GH-NNN](...), commit(s): [sha](...). 🟢 N days baked in main.\n\n     [If signature diff applies, a fenced diff block.]\n     [If behavior shift, a before/after code snippet synthesized from the diff\n      and the commit message.]\n\n     [1-3 sentences of explanatory prose in plain user-facing language.]\n\n     [Full CHANGELOG text blockquoted, if the entry came from CHANGELOG.]\n\n     [For removals backed only by a runtime warning at the base ref: a one-line\n      deprecation-window note plus a non-blocking CHANGELOG documentation flag.]\n\n     [For 🚨 Policy: removed without prior deprecation entries: a one-line\n      callout stating that neither released CHANGELOG nor base-ref code contains\n      deprecation evidence and what the release manager should do about it.]\n\n     Illustrative example (do not copy verbatim):\n\n     ### `ModelBuilder.add_shape_gaussian` parameter reorder\n\n     Links: [GH-NNN](https://github.com/newton-physics/newton/issues/NNN),\n     commit: [abc1234](https://github.com/newton-physics/newton/commit/abc1234). 🟢 22 days baked in main.\n\n     The `xform` argument now precedes `gaussian` to match every other\n     `add_shape_*` method on `ModelBuilder`. Callers that relied on positional\n     arguments must switch to keyword form. Passing a `Gaussian` as the second\n     positional argument still works but emits a `DeprecationWarning`.\n\n     Before:\n     ```python\n     builder.add_shape_gaussian(body_idx, gaussian, xform=my_xform)\n     ```\n\n     After:\n     ```python\n     builder.add_shape_gaussian(body_idx, xform=my_xform, gaussian=gaussian)\n     ```\n-->\n\n---\n\n## Changes to Existing API\n\n<!-- Covers CHANGELOG Changed, Removed, Deprecated, plus capability extensions\n     routed here from the new-API classification pass (e.g., \"Add support for X\n     in existing Y\"). -->\n\n{{CHANGED_SUMMARY_TABLE}}\n\n<!-- Columns: API | Kind | Breaking | Description | GH | Commits | Bake\n     Kind values: signature change, new parameter, capability extension, rename,\n     parameter reorder, removed, deprecated, semantic change. Description is a\n     short phrase (≤ 10 words). Breaking cell values: Yes / No / Experimental. -->\n\n{{CHANGED_DETAIL_BLOCKS}}\n\n<!-- Per-entry template (signature change). Use a colon in the heading, not an em dash.\n\n### `SolverMuJoCo`: new `enable_multiccd` parameter\n\nBreaking: **No** (additive keyword-only default)\nLinks: [GH-NNN](...), commit: [5c5f67e9](...)\nBake: 🟢 38 days in main\n\n```diff\n- def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True)\n+ def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True, enable_multiccd: bool = False)\n```\n\n**From CHANGELOG**\n> Add `enable_multiccd` parameter to `SolverMuJoCo` for multi-CCD contact generation\n> (up to 4 contact points per geom pair).\n\nCapability extension (existing API gains a new option/behavior):\n\n### `ModelBuilder.add_shape_*`: per-shape color\n\nLinks: [GH-NNN](...), commit: [abcdef12](...)\nBake: 🟢 35 days in main\n\nEvery `add_shape_*` method gains a `color=` keyword argument; `Model.shape_color`\nholds the authored per-shape display color for runtime edits; mesh shapes fall\nback to `Mesh.color` when available.\n\n```diff\n- def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True)\n+ def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True, color: Vec3 | None = None)\n```\n\n**From CHANGELOG**\n> <full CHANGELOG text blockquoted>\n\nRename (Newton-specific kind, soft deprecation via DeprecationWarning):\n\n### `ModelBuilder.add_shape_ellipsoid`: parameter rename\n\nBreaking: **Yes** (source break if old names used positionally)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 28 days in main\n\n```diff\n- def add_shape_ellipsoid(self, body: int, a: float, b: float, c: float, ...)\n+ def add_shape_ellipsoid(self, body: int, rx: float, ry: float, rz: float, ...)\n```\n\nOld names `a`, `b`, `c` are still accepted as keyword arguments but emit a\n`DeprecationWarning`. Positional callers must switch to keyword form.\n\n**From CHANGELOG**\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`.\n> Old names are still accepted as keyword arguments but emit a `DeprecationWarning`.\n\nRemoved symbol:\n\n### `Model.geo_meshes`: removed\n\nLinks: [GH-NNN](...), commit: [sha](...)\nDeprecation window: Deprecated in 1.0.0; removed here.\n\n```diff\n- geo_meshes: list[Mesh]\n```\n\n**From CHANGELOG (prior deprecation in 1.0.0)**\n> Deprecate `Model.geo_meshes` in favor of `Model.shapes`. Will be removed in a\n> future release.\n\n**From CHANGELOG (removal)**\n> <full CHANGELOG text blockquoted>\n\nExperimental-softened entry (symbol was shipped as experimental in a prior release; change here is technically source-breaking but the stability bar was advertised up front):\n\n### `SensorTiledCamera`: RenderContext reorganization\n\nBreaking: **Experimental** (since 1.0.0)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 40 days in main\n\n`SensorTiledCamera` landed as an experimental sensor in 1.0.0; this release\nsplits `RenderContext` into `RenderConfig` (config types) and `utils` (runtime\naccess), deprecates the old names, and adjusts default Gaussian sorting modes.\n\n```diff\n- class SensorTiledCamera:\n-     render_context: RenderContext\n+ class SensorTiledCamera:\n+     render_config: RenderConfig\n+     utils: SensorTiledCameraUtils\n```\n\n**From CHANGELOG (1.0.0 introduction, still experimental)**\n> Add `SensorTiledCamera` (experimental): GPU-tiled camera sensor for multi-agent RL.\n\n**From CHANGELOG (this release)**\n> <full CHANGELOG text blockquoted>\n-->\n\n---\n\n## Behavioral & Support Changes\n\n<!-- Group by topic with short descriptive section headings synthesized from\n     the entry content. Use colons in headings if separation is needed.\n     Related topics should live together.\n\n     Example headings (illustrative, choose based on actual content):\n     - \"Python minimum version bumped\"\n     - \"MuJoCo / mujoco-warp dependency pins\"\n     - \"Deterministic contact ordering\"\n     - \"USD import: visibility honored\"\n     - \"Mesh SDF construction: parity path\"\n     - \"Asset pinning for reproducible builds\"\n\n     Each topic: a short paragraph summary, links, commits, bake. -->\n\n{{BEHAVIORAL_SECTIONS}}\n\n---\n\n## Dependency & License Audit\n\n{{DEPENDENCY_LICENSE_AUDIT}}\n\n<!-- Render the markdown emitted by scripts/license_audit.py. This section is\n     always present. It compares direct dependencies, resolved lockfile package\n     names, version changes, and declared license-file pathspecs across the\n     release range. Use one complete helper result; never combine a\n     `--skip-pypi` table with prose from a separate live query. Preserve \"not\n     checked\", \"not evaluated (--skip-pypi)\", and \"not declared\" license\n     metadata exactly when package-index lookup was unavailable, deferred, or\n     inconclusive. Keep the helper's Existing Resolved Package Version-Set\n     Changes table inside its closed `<details>` block so the long table is\n     collapsed by default. -->\n\n---\n\n## Schema & Importer Support\n\n{{SCHEMA_IMPORTER_SUPPORT}}\n\n<!-- Render the Phase 4h table, or state that no relevant features were found. -->\n\n---\n\n## Fixed\n\n{{FIXED_TABLE}}\n\n<!-- Columns: Fix | GH | Commits | Bake\n     Keep the full CHANGELOG text in the Fix column; no truncation.\n     Do NOT mention fixes from previously-shipped patch releases. The commit-list\n     tool scopes to <base>..<head> so those are already excluded. -->\n\n{{CALIBRATION_NOTES}}\n\n<!-- Retrospective mode only. Pre-release / RC mode must leave\n     {{CALIBRATION_NOTES}} empty (template consumers should strip the whole\n     placeholder line, not leave a stray section heading).\n\n     Retrospective mode renders a ## Calibration Notes section here, immediately\n     after Fixed and before the optional audit appendix. Shape:\n\n     ## Calibration Notes\n\n     One-paragraph headline: overall validated / invalidated / unresolved counts\n     across all flag classes, plus a one-sentence takeaway on what the calibration\n     suggests about skill precision for this release.\n\n     ### 🚨 Missing-deprecation\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `Model.foo` | Validated | No prior Deprecated entry or matching runtime warning at the base ref; symbol stayed removed through 1.1.2. |\n     | `Model.bar` | Invalidated | Deprecated in 1.0.0 under `### Deprecated` — the audit's search missed it (lowercase `model.bar` in the entry). |\n\n     ### 🕵️ Private-only\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `newton._src.utils._helper` | Validated | Re-exported as `newton.utils.helper` in [1.1.1](commit-link). |\n\n     ### ⬆️ Missing-migration-guidance\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### 🏷️ Naming-convention drift\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### Semantic-change review candidates\n\n     | File / feature | Outcome | Evidence |\n     |---|---|---|\n     | `newton/_src/solvers/xpbd.py` contact-ordering diff | Validated | [1.1.1](commit-link) fixes \"convergence regression on stacked bodies\" — consistent with the flagged change's hypothesis. |\n\n     ### Deprecation follow-through\n\n     | Deprecated in this release | Followed through | Evidence |\n     |---|---|---|\n     | `Model.geo_meshes` | Followed through in 1.2.0 | Removed entry cites `Use Model.shapes`; matches the promised migration path. |\n     | `SensorContact.net_force` | Still deprecated | Symbol remains in the public surface through 1.2.1 with DeprecationWarning. |\n\n     Closing note (one or two sentences): what the calibration tells the reader\n     about Newton's release hygiene for this specific release.\n-->\n\n---\n\n{{OPTIONAL_APPENDIX}}\n\n<!-- Render conditionally based on content and wrap each non-empty section in\n     a GFM <details> block so it collapses by default (the umbrella content is\n     reference material, not headline reading).\n\n     Three cases:\n\n     1. Both CHANGELOG-orphan list AND language-review flags are empty:\n        Render nothing. No appendix heading, no trailing section.\n\n     2. Exactly ONE is non-empty: Render that one as a top-level section\n        (no \"Audit Appendix\" umbrella) with the table inside <details>.\n\n        ## CHANGELOG Entries Without Matching Commits\n        <details>\n        <summary>N entries (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        | full entry text | ... | ... |\n\n        </details>\n\n     3. Both are non-empty: Render an umbrella section; each subsection gets\n        its own <details>.\n\n        ## Audit Appendix\n\n        <details>\n        <summary>N CHANGELOG entries without matching commits (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        ...\n\n        </details>\n\n        <details>\n        <summary>N CHANGELOG entries flagged for review (click to expand)</summary>\n\n        | Entry | Flag | Why |\n        |---|---|---|\n        ...\n\n        </details>\n\n     Column rules for BOTH tables: full entry text (no truncation).\n     Flag glyphs: 🔗 (suspected wrong GH ref), 🗣️ (internal language),\n                  📝 (too terse or missing context),\n                  🕵️ (private-only symbol not re-exported through a public module),\n                  ⬆️ (Deprecated / Removed / rename entry missing migration guidance),\n                  🏷️ (new public symbol violates Newton's prefix-first naming),\n                  🧾 (runtime deprecation shipped but the released CHANGELOG omitted it),\n                  🚨 (removed without prior CHANGELOG or runtime deprecation evidence;\n                      policy violation surfaced in Breaking Changes and listed here\n                      for auditability).\n     An entry with multiple flags appears once per flag. -->\n\n<!-- Report ends here. Do NOT append \"end of report\", a closing quote, a thanks\n     note, or any terminal marker. -->\n","isInternal":false,"tokens":5909,"sizeBytes":24704},{"name":"SKILL.md","path":".agents/skills/release-audit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-audit/SKILL.md","title":"release-audit","category":"anthropic-skill","format":"markdown","content":"---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\n---\n\n# Release Audit\n\nGenerates a markdown audit of a Newton release for keep/defer decisions (or, in retrospective mode, for skill calibration). Three modes, auto-detected in Phase 1:\n\nRead `CODING_GUIDELINES.rst` and `REVIEW_GUIDELINES.rst` from the\nrepository root before auditing. They define the canonical coding, API, and\nreview policies. This skill performs the final cross-release reconciliation;\nit does not replace pull-request review, and a prior review pass does not make\nany audit phase optional. In retrospective mode, using the current guides is\nintentional: calibrate the current audit policy against evidence pinned to the\ntarget tag. Do not claim historical noncompliance unless the requirement also\nexisted at that tag.\n\n- **Pre-release**: spot-check while work is still landing on main. No release branch cut. Version string is `X.Y.Z.devN`.\n- **Release-candidate**: readiness review after the release branch is cut. Version string is `X.Y.ZrcN` or head is `release-X.Y`.\n- **Retrospective**: audit an already-shipped release (e.g., `v1.1.0`) against its predecessor, with a Calibration Notes section (Phase 7) that checks the audit's flags against what subsequent patch/minor releases actually did. Triggered by passing a bare released-version argument that matches an existing git tag.\n\n**Output:** a single markdown report, filed according to the destination chosen in Phase 1:\n- **Secret gist** (default when `gh` is available and authenticated): stable filename `newton-<version-string>-<prerelease|rc|retrospective>-report.md`, stable description `Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report`. Later runs against the same version revise the same gist in place; prior versions are preserved in the gist's git history.\n- **Local markdown file** (fallback when `gh` unavailable, or opt-in when `gh` available): dated path at `$(git rev-parse --show-toplevel)/newton-<version-string>-<prerelease|rc|retrospective>-report-<YYYY-MM-DD>.md`. Not auto-committed; user moves, shares, or deletes as desired.\n\n**Inputs inferred from repo state:**\n- Pre-release / RC: target version from `pyproject.toml` (`version = \"...\"`). `newton/_version.py` reads from installed metadata at runtime and is not a static source.\n- Retrospective: target version from the user's argument. `pyproject.toml` is ignored.\n- Base = latest tag matching previous minor's line (`vX.Y-prev.*`, latest patch).\n- Head (pre-release / RC) = `upstream/release-<target>` if it exists, else `upstream/main`. Head (retrospective) = the `vX.Y.Z` tag itself.\n\n**Reference documents to load on demand** (via `Read`):\n- `references/report-template.md` — fill this in during Phase 7b (the `{{HEADLINE_SUMMARY}}` placeholder is drafted in Phase 7a).\n- `references/render-rules.md` — rendering conventions and output style hard constraints for Phase 7b.\n- `references/classification-rules.md` — path/symbol rules used in Phases 3-5.\n- `references/language-review-examples.md` — Phase 5 language-review calibration.\n\n## Phase 1 — Align on scope\n\n1. **Determine the mode.** Look at any target-version argument supplied with the invocation:\n\n   - **Argument present AND matches an existing tag** (`git rev-parse --verify v<arg>` or `git rev-parse --verify <arg>` succeeds, AND the resolved name looks like `vX.Y.Z` / `vX.Y.ZrcN`): **Retrospective mode**. The argument is the already-shipped target version. Skip `pyproject.toml` entirely; the tag is authoritative. Do not run the pre-release / RC reconciliation in step 4.\n   - **Argument present but does NOT match any tag**: treat as a version override for the upcoming release. Use it as if it came from `pyproject.toml`, then fall through to the pre-release / RC detection below.\n   - **No argument**: read the version string from `pyproject.toml` — the top-level `[project]` table's `version = \"...\"` line.\n\n   Normalize the selected version by removing one leading `v`, if present. Before using it in a title, filename, or path, require the normalized value to match `^[0-9]+\\.[0-9]+\\.[0-9]+(?:rc[0-9]+|\\.dev[0-9]+)?$`. If it does not match, stop and report the unsupported version. Do not construct an output path from an unvalidated version string.\n\n   Record the report date at the same time. In retrospective mode, use the target tag's creator date:\n   ```bash\n   git for-each-ref --format='%(creatordate:short)' refs/tags/v<version>\n   ```\n   This returns the tagger date for an annotated tag and the commit date for a lightweight tag. For pre-release and RC modes, use the current date (`date +%F`).\n\n   For the non-retrospective path, parse the version string to extract the target minor (e.g., `1.2.0.dev0` → target `1.2`) and pre-classify mode:\n   - If the version string contains `\"rc\"` (e.g., `1.2.0rc1`) → **RC mode candidate**: this is a release-candidate readiness report.\n   - If the version string contains `\"dev\"` (e.g., `1.2.0.dev0`) → **Pre-release mode candidate**: this is an early-stage audit of unreleased work.\n   - Otherwise → pre-release mode (default), but record the raw version string so the header can show it as-is.\n\n2. **Enumerate previous-minor tags** (applies to all modes):\n   ```bash\n   git tag --list 'v<prev-major>.<prev-minor>.*' --sort=-v:refname\n   ```\n   where `<prev-major>.<prev-minor>` is `target - 0.1` (e.g., for target `1.2`, previous minor is `1.1`). Retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`; release-candidate and other prerelease tags are not release baselines. Take the first remaining result as the base candidate. Ignore pre-1.0 `beta-*` tags when a stable `vX.Y.Z` line exists.\n\n   **Major-boundary fallback.** When `target.minor == 0` (e.g., `2.0.0`), the `target - 0.1` computation yields a minor line that never existed (`1.9`), and the tag list comes back empty. In that case, enumerate the highest minor line of the previous major instead:\n   ```bash\n   git tag --list 'v<target-major - 1>.*' --sort=-v:refname\n   ```\n   Apply the same exact stable-release filter, then take the first result (the last-patch of the last-minor of the previous major) as the base candidate. If both the primary and fallback searches return empty (which should only happen on a never-released line), surface that to the user in step 6 rather than silently proceeding.\n\n   For **retrospective mode** with target `X.Y.Z`: the base is the last `vX.Y-prev.*` tag strictly before `vX.Y.Z`. Also check whether `X.Y.Z` is itself a patch release (`.Z > 0`): if so, the \"base\" could be either the previous patch on the same minor (`vX.Y.<Z-1>`) OR the previous minor's latest. Present both in step 6 and let the user pick — a patch retrospective usually wants patch-on-patch; a minor-release retrospective wants previous-minor's last patch.\n\n3. **Probe for the head**:\n   - **Retrospective mode**: head is the `vX.Y.Z` tag directly. Resolve with `git rev-parse --verify v<target>`.\n   - **Pre-release / RC**:\n     ```bash\n     git rev-parse --verify upstream/release-<target>\n     ```\n     If this succeeds, head = `upstream/release-<target>` and this is also a strong signal for **RC mode** (the branch-cut has happened). Otherwise try `origin/release-<target>`; otherwise head = `upstream/main` (falling back to `origin/main`, then `main`) which is **pre-release mode**. Record whichever fallback was used for the report header.\n\n4. **Reconcile mode** from version string and head (skipped for retrospective mode; its mode is already fixed):\n   - Version says RC AND head is a release branch → **RC report** (strong match).\n   - Version says RC but head is main (branch not cut yet) → **RC report** (version is authoritative; note the mismatch in the header).\n   - Version says dev AND head is a release branch → **RC report** (branch cut implies we're past the dev window).\n   - Version says dev AND head is main → **Pre-release report**.\n\n5. **Probe `gh` availability and look up any existing matching gist.**\n\n   First run:\n   ```bash\n   gh --version && gh auth status\n   ```\n   If either fails → `gh` unavailable; destination will be a local markdown file only; skip the rest of this step.\n\n   Both succeeded → compute the stable gist title for this report:\n   ```text\n   Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report\n   ```\n   (e.g., `Newton 1.2.0rc1 Release Candidate Report`, `Newton 1.2.0.dev0 Pre-Release Report`, `Newton 1.1.0 Retrospective Report`). No date. The gist filename and description are stable so later runs can find the same gist and revise it; gist git history preserves prior versions automatically.\n\n   Run `gh gist list --limit 1000` and filter rows whose description exactly matches that stable title. Capture the matching gist IDs; display URLs are `https://gist.github.com/<id>`. Record the match count (0, 1, or N ≥ 2) for step 6.\n\n6. Present proposal in chat and **wait for explicit user confirmation** of refs AND output destination. Mandatory pause.\n\n   Lead with the mode-specific intro line:\n   - Pre-release: `Generating **pre-release report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>**. **<N>** commits in range.`\n   - RC: `Generating **release-candidate report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>** (release branch cut). **<N>** commits in range.`\n   - Retrospective: `Generating **retrospective report** for Newton **<version>** (already shipped). Base **<base-ref>** → Head **v<version>**. **<N>** commits in range. Calibration pass will cross-reference the audit's flags against subsequent patch / minor releases.`\n\n   For retrospective mode with a patch-target (when `.Z > 0`), also present the base choice explicitly:\n   > Base candidates for retrospective of `vX.Y.Z`:\n   > 1. `vX.Y.<Z-1>` (patch-on-patch: what changed since the previous patch on the same minor)\n   > 2. `v<prev-major>.<prev-minor>.<latest-patch>` (minor-boundary: what changed since the previous minor)\n   >\n   > Pick (1) or (2), or specify a different base.\n\n   Append the output block for the current `gh` / match state:\n\n   **`gh` unavailable:**\n   > Output: markdown file at repo root (`gh` not available). Confirm, or specify different refs?\n\n   **`gh` available, 0 matches:**\n   > Output: (a) new secret gist [default], (b) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, 1 match:**\n   > Output: (a) revise existing gist `<url>` [default], (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, N matches (N ≥ 2):**\n   > Multiple existing gists share the stable title:\n   > 1. `<url-1>` — updated `<time-1>`\n   > 2. `<url-2>` — updated `<time-2>`\n   > ...\n   >\n   > Output: (a) revise gist by number, (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   Do not run any further phase until the user confirms refs and (when `gh` is available) chooses destination. Translate the user's reply into exactly one of the destination tokens `local`, `new-gist`, `revise-gist:<id>` and record it for Phase 7c. Letters `(a)`, `(b)`, `(c)` are positional within the current branch's prompt, not global: resolve them against the option list you just showed the user. For the N-match branch, the user picks a gist by the number you listed (e.g., \"revise 2\" → `revise-gist:<id-of-listed-row-2>`), or says new / local.\n\n## Phase 2 — Gather ground truth\n\n1. Run the commit-list tool:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n     --base <base-ref> \\\n     --head <head-ref> \\\n     --report-date \"<report-date>\" \\\n     --main-ref <resolved-main-ref>\n   ```\n   from the repo root (`$(git rev-parse --show-toplevel)`). Use the date recorded in Phase 1 so retrospective bake time is measured as of the audited release rather than as of today. Capture stdout as the `commit_list_json`.\n\n2. Run the dependency and license audit helper:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py \\\n     --base <base-ref> \\\n     --head <head-ref>\n   ```\n   from the repo root. The helper requires Python 3.11+ for stdlib TOML parsing and exits with a clear preflight error on older Python versions. Capture stdout as `dependency_license_audit_md`. The helper compares:\n   - Direct requirements in `pyproject.toml`, grouped by runtime and optional extra.\n   - Resolved package names, duplicate variants, and version sets in `uv.lock` when present.\n   - `project.license` and `project.license-files` metadata in `pyproject.toml`.\n   - In-tree notice files matched by the `project.license-files` pathspecs declared at the base or head ref.\n   - Version-specific PyPI license metadata for newly introduced package names and changed locked package versions when network access is available. If metadata lookup fails, keep the helper's \"not checked\" text and surface that uncertainty rather than filling in a guessed license. If the helper was run with `--skip-pypi`, treat package-index metadata as deliberately deferred, not as per-package review failures.\n\n   Use one helper invocation as the source of the entire dependency/license section. Do not splice prose from a live metadata check onto tables produced by `--skip-pypi`. If a sandboxed or deferred run used `--skip-pypi` and a later host-side run can reach package indexes, replace the complete section with the default host-side output. Use `--skip-pypi` only as a fallback when a live metadata pass cannot be completed.\n\n   In Existing Resolved Package Version-Set Changes, the helper keeps standard license expressions and review statuses inline. Legacy or verbose nonstandard license text is rendered as a compact package-metadata link rather than copied into the report. The helper wraps this potentially long table in a closed `<details>` block; keep it collapsed by default so it does not dominate report scrolling.\n\n   The helper is intentionally stdlib-only. Do not replace it with a dependency inventory tool during the audit run: Newton avoids new release-only dependencies, and this script needs deterministic comparisons across arbitrary git refs without installing the target environment. External tools such as `pip-licenses`, `cyclonedx-py`, `pip-audit`, or `syft` can supplement a deeper investigation, but they do not replace this git-ref diff over `pyproject.toml`, `uv.lock`, declared license files, and version-specific PyPI metadata.\n\n   Interpretation rules for `dependency_license_audit_md`:\n   - A newly introduced external direct dependency or new resolved package name is license-relevant even when it lives behind an optional extra. Do not dismiss optional dependencies; state the extra or install path that pulls them in.\n   - A package that first appears in the lockfile only beneath a direct dependency already declared at the base is resolved-set churn, not a new dependency. The helper renders it in Existing Resolved Package Version-Set Changes with `(not resolved)` as the base and attributes the existing direct root. Reserve New Resolved Packages for packages introduced by a new direct dependency root or packages whose root cannot be established.\n   - A new optional extra whose dependencies are all already present is a support/install-surface change, but not a new package-license change.\n   - Existing package version bumps are not new licenses by themselves. The helper separates direct requirement moves from transitive-only churn; only elevate version bumps to release highlights or Behavioral & Support Changes when the package pin or compatibility constraint is user-visible.\n   - In-tree notice-file additions, removals, or modifications under the declared `project.license-files` pathspecs always appear in the dependency/license section. If a notice file is missing for a new bundled asset or vendored component, flag it in CHANGELOG Review Notes.\n   - If the helper reports license metadata as \"not checked\" due to lookup failure or \"not declared\" for a new package, keep that wording and mark it as needing release-manager review. Do not infer a license from package authorship or project name.\n   - If the helper reports \"not evaluated (--skip-pypi)\", say that package-index metadata was deferred and should be checked before final release sign-off. Do not turn that into a per-package review list.\n   - If a new package is proprietary, copyleft, commercial, unknown, not declared, or not checked due to lookup failure, mention that in the release highlights only when users can install it through a published extra or documented workflow.\n\n3. Load the pending or released changelog source by mode:\n   - **Pre-release / RC**: user-facing release scope is the rolling\n     `## [<target-version>]` section in `CHANGELOG.md`, when already assembled,\n     plus any later `.md` fragments on the resolved head. Before the first\n     Towncrier build, use the fragments plus legacy `[Unreleased]` entries.\n     Enumerate `changelog/*.md` with\n     `git ls-tree -r --name-only <head> -- changelog`, exclude `README.md`,\n     and read each file with `git show <head>:<path>`. Inventory `.skip` files\n     separately. Read `CHANGELOG.md` with `git show <head>:CHANGELOG.md`. If the\n     target's dated section exists, collect it through the next dated heading\n     and treat it as the assembled baseline. Otherwise, legacy entries are\n     between `<!-- towncrier release notes start -->` and the next dated `##`\n     heading.\n     If the audited head is the checked-out clean working tree, also run:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Use the draft output as the canonical preview for fragments not yet folded\n     into the rolling section; it does not modify `CHANGELOG.md` or delete\n     fragments. Audit the assembled baseline and draft additions together.\n   - **Retrospective**: read the target tag's changelog with\n     `git show v<target>:CHANGELOG.md`. Locate the `## [<target-version>]`\n     header and collect content up to the next dated `##` heading.\n\n4. Parse entries. Infer a fragment's section from its filename type (`added`,\n   `changed`, `deprecated`, `removed`, or `fixed`); the file content is one\n   entry without a leading bullet. Parse legacy or dated Markdown under the\n   corresponding five `###` headings. For every entry, extract:\n   - **Raw text (FULL — never truncate)**: the full bullet content (may span multiple lines).\n   - **Section**: one of the five names above.\n   - **Source path**: the fragment path or `CHANGELOG.md`.\n   - **Fragment identifier**: the numeric issue or leading-`+` orphan prefix\n     from the filename. Same-category counters do not change the identifier.\n   - **GH refs**: regex `GH-(\\d+)` over the bullet text. Dedup. (Newton commits and CHANGELOG entries sometimes also reference `#NNNN` as a bare PR number; capture these too.)\n   - **Migration hint**: does the prose contain a migration phrase (`use <new>`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`)? Record a boolean.\n\n   **Newton does NOT use a `**Breaking:**` literal marker in CHANGELOG** (unlike Warp). Do not rely on its presence. Breaking-change detection in Newton comes from: (a) the `### Removed` section (implicitly breaking), (b) signature-diff AST analysis (Phase 4e), and (c) reading `### Changed` prose for rename / parameter-reorder / signature-shift language (Phase 4d).\n\n## Phase 3 — Cross-reference\n\n1. **Build the commit ↔ CHANGELOG join** on GH-ref overlap:\n   - For each CHANGELOG entry with at least one GH ref, find commits (from `commit_list_json`) whose `gh_refs` intersect.\n   - For each pending fragment, find the commit that added its exact path:\n     ```bash\n     git log --reverse --diff-filter=A --format='%H|%s|%cs' \\\n       <base-ref>..<head-ref> -- changelog/<fragment-filename>\n     ```\n     Numeric identifiers link to issues, not necessarily to the implementing\n     pull request, so the fragment-addition commit is the authoritative join.\n   - For legacy entries and any fragment still lacking a backing commit, put\n     the distinctive substring in `entry_text` without interpolating it into\n     shell source, then search exact text across both storage forms:\n     ```bash\n     git log --reverse -S\"$entry_text\" \\\n       --format='%H|%s|%cs' <base-ref>..<head-ref> -- CHANGELOG.md changelog\n     ```\n     The first commit that is not a Towncrier build, synchronization, or another\n     changelog-only edit usually is the code change associated with the entry.\n     Record that as the backing commit.\n   - After these two passes, any CHANGELOG entry still with no matching commit is a genuine orphan case (deferred/dropped). Keep full entry text; do not truncate in the report.\n\n2. **Do NOT build an audit trace of unmatched commits.** The old \"commits without CHANGELOG entries\" appendix adds noise without value. Commits that don't map to a CHANGELOG entry are not surfaced in the report.\n\n## Phase 4 — Analyze API surface\n\n### 4a — Determine what is genuinely NEW API\n\nFor each CHANGELOG `Added` entry, extract the named symbol(s) — text in backticks matching `newton.*`, bare `ClassName`, bare `snake_case_name()`, or `ClassName.method()` patterns.\n\nFor EACH named symbol, check if it existed at base. Newton exposes user-facing symbols through multiple public re-export modules (not a single `__init__.py`). See `references/classification-rules.md` → \"Public API surface\" for the discovery rules. `docs/generate_api.py::api_modules()` discovers top-level public modules from module-valued names in `newton.__all__`; `solver_submodule_pages()` adds public solver module trees. There is no fixed `MODULES` constant. Inspect this discovery code plus `newton/__init__.py` and `newton/solvers.py` at both refs because the exported module set may grow or shrink between releases.\n\nTo check presence at base, run `git show <base>:<path>` for each relevant public module and grep its imported names. For method additions on an existing class (e.g., `SolverXPBD.update_contacts()`), inspect the class body at base in its real source (resolved via `_src/`). For retrospective mode, \"HEAD\" in the symbol-resolution text below means the `v<target>` tag, not the working tree. Use `git show v<target>:<path>` everywhere the pre-release / RC flow uses the working tree.\n\nClassification:\n- **Genuinely new** (symbol was not present at base) → **New API** section.\n- **Existed at base** (entry is adding a new parameter, option, or capability to something that already existed) → **Changes to Existing API** section with a \"capability extension\" or \"new parameter\" kind. Cite the backing commit's signature diff.\n- **Does not name a single symbol** (e.g., \"Interactive example browser in the GL viewer with tree-view navigation\") and describes a cross-cutting capability → **Behavioral & Support Changes** section unless one of the mentioned symbols is genuinely new (in which case split: put the new symbol in New API, the capability description in Behavioral).\n\n**If an entry mentions multiple symbols where some are new and some pre-existed** (e.g., \"Add `newton.geometry.compute_offset_mesh()` and a viewer toggle\"), split: the genuinely new symbols each get a New API entry; the extensions to existing symbols each get a Changes entry.\n\n**Public-API declaration and exposure check.** At HEAD, inspect every public\nmodule discovered by `api_modules()` and `solver_submodule_pages()`. Each module\nmust define `__all__` as a list or tuple containing only strings; a missing or\ninvalid declaration is a policy finding in \"CHANGELOG Review Notes\". For every\nsymbol that passes the \"genuinely new\" test, collect its memberships across\nthose declarations:\n\n- No memberships: report 🕵️ Private-only. The symbol exists only under\n  `newton._src.*` and was not re-exported through a public module.\n- One membership: the symbol has a canonical public import path.\n- More than one membership: report a duplicate-public-export policy finding\n  and list every public module that exports it.\n\n`CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one\npublic module's `__all__` and forbids examples/docs from importing\n`newton._src`. Do not treat the private-only finding as a hard block on the\nentry; surface it so the release manager can confirm the symbol was intended\nto be public. Treat missing or invalid declarations and duplicate exports as\npolicy findings that require an explicit release decision.\n\n### 4b — Resolve New API signatures + docstrings\n\nFor each symbol confirmed as new:\n\n1. Find its real source module by following the re-export in the public module (e.g., `newton/solvers.py` → `newton/_src/solvers/xpbd.py`).\n2. `ast.parse` the source module; find the `FunctionDef` / `ClassDef` / `AsyncFunctionDef`.\n3. Extract the signature by re-stringifying the args (preserve type annotations).\n4. Extract the docstring verbatim via `ast.get_docstring(node)`.\n5. Render as shown in the template.\n\nNewton has no kernel-scope builtins layer to extract (no `add_builtin()` registry like Warp). All user-facing symbols live in Python modules and `ast` resolves them directly.\n\n### 4c — Symbol resolution fallbacks\n\n- **Symbol in backticks doesn't resolve at HEAD**: render the entry with a ⚠️ note: \"Couldn't resolve `<symbol>` in source — verify entry names a real public symbol.\" Do not fabricate a header like `newton.*(no symbol)*`. Use the entry's natural subject as the section title.\n- **Entry describes a topic, not a symbol** (e.g., \"Interactive example browser in the GL viewer\"): use a short descriptive title summarized from the entry (e.g., \"Interactive example browser\"), not a synthetic `newton.*` name.\n- **Header naming rule**: section headers in the report should be either real fully-qualified symbols (`newton.solvers.SolverXPBD.update_contacts`) OR short descriptive titles extracted from the entry. Never `newton.*`, `newton.(something)`, or similar stub patterns.\n\n### 4d — Changed / Removed / Deprecated signature diffs\n\nFor each CHANGELOG entry in Changed / Removed / Deprecated (plus any \"capability extension\" entries routed here from 4a):\n\n- Compute signatures at base and HEAD (same resolution as 4b).\n- For signature-shape changes: render a fenced `diff` block showing `-` and `+` lines.\n- For semantic-only changes (no signature shift) where the prose describes a rename / reorder / behavioral flip: skip the diff block; include the backing commit's URL and the full CHANGELOG text.\n- For Removed entries: show the old signature on a `-` line; omit `+`.\n\n**Deprecation-window lookup for Removed entries.** Newton's policy (per `CODING_GUIDELINES.rst`) is: *breaking changes require a deprecation first*. Every Removed entry needs evidence of a deprecation in a prior release. Start with the released CHANGELOG, then fall back to code-level runtime-warning evidence at the base ref. For every Removed entry (and every Changed entry whose prose describes a removal), search CHANGELOG.md for the matching prior Deprecated entry:\n\n1. Extract distinctive tokens from the Removed entry: the named symbol(s) in backticks and, if the entry carries a GH ref, that ref number.\n2. Scan the appropriate released-version sections of CHANGELOG.md for a `### Deprecated` bullet that names the same symbol(s) OR the same GH ref. The search scope depends on mode:\n   - **Pre-release / RC**: scan all dated sections, top-down. Pending fragments and legacy current-cycle entries do not prove a prior shipped deprecation.\n   - **Retrospective** (current target is `X.Y.Z`): scan ONLY the sections strictly below `## [X.Y.Z]` in CHANGELOG.md — the prior-release sections. Do NOT consider `## [Unreleased]` or later-version sections; they were written after `X.Y.Z` shipped and cannot have preceded it. Top-down within the allowed range.\n   The FIRST such entry (highest version, since CHANGELOG is reverse-chronological) is the deprecation introduction.\n3. If a matching CHANGELOG entry is found, record: (a) the release version heading that contains the Deprecated entry (e.g., `1.0.0`), (b) the full Deprecated entry text.\n4. If no matching prior CHANGELOG entry is found, check for a code-level runtime deprecation at the base ref. Resolve candidate source paths using the removed symbol, legacy parameter, or literal value, then grep those paths for deprecation warnings and inspect the surrounding source:\n   ```bash\n   git grep -n -F '<distinctive-symbol-or-legacy-value>' <base-ref> -- newton\n   git grep -n -E 'DeprecationWarning|deprecated' <base-ref> -- <candidate-paths>\n   git show <base-ref>:<candidate-path>\n   ```\n   If the candidate uses a shared deprecation helper or decorator, resolve the imported name and inspect its definition at the base ref too:\n   ```bash\n   git grep -n -F '<helper-or-decorator-name>' <base-ref> -- newton\n   git show <base-ref>:<helper-definition-path>\n   ```\n   Count this as prior-deprecation evidence when a runtime `DeprecationWarning` at the base ref clearly applies to the exact removed symbol or behavior, either through a direct `warnings.warn(...)` call or through a shared helper / decorator. For helper-mediated evidence, verify both sides of the connection: the candidate path applies or calls the helper for the removed API, and the helper definition emits `DeprecationWarning` for the calling mode or behavior being removed. For example, `@deprecate_nonkeyword_arguments` is evidence for removing positional-argument support only when it decorates that callable at the base ref; it is not evidence that the callable itself was deprecated. A generic helper that merely exists or is imported, a warning elsewhere in the same file, a docstring without a runtime warning, or a warning added only after the base release does not count. Record the warning text, the helper application path, and the warning-emission path. The base ref proves the deprecation shipped by that release; only claim an earlier introduction version if the same connected evidence is verified at that earlier tag.\n5. In the rendered Removed entry, include one of these deprecation-window lines:\n   - CHANGELOG evidence: `Deprecated in X.Y.Z; removed here.`\n   - Runtime-only evidence: `Runtime deprecation present in <base-ref>; removed here. No matching prior CHANGELOG Deprecated entry was found.`\n   - No evidence: `No prior deprecation found in released CHANGELOG sections or in code at <base-ref> — Newton's policy requires deprecation before removal.`\n   Do NOT fabricate a version.\n\nThe deprecation window belongs in BOTH the Breaking Changes entry for the removal AND the Changes-to-Existing-API row (in the Description cell or as an appended sentence in the detail block). A reader should never have to ask \"was this deprecated first, and for how long?\"\n\n**Missing-deprecation flag.** Surface `🚨 Policy: removed without prior deprecation` only when BOTH checks fail: no prior Deprecated entry exists in a previously-released CHANGELOG section, and no matching direct or helper-mediated runtime `DeprecationWarning` exists at the base ref. This fires whether or not the current release's own `### Deprecated` section also names the symbol because a warning added only in the removal release did not ship in a prior release. The release manager needs this to block the release or add migration tooling.\n\nIf a matching runtime warning exists at the base ref but the released CHANGELOG has no corresponding Deprecated entry, the deprecation window is real. Do not emit a policy violation. Instead, add a non-blocking `🧾 Deprecation omitted from CHANGELOG` review note with the base ref, warning text, and the direct source path or connected helper application / emission paths so the release-note gap remains visible.\n\n**Exception: `1.0.0` pre-stable cleanup.** Removed entries in the `1.0.0` release (and `1.0.0rcN`) are exempt from the deprecation-first policy — PRs labeled `1.0-release` are the pre-stable API cleanup and were not required to go through a prior deprecation window. When the target version is `1.0.0` or `1.0.0rcN`, do not emit the `🚨 Policy` flag or the \"No prior **Deprecated** entry found\" line for its Removed entries. Still render the deprecation-window line if a matching Deprecated entry happens to exist; otherwise note `1.0 pre-stable cleanup; no prior deprecation required.`\n\n### 4e — Signature-AST diff for unlabeled migration-required changes\n\nIndependently of CHANGELOG content, compute the public API surface at base vs. HEAD by walking every symbol re-exported from the public modules in 4a:\n\n- Base: `git show <base-ref>:<module.py>` for each public module and for every real-source module it re-exports from → parse with `ast`. Resolve each re-export's real signature at base.\n- Target: same as Base, but at the target ref — the working tree in pre-release / RC mode, or `git show v<target>:<module.py>` in retrospective mode. Do NOT read the working tree in retrospective mode; later commits on `main` would otherwise be falsely attributed to `vX.Y.Z`.\n- For each symbol whose signature shape changed AND whose matching CHANGELOG entry (if any) doesn't indicate a rename / parameter shift / removal → add to Breaking Changes section as \"unlabeled signature change — please verify\".\n\n**Exception: Removed symbols are breaking by definition.** A symbol that appears in CHANGELOG's `Removed` section does NOT need prose hedging to be valid. Do NOT flag Removed entries as \"unlabeled breaking\" — the section name itself communicates the breakage. Removed entries surface in the Breaking Changes callout and in the Changes-to-Existing-API section (as \"removed\" kind), but the report must not whinge about missing Breaking labels on them.\n\n**Exception: additive keyword-only parameters with defaults are not migration-required.** A signature change that only adds new kwargs with defaults after `*` is additive; do not surface in Breaking Changes. It belongs in Changes-to-Existing-API with Kind `new parameter` and Breaking `No`.\n\n### 4f — Semantic-change candidates from solver / integrator commits\n\nNewton has no native C++/CUDA code (unlike Warp); there is no build-and-run verification step. However, changes to solver internals, integrators, collision pipelines, and math helpers can still change observable numerical behavior without altering any signature.\n\nFor each commit in `commit_list_json` that touches paths under `newton/_src/solvers/**`, `newton/_src/sim/**` (integrator / collision code), or `newton/_src/math/**`:\n\n1. Skip if the commit is already mapped to a CHANGELOG entry explicitly describing the semantic shift.\n2. Read the commit's diff: `git show --stat <sha>` then `git show <sha>` for small diffs, or read specific hunks for large ones.\n3. **Triage** into one of three buckets:\n   - **Clearly not semantic-breaking** → drop. Examples: renaming internal symbols, comment / format changes, pure internal refactors, performance optimizations that preserve output, test-only changes, bug fixes where the pre-fix behavior was itself a bug.\n   - **Clearly semantic-shifting** with an obvious user-observable numerical / behavioral change visible from the diff alone → include in Breaking Changes with a short \"Before / After\" explanation derived from the diff and commit message.\n   - **Ambiguous** — the diff suggests the change could affect numerical output but the audit cannot establish from reading alone whether users would notice → add a concise entry in a \"Review candidates\" subsection of CHANGELOG Review Notes (NOT Breaking Changes). Include the commit, the touched file(s), and a one-sentence hypothesis. Do not speculate in Breaking Changes.\n\n**Do NOT attempt to build and run Newton at base vs. HEAD.** Newton's solver outputs depend on Warp, MuJoCo, and GPU state; reproducing a numerical diff in a one-shot audit is not reliable and not worth the setup cost. When in doubt, route to the review-candidates list and leave verification to the release manager.\n\n### 4g — Experimental-marker cross-reference\n\nSome Newton features ship with an explicit `experimental` note in the CHANGELOG entry that introduced them (e.g., \"Add differentiable rigid contacts (experimental)\") or in docstrings. Changes to those features do NOT carry the same stability contract as changes to stable APIs. The report must reflect that so the release manager does not over-weight the concern.\n\nFor each entry in Breaking Changes, Changes to Existing API, and Removed (as collected through 4a–4f), determine whether the affected symbol or feature area is currently experimental:\n\n1. Collect candidate symbols / feature-area phrases from the entry: backticked identifiers, class names, and (for topic-style entries) the most distinctive descriptive noun phrase.\n2. Search CHANGELOG.md in released-version sections for bullets that name one of the candidates AND contain the literal substring `experimental` (case-insensitive). Also match via GH ref if the current entry and a prior experimental entry share a GH number. Scope:\n   - **Pre-release / RC**: all dated sections.\n   - **Retrospective** (current target is `X.Y.Z`): everything below `## [X.Y.Z]`. The stability-promotion check (step 3 below) likewise only considers versions strictly before `X.Y.Z`.\n3. If a match exists AND there is no subsequent CHANGELOG bullet in a later released version explicitly promoting the symbol to stable (e.g., \"Promote X out of experimental\", \"Stabilize Y\"), the symbol is still experimental. Record: (a) the release version that introduced the symbol as experimental, (b) the full text of that introduction bullet.\n4. Also check the module source at HEAD for an in-code `.. experimental` / `Experimental:` / `experimental_api` / `@experimental` annotation on the symbol's declaration. If present, treat as experimental regardless of CHANGELOG signal.\n\nTag every matched entry internally as `experimental=True`. Do not alter the CHANGELOG text itself.\n\n**How the tag changes rendering:**\n- Breaking Changes heading for the entry: prefix with `Experimental:` and do not use a warning emoji. Include a short sentence reminding readers that the symbol is opt-in and has a looser stability contract, with the release where the experimental marker was introduced.\n- Changes-to-Existing-API table: the Breaking column shows `Experimental` rather than `Yes`.\n- Release Highlights bullet (Phase 7a): if the item independently clears the significance bar, use a neutral `Experimental:` label without a warning emoji. Experimental status alone does not make an item a highlight.\n\n**Never drop the entry from the detailed audit.** Experimental status changes the stability interpretation, not the underlying API diff. A removed or signature-changed experimental symbol still appears in Breaking Changes and Changes to Existing API, but it is not presented as a release-manager warning.\n\n### 4h — Schema and importer completeness\n\nApply the guides' schema/importer policy to new or substantially changed\nauthorable features across the audited range, including existing-API extensions\nand commits without changelog entries. Inspect schema definitions/proposal\nrevisions, parsing, compatible schema-package versions, and behavioral tests at\nthe audited ref; schema representation alone is not complete support.\n\nRender **Schema & Importer Support** with columns\n`Feature | Disposition | Evidence / remaining work`:\n\n- **Supported**: record the supported subset and cite schema-to-builder-to-runtime\n  evidence, tests against equivalent builder-created models, and verified schema\n  semantics.\n- **Explicitly deferred**: cite review acceptance, reason, issue, owner, and\n  target milestone, plus the remaining limitation.\n- **Not applicable**: explain why the feature is runtime-only or non-authorable.\n- **Gap / decision required**: identify missing support, evidence, or accepted\n  deferral details for a keep/defer decision.\n\nFor retrospective audits, distinguish current-policy gaps from violations of\nrequirements in force at the target tag.\n\n## Phase 5 — Review CHANGELOG language and bake\n\n### 5a — Language review\n\nRead `references/language-review-examples.md`. For EACH CHANGELOG entry, apply LLM judgment:\n\n- **🔗 Wrong ref (tier-1)**: for every GH ref in the entry, fetch the mapped commits' subjects and paths. If the entry topic doesn't match the commits' actual scope, flag.\n- **🔗 Wrong ref (tier-2)**: if `gh --version` and `gh auth status` both succeed, run `gh issue view <num> --json title,body` per ref and compare issue title to entry topic. Skip silently if `gh` unavailable.\n- **🗣️ Internal language**: internal module paths (`newton._src.*`), private identifiers with a leading underscore, Warp-internal types (`wp.types.*` that are not documented user types), implementation-detail verbs (\"refactor\", \"reorganize\", \"rewrite\") without a user-visible outcome.\n- **📝 Too terse**: under ~10 words with no context, or missing migration guidance in a Deprecated / Changed entry that names a rename or removal.\n- **🕵️ Private-only symbol**: the CHANGELOG `### Added` entry names a symbol that exists only in `newton._src.*` at HEAD and is not re-exported through a public module. See Phase 4a.\n- **⬆️ Missing migration guidance** (Newton-specific): entries in `### Deprecated`, `### Removed`, or `### Changed` (where the prose indicates rename / reorder / removal) MUST include migration guidance per `changelog/README.md` (\"Use `Y` instead\", \"in favor of `Y`\", \"switch to `Y`\"). Flag entries that rename or remove symbols without pointing to the replacement.\n- **🏷️ Naming-convention drift** (Newton-specific): new public symbols in `### Added` whose names violate Newton's prefix-first convention (e.g., `PDActuator` should be `ActuatorPD`; `add_sphere_shape()` should be `add_shape_sphere()`). See `CODING_GUIDELINES.rst`.\n\nRecord flagged entries. Keep the FULL entry text in the audit table — do not truncate.\n\n### 5b — Bake aggregation\n\nFrom `commit_list_json`:\n- Bucket each commit's `days_in_main` into **🟢 (>14 days)**, **🟡 (7–14 days)**, **🟠 (<7 days)**. Commits whose `days_in_main` is `null` (no main equivalent) skip bucketing — do NOT coerce `null` to `0` or compare it to a numeric threshold; those commits are accounted for in the next bullet instead.\n- Count anomalies: commits with `main_equivalent_sha == null`. If non-zero, prepare the ⚠️ banner for the report header.\n\n### 5c — Dependency and license audit\n\nUse `dependency_license_audit_md` from Phase 2 as the report's `{{DEPENDENCY_LICENSE_AUDIT}}` section. Apply the interpretation rules listed with the helper invocation in Phase 2.\n\n## Phase 6 — Calibration Notes (retrospective mode only)\n\n**Skip this phase entirely in pre-release / RC mode.** There is no shipped history to calibrate against.\n\nIn retrospective mode, the Phase 3–5 output is a set of flags and classifications that would have surfaced had the skill been run *before* `X.Y.Z` shipped. The point of calibration is to check those flags against what *actually* happened after the release — did the concerns hold up? The output of this phase is a \"Calibration Notes\" section in the report (Phase 7b renders it).\n\n### 6a — Enumerate post-target history\n\nIdentify releases that shipped strictly after `X.Y.Z`:\n\n```bash\ngit tag --list 'v*' --sort=v:refname\n```\n\nBefore selecting post-target history, retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`. Exclude release-candidate and other prerelease suffixes. From that filtered, sorted list, drop everything up to and including `vX.Y.Z` and keep the rest. Typical post-target history for a minor release `vX.Y.0` is:\n- `vX.Y.1`, `vX.Y.2`, ... (patch releases on the same minor)\n- `vX.Y+1.0`, `vX.Y+1.1`, ... (the next minor and its patches)\n\nFor each post-target tag, read its CHANGELOG section (the `## [<version>]` block in `CHANGELOG.md` at HEAD, or via `git show <tag>:CHANGELOG.md` if the section has since been edited). Parse the five subsections (`Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`) the same way Phase 2 does.\n\nAlso collect the commits in each post-target range (`<prior-tag>..<tag>`) — one full `list_commits.py` invocation per range, with the same required args as Phase 2. `--main-ref` reuses the main ref resolved in Phase 1 (don't rely on the script's `upstream/main` default; Phase 1 may have fallen back to a different remote):\n\nFor each retained post-target tag, derive `<post-target-release-date>` with the same `git for-each-ref --format='%(creatordate:short)'` command used in Phase 1. This keeps any soak-time metadata relative to that release rather than the day the retrospective audit happens.\n\n```bash\nuv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n  --base <prior-tag> \\\n  --head <tag> \\\n  --report-date \"<post-target-release-date>\" \\\n  --main-ref <resolved-main-ref>\n```\n\nThese commits become the evidence pool for validating the Phase 4f semantic-change candidates.\n\n### 6b — Cross-reference audit flags against post-target history\n\nFor each flag class, run the check below and record one of three outcomes per flag:\n- **Validated** — subsequent history confirms the audit concern was real.\n- **Invalidated** — subsequent history contradicts the audit concern (false positive).\n- **Unresolved** — no post-target evidence either way (flag stands as-is, but the reader can treat it as lower-confidence).\n\nThe calibration section groups results by flag class and, within each, by outcome. Never drop a flag from the original report body because of calibration — the calibration is a separate layer of commentary.\n\n**🚨 Missing-deprecation (Removed without prior evidence):**\n- Validated if: (a) no prior released CHANGELOG section names the deprecation, (b) no matching direct or helper-mediated runtime `DeprecationWarning` exists at the retrospective base ref, and (c) the symbol stays removed. Users actually lost the API without a deprecation window.\n- Invalidated if: a prior Deprecated entry existed that the audit missed. Re-scan CHANGELOG scope with fuzzier matching (different casing, plural / singular, alternate backtick placement). Report the missed entry with its version.\n- Invalidated if: the base ref contains a matching direct or helper-mediated runtime `DeprecationWarning`. Report the warning text and the direct source path or connected helper application / emission paths, and classify the missing CHANGELOG bullet as a documentation gap rather than a deprecation-policy violation.\n- Invalidated if: a later patch (`vX.Y.<Z+1>`) added the symbol *back* (revert). Name the revert commit and note \"removal reverted in vX.Y.<Z+1>\".\n\n**🕵️ Private-only (new public API with `_src`-only reachability):**\n- Validated if: a later release adds a re-export for the symbol through a public module (`newton.<module>.py`). Cite the release and the re-export commit.\n- Invalidated if: the symbol stays reachable only via `_src` in every post-target release AND no issues reference it — it was probably intentional internal-only despite its position in the Added section. Note this as \"intended internal; CHANGELOG language could have been clearer\".\n- Unresolved if: the symbol was removed / renamed before re-export resolution.\n\n**⬆️ Missing-migration-guidance:**\n- Validated if: a later release's CHANGELOG bullet (in `### Changed` or `### Fixed`) retroactively points to the replacement, OR a subsequent issue references users stuck on the migration. The second signal is only available if `gh issue list` returns matches for the symbol name; probe with `gh issue list --search \"<symbol>\" --state all --json number,title`.\n- Invalidated if: the migration was handled by a runtime `DeprecationWarning` with a clear message (grep the code at `v<target>` for the warning text).\n- Unresolved: default.\n\n**🏷️ Naming-convention drift:**\n- Validated if: a later release renames the symbol to match Newton's prefix-first rule, typically with a DeprecationWarning on the old name. Cite the rename commit and the release.\n- Invalidated if: the symbol stays and matches the *local* module convention rather than the global prefix-first rule (e.g., a module of siblings that all use `<Kind>Foo`). Note which convention it actually follows.\n- Unresolved: default.\n\n**Phase 4f semantic-change candidates** (the ones routed to \"Review Candidates\", not Breaking Changes):\n- Validated if: a later patch release's `### Fixed` entry touches the same file(s) and describes a symptom consistent with the candidate's hypothesis (e.g., \"Fix convergence regression in SolverXPBD step ordering\" after a candidate about solver step ordering). Cite the fix commit and the release.\n- Invalidated if: the file stayed stable for the rest of the minor line with no related bug reports. Probe `gh issue list --search \"<file-or-feature>\" --state all --json number,title,createdAt` if `gh` is authenticated — only count issues created after `v<target>`'s release date. Skip the probe silently if `gh` is unavailable.\n- Unresolved: default.\n\n**Deprecation-follow-through (new check, retrospective-only):** for every entry in `X.Y.Z`'s own `### Deprecated` section, check subsequent minor releases for the corresponding `### Removed` entry.\n- **Followed through** — a later minor removed the symbol as promised. Cite the release.\n- **Still deprecated** — symbol remains in the public surface with the deprecation warning in all later minors. No action required; just a fact.\n- **Silently dropped** — symbol was removed but no `### Removed` entry cites it (CHANGELOG hygiene bug in the later release). Flag this as a separate concern.\n\n### 6c — Compose the calibration narrative\n\nAggregate the per-flag outcomes into a short section with this shape:\n- One-paragraph headline: how many flags were validated / invalidated / unresolved overall, a\n\n<!-- [TRUNCATED AT 50KB] -->","frontmatter":{"name":"release-audit","description":"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release."},"isInternal":false,"tokens":11570,"sizeBytes":50252},{"name":"SKILL.md","path":".agents/skills/release-changelog/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-changelog/SKILL.md","title":"release-changelog","category":"anthropic-skill","format":"markdown","content":"---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nPending user-facing changes live in Towncrier fragments under `changelog/`.\n`CHANGELOG.md` is generated only on a release branch. Shipped sections are\nimmutable; the assembled section for the pending release remains a rolling\ndocument until tagging. Follow `changelog/README.md` as the command and format\nauthority.\n\n## Audit pending changes\n\n1. Identify the release ref and comparison base. Audit `release-X.Y` once it\n   exists; otherwise audit the intended main ref.\n2. Protect released history. Diff `CHANGELOG.md` from the latest stable tag and\n   require explicit maintainer approval for edits to dated sections.\n3. Render a non-mutating preview, which also validates Towncrier's renderable\n   fragment filenames:\n   ```bash\n   uvx --from towncrier==25.8.0 towncrier build --draft \\\n     --version X.Y.Z --date YYYY-MM-DD\n   ```\n4. Compare the preview with the release audit and commit range from the previous\n   release. Inspect `.skip` reasons separately.\n5. Preserve information. Rephrase, split, merge, or recategorize fragments only\n   when the facts remain intact. Ask before deleting information or downgrading\n   a user-visible change.\n6. Use only `Added`, `Changed`, `Deprecated`, `Removed`, and `Fixed`, in that\n   order. Keep migration and retesting guidance in affected entries.\n7. Remove exact and semantic duplicates. When a feature and its fix both land\n   in one cycle, describe the final user-visible behavior once.\n8. Keep `Added` for new public APIs, options, features, examples, and docs. Put\n   existing-API behavior, warning, default, importer, and solver changes in\n   `Changed`, even when they expand support.\n9. Give every breaking, removed, deprecated, or default-changing entry a\n   concrete action. Never direct users to `newton._src`.\n10. A numeric fragment identifier is a GitHub issue number. Towncrier renders\n    its issue link automatically; do not rewrite it as a pull request number.\n\n## Assemble the release during RC stabilization\n\nAfter the initial release scope has been audited on `release-X.Y`, assemble the\ncurrent fragments early enough for maintainer review:\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\nuvx --from towncrier==25.8.0 towncrier build --yes \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit rm --ignore-unmatch \"changelog/*.skip\"\ngit add -A CHANGELOG.md changelog\n```\n\nReview and approve the draft before running the mutating command. Towncrier\ninserts the dated section below `[Unreleased]` and deletes rendered fragments.\nIt ignores `.skip` files, so remove those explicitly. Review the staged diff in\na changelog-only pull request labeled `release-management`.\n\nAfter assembly, apply the audit rules above to the dated section: verify\ncompleteness, grouping, deduplication, wording, categories, and migration\nguidance. Keep editorial cleanup in the changelog-management commits that will\nlater be synchronized to `main`.\n\nThe first Towncrier release requires one migration audit. The insertion marker\nsits above the legacy `[Unreleased]` entries so they remain under the first\ngenerated release title. Merge duplicate category headings without dropping or\nduplicating an entry. Later releases need no special handling.\n\nTreat the assembled section as a rolling document. For every later cherry-pick\nbefore tagging:\n\n1. Validate the new fragments and render them with `towncrier build --draft`.\n2. Fold the previewed entries into the existing dated section without creating\n   a second release heading.\n3. Delete exactly the consumed `.md` and `.skip` fragments, then stage\n   `CHANGELOG.md` and `changelog/`.\n4. Rerun the changelog cleanup and `release-audit` checks, and merge the update\n   as another changelog-only `release-management` pull request.\n\nFinal GA preparation verifies the completed section and confirms that no\nrelease-branch fragments remain. Do not postpone the full cleanup until GA.\n\n## Synchronize to main\n\nAfter tagging:\n\n1. Create a changelog-only branch from current `main`.\n2. Cherry-pick, in order, every changelog-management commit from `release-X.Y`:\n   the initial Towncrier build, editorial cleanup, and all later cherry-pick\n   additions.\n3. Confirm fragments deleted by those commits disappear while fragments added to\n   `main` after the branch cut remain under `changelog/`.\n4. Confirm the dated section matches the release tag and older history is\n   unchanged.\n5. Open a changelog-only pull request labeled `release-management`.\n\nDo not replace the whole file with the release-branch copy. The commits'\npath-level deletions are what preserve main-only fragments.\n\n## Checks\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit diff v<latest-release> -- CHANGELOG.md changelog\ngit diff --cached --name-status -- CHANGELOG.md changelog\nrg -ni \"removed|deprecated|in favor of|use .* instead|renam|replac|default|breaking\" \\\n  CHANGELOG.md changelog\n```\n\nConfirm that `[Unreleased]` is empty after the first migration, no dated history\nchanged, released entries appear exactly once, and post-cut main fragments\nsurvive synchronization.\n","frontmatter":{"name":"release-changelog","description":"Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main."},"isInternal":false,"tokens":1223,"sizeBytes":5337},{"name":"SKILL.md","path":".agents/skills/release-notes/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.agents/skills/release-notes/SKILL.md","title":"release-notes","category":"anthropic-skill","format":"markdown","content":"---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nDraft concise GitHub Release notes that explain why a Newton release exists and\nwhat users should know. Do not reproduce the full changelog; link to it.\n\nWrite for external users moving from the previous final release to the current\nartifact without assuming they followed development or release candidates.\nFinal-release notes must not mention earlier RCs. Never mention or link internal\nrelease audits, audit gists, readiness reports, cutoff SHAs, bake durations,\naudit counts, or other audit-only metadata; use those sources as evidence only.\n\n## Workflow\n\n1. Identify the artifact, target version, and release type:\n   - **GitHub release description**: public release page. Follow Newton/Warp\n     release-page style and include user-actionable migration sections.\n   - **Internal release announcement**: short internal email/doc. Use release\n     metadata first, then grouped bullets such as `New Features`,\n     `Performance Improvements`, and `Developer Experience`.\n   - If the user wants both and the content should converge, keep one document\n     only when explicitly requested; otherwise maintain separate drafts.\n   - Patch / bugfix releases: emphasize fixes, compatibility, and stability.\n   - Minor / feature releases: emphasize major user-facing capabilities.\n   - RCs: state that this is a release candidate and what needs validation.\n     If drafting final-release text from an RC tag or release branch, do not\n     mention the RC; use the RC only as the temporary source of truth.\n2. Choose changelog source material from the authoritative release ref:\n   - After the Towncrier build or tagging, read the matching dated\n     `CHANGELOG.md` section from the release tag or release branch.\n   - Before the build, check out the release branch, validate its pending\n     fragments, and render a non-mutating preview:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Draft from the preview and legacy `[Unreleased]` entries during the first\n     Towncrier transition. Do not run a mutating build merely to draft notes.\n   Do not rely on `main` unless the release is actually cut from `main`.\n3. Determine the previous release tag:\n   - Patch release `X.Y.Z`, `Z > 0`: use the highest earlier `vX.Y.<Z'>` tag.\n   - Feature release `X.Y.0`: use the highest `vX.<Y-1>.*` tag. If `Y == 0`,\n     use the highest tag from the previous major.\n4. Compare the release range against the previous release:\n   ```bash\n   git log --no-merges --oneline --cherry-pick --right-only v<previous>...v<target>\n   git diff --name-status v<previous>..v<target>\n   ```\n   Use the symmetric-difference `...` log form for counting and scanning commits\n   when a release branch contains cherry-picks; it avoids overstating scope with\n   equivalent patches already present in the previous release. Use the normal\n   `..` diff for changed files. If the final tag does not exist yet, use the\n   latest RC tag or `upstream/release-X.Y` as the temporary target.\n5. Inspect the PRs behind candidate highlights. Commit subjects usually carry\n   `(#NNNN)`; use PR bodies when needed to understand impact and any linked\n   issues.\n6. Check prior release-note and announcement formats when available:\n   - Newton release pages, e.g. `v1.2.0`, for the local public-release shape.\n   - Warp release pages for `Announcements`, `Upcoming removals`, and\n     acknowledgement patterns.\n   - Internal announcements for short internal release-email structure.\n7. Draft a high-level overview and a short highlights list. Keep only\n   consumer-relevant items. Omit CI, workflow, README layout, release-link\n   pinning, and other internal/docs polish unless the user explicitly asks or it\n   affects library users. When a validated release review supplies the\n   highlights, preserve its release-defining conclusions, ordering, and public\n   wording unless publication rules require a change. Rewrite audit-oriented\n   framing, remove audit-only metadata, and adapt references to the release-note\n   format without weakening the user-facing claims.\n8. Keep a review-ready release-branch draft. After tagging, refresh it against\n   the final tag and inspect the workflow-created draft GitHub Release. Publish\n   only after verifying the final artifact and links per `docs/guide/release.rst`.\n\n## Linking Rules\n\n- Link the changelog to the final release tag:\n  `https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor`\n- If drafting before the final tag exists, use `release-X.Y` or the RC tag\n  temporarily, but note that the published release should use the final tag.\n- Never link the changelog to `main` for a release branch unless `main` is the\n  authoritative release ref; `main` may have newer unreleased changes.\n- Add one GitHub reference to each highlight, usually the PR. Use an issue only\n  when there is no useful PR or the issue is the canonical context.\n- Avoid linking both an issue and a PR for the same highlight unless that extra\n  context is necessary.\n- In GitHub Release notes, render same-repository references as plain `#NNNN`\n  instead of full markdown links. GitHub auto-links them on the release page, and\n  the compact form matches Warp's release-note style.\n- Link in-tree examples or docs on the release tag URL, never `main`, so links\n  do not drift after publication.\n- For dependency summaries, prefer a link to the relevant `pyproject.toml`\n  compare over listing every changed constraint:\n  `https://github.com/newton-physics/newton/compare/v<previous>...v<target>?diff=split`\n  Mention only high-signal dependency changes in bullets.\n\n## Style\n\n- Start with a short paragraph naming the version, release type, and purpose.\n- Use a `## Highlights` section with typically 3-6 grouped bullets. Retain\n  additional release-defining highlights when the user explicitly requests them\n  or a validated release review establishes that they belong; do not drop a\n  significant theme merely to meet the usual count.\n- For bugfix releases, keep notes slim: no `## New features` section unless a\n  genuinely notable capability shipped in the patch. The highlights are a\n  categorized digest of fixes.\n- For feature releases, group related features by user workflow and order by\n  impact. Lead with the most important user-facing capability, not API names.\n- Prefer user impact over implementation detail.\n- Keep bullets compact: one bold label, one or two explanatory sentences, then\n  the `#NNNN` reference.\n- Treat the changelog as source material, not prose to copy. Translate internal\n  implementation terms into user-facing impact.\n- Include `## Announcements` only for changes users must act on, such as\n  removals, deprecations, platform-support changes, or dependency constraints.\n- For public feature releases, include focused sections for:\n  - breaking changes and removals,\n  - new deprecations,\n  - upcoming removals,\n  - dependency updates,\n  - acknowledgements.\n  Keep these concise; the changelog carries the exhaustive detail.\n- Include `## Notes` only for compatibility, install, or migration information\n  users need. Drop the section when there is nothing useful to say.\n- Include `## Acknowledgments` when there are meaningful contributions from\n  outside Newton maintainers and project-member groups. Omit trivial typo-only\n  or formatting-only changes.\n- For patch releases, say whether the release is intended to be API-compatible\n  with the previous patch/minor when that is true.\n- Avoid em dashes in rendered prose.\n- Keep raw Markdown soft-wrapped: use one physical line per paragraph and list item; let viewers wrap it to their window width.\n\n## Dependency Updates\n\nDo not default to a large table. Keep dependency updates high signal:\n\n- Call out major/minor runtime baseline bumps, new extras, dependency caps that\n  affect users, and removed caps when they unblock compatibility.\n- Link to the `pyproject.toml` compare for the complete detail.\n- If the prior patch release changed dependencies, compare against the closest\n  prior release tag, not the earlier minor tag.\n\n## Acknowledgments\n\nBefore listing outside contributors, verify they are not in Newton's maintainer\nor project-member groups.\n\n1. Read `newton-governance/CONTRIBUTORS.md` or the current governance source\n   when reachable. Treat it as the authority for maintainer and project-member\n   membership.\n2. If GitHub access is available and governance points to org teams, query the\n   current team slugs from GitHub rather than relying on a hardcoded list:\n   ```bash\n   gh api orgs/newton-physics/teams --paginate --jq '.[] | [.slug, .name] | @tsv'\n   gh api orgs/newton-physics/teams/<team-slug>/members --paginate --jq '.[] | .login'\n   ```\n   Prioritize teams named by governance, or teams whose current names clearly\n   identify maintainers, TSC, project members, or project-member organizations.\n3. Cross-check candidate PR authors with `gh pr view <number> --json author`\n   and commit emails. Commit email/company is a hint, not a substitute for the\n   team/governance check.\n4. Phrase the section accurately, for example \"outside the Newton maintainer\n   and project-member groups\" when that is the filter used.\n\n## Template\n\n```markdown\n# Newton vX.Y.Z\n\nNewton vX.Y.Z is a patch release following vX.Y.W. It focuses on bug fixes and\ncompatibility updates for the X.Y release line, especially around <areas>.\n\nFor the complete list of changes, see the [changelog](https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor).\n\n## Highlights\n\n- **<User-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n- **<Another user-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n## Announcements\n\n<Only include this section when there is a removal, deprecation,\nplatform-support change, dependency constraint, or other user-actionable\nannouncement. Drop it otherwise.>\n\n## Notes\n\nThis release is intended to be API-compatible with Newton vX.Y.W. No breaking\nchanges are expected.\n```\n","frontmatter":{"name":"release-notes","description":"Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases."},"isInternal":false,"tokens":2274,"sizeBytes":10232},{"name":"SKILL.md","path":".claude/skills/code-review-newton/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.claude/skills/code-review-newton/SKILL.md","title":"code-review-newton","category":"anthropic-skill","format":"markdown","content":"---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/code-review-newton/SKILL.md`. If it is unavailable, stop\nwithout performing the review.\n","frontmatter":{"name":"code-review-newton","description":"Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards."},"isInternal":false,"tokens":88,"sizeBytes":429},{"name":"SKILL.md","path":".claude/skills/release-audit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.claude/skills/release-audit/SKILL.md","title":"release-audit","category":"anthropic-skill","format":"markdown","content":"---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\ndisable-model-invocation: true\nargument-hint: \"[target-version]\"\nallowed-tools: Bash(git log *) Bash(git show *) Bash(git grep *) Bash(git tag *) Bash(git rev-parse *) Bash(git diff *) Bash(git ls-tree *) Bash(uvx --from towncrier==25.8.0 towncrier build --draft *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/cleanup_report.py *) Bash(gh --version) Bash(gh auth status) Bash(gh gist create *) Bash(gh gist list *) Bash(gh gist view *) Bash(gh gist edit *) Bash(gh issue view *) Bash(gh issue list *) Read Write Grep Glob\n---\n\n# Release Audit\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-audit/SKILL.md`. If it is unavailable, stop without\nstarting the audit.\n","frontmatter":{"name":"release-audit","description":"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.","disable-model-invocation":true,"argument-hint":"[target-version]","allowed-tools":"Bash(git log *) Bash(git show *) Bash(git grep *) Bash(git tag *) Bash(git rev-parse *) Bash(git diff *) Bash(git ls-tree *) Bash(uvx --from towncrier==25.8.0 towncrier build --draft *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/cleanup_report.py *) Bash(gh --version) Bash(gh auth status) Bash(gh gist create *) Bash(gh gist list *) Bash(gh gist view *) Bash(gh gist edit *) Bash(gh issue view *) Bash(gh issue list *) Read Write Grep Glob","allowedTools":["Bash(git","log","*)","Bash(git","show","*)","Bash(git","grep","*)","Bash(git","tag","*)","Bash(git","rev-parse","*)","Bash(git","diff","*)","Bash(git","ls-tree","*)","Bash(uvx","--from","towncrier==25.8.0","towncrier","build","--draft","*)","Bash(uv","run","--no-project","python",".agents/skills/release-audit/scripts/list_commits.py","*)","Bash(uv","run","--no-project","python",".agents/skills/release-audit/scripts/license_audit.py","*)","Bash(uv","run","--no-project","python",".agents/skills/release-audit/scripts/cleanup_report.py","*)","Bash(gh","--version)","Bash(gh","auth","status)","Bash(gh","gist","create","*)","Bash(gh","gist","list","*)","Bash(gh","gist","view","*)","Bash(gh","gist","edit","*)","Bash(gh","issue","view","*)","Bash(gh","issue","list","*)","Read","Write","Grep","Glob"],"disableModelInvocation":true},"allowedTools":["Bash(git","log","*)","Bash(git","show","*)","Bash(git","grep","*)","Bash(git","tag","*)","Bash(git","rev-parse","*)","Bash(git","diff","*)","Bash(git","ls-tree","*)","Bash(uvx","--from","towncrier==25.8.0","towncrier","build","--draft","*)","Bash(uv","run","--no-project","python",".agents/skills/release-audit/scripts/list_commits.py","*)","Bash(uv","run","--no-project","python",".agents/skills/release-audit/scripts/license_audit.py","*)","Bash(uv","run","--no-project","python",".agents/skills/release-audit/scripts/cleanup_report.py","*)","Bash(gh","--version)","Bash(gh","auth","status)","Bash(gh","gist","create","*)","Bash(gh","gist","list","*)","Bash(gh","gist","view","*)","Bash(gh","gist","edit","*)","Bash(gh","issue","view","*)","Bash(gh","issue","list","*)","Read","Write","Grep","Glob"],"isInternal":false,"tokens":277,"sizeBytes":1112},{"name":"SKILL.md","path":".claude/skills/release-changelog/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.claude/skills/release-changelog/SKILL.md","title":"release-changelog","category":"anthropic-skill","format":"markdown","content":"---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-changelog/SKILL.md`. If it is unavailable, stop\nwithout modifying the changelog.\n","frontmatter":{"name":"release-changelog","description":"Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main."},"isInternal":false,"tokens":79,"sizeBytes":376},{"name":"SKILL.md","path":".claude/skills/release-notes/SKILL.md","rawUrl":"https://raw.githubusercontent.com/newton-physics/newton/HEAD/.claude/skills/release-notes/SKILL.md","title":"release-notes","category":"anthropic-skill","format":"markdown","content":"---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-notes/SKILL.md`. If it is unavailable, stop without\ndrafting or revising release text.\n","frontmatter":{"name":"release-notes","description":"Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases."},"isInternal":false,"tokens":83,"sizeBytes":401}],"systemPromptSnippet":"<yakaai_skills repo=\"newton-physics/newton\">\n<!-- File: AGENTS.md (Tokens: ~566 | Category: root-instruction) -->\n# Newton Development Guidelines\n\nRead and follow the canonical [source code and public API guidelines](CODING_GUIDELINES.rst) before changing or reviewing Newton code. This file contains agent-specific workflow instructions; the linked guide is authoritative for coding and API design.\nFor reviews, also read and apply the [review guidelines](REVIEW_GUIDELINES.rst) and follow `.agents/skills/code-review-newton/SKILL.md`.\n\n- Create a feature branch on your fork before committing—never commit directly to `main`. Give the pull request a concise, descriptive title.\n- Use imperative mood in commit messages (\"Fix X\", not \"Fixed X\"), with a roughly 50-character subject and a body wrapped at 72 characters that explains what and why.\n- Verify regression tests fail without the fix before committing.\n\nRun `uvx pre-commit run -a` to lint and format before committing. Use `uv` for all commands; fall back to `venv` or `conda` only if `uv` is unavailable.\n\n```bash\n# Examples\nuv sync --extra examples\nuv run -m newton.examples basic_pendulum\n```\n\n## Tests\n\nFollow the canonical [test organization and runtime guidelines](CODING_GUIDELINES.rst#test-organization-and-runtime) when changing or reviewing tests.\n\n```bash\nuv run --extra dev -m newton.tests\nuv run --extra dev -m newton.tests -k test_viewer_log_shapes           # specific test\nuv run --extra dev -m newton.tests -k test_basic.example_basic_shapes  # example test\nuv run --extra dev --extra torch-cu12 -m newton.tests                  # with PyTorch\n```\n\n```bash\n# Benchmarks\nuvx --with virtualenv asv run --launch-method spawn main^!\n```\n\n## PR Instructions\n\n- If opening a pull request on GitHub, use the template in `.github/PULL_REQUEST_TEMPLATE.md`.\n- Follow `changelog/README.md`: add a Towncrier fragment for user-facing changes instead of editing `CHANGELOG.md` directly. A `.skip` reason is optional for changes without user-facing impact.\n- Preview fragments with `uvx --from towncrier==25.8.0 towncrier build --draft --version X.Y.Z --date YYYY-MM-DD`.\n\n## Examples\n\n- Follow the `Example` class format.\n  - Implement `test_final()` or `test_post_step()`; an example may implement both.\n  - In test mode, `test_post_step()` runs after each simulation step and `test_final()` runs after the example completes.\n- Register the example in `README.md` with its `python -m newton.examples <name>` command and a 320x320 JPEG screenshot.\n\n<!-- File: .agents/skills/code-review-newton/SKILL.md (Tokens: ~619 | Category: anthropic-skill) -->\n---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nRead `REVIEW_GUIDELINES.rst` and `CODING_GUIDELINES.rst` in full. Treat the\nformer as the explicit definitions of the Fit, Requirements, and Standards\naxes, and enforce the latter during Standards review.\n\n1. Resolve the exact merge base and head. Read the complete\n   `merge-base..head` diff and commit list.\n2. Read the pull-request description, linked issue or specification, relevant\n   primary sources, and `CODING_GUIDELINES.rst`. If no separate specification\n   exists, use the pull-request description as the stated intent. Do not read\n   existing review comments yet.\n3. Perform an adversarial correctness-first Requirements pass. Trace changed\n   inputs, state, counts, offsets, ownership, and outputs through every relevant\n   supported execution mode. Check applicable zero/one/many and capacity\n   boundaries, heterogeneous inputs, toggle/reset/reuse and partial failures,\n   CPU/CUDA and backend differences, autodiff, determinism, graph capture, and\n   numerical invariants. For performance changes, examine setup and steady-state\n   complexity, allocations, synchronization, transfers, and whether benchmarks\n   exercise the changed path. Answer the Honest contract, Siblings, Tests, and\n   Cost questions in `REVIEW_GUIDELINES.rst`. Run a minimal adversarial probe\n   when feasible. Apply the guides' schema and importer checks to authorable\n   features, including behavioral equivalence and explicit acceptance of\n   deferrals.\n4. Freeze candidate findings before reading existing reviews. Record the\n   location, triggering input or condition, mechanism, observable impact,\n   evidence, and confidence for each candidate.\n5. Read the top-level discussion and review threads. Refine or deduplicate the\n   independently discovered concerns; acknowledge existing concerns when they\n   affect the verdict.\n6. Review Fit and Standards independently using their definitions in\n   `REVIEW_GUIDELINES.rst`, and answer its Simplest and Principled questions\n   as part of Fit. When independent agent contexts are available, use separate\n   passes so one conclusion does not bias another.\n7. Report Fit and architectural concerns first, but retain every supported\n   material behavioral, correctness, compatibility, and performance finding\n   even when Fit fails. Do not let missing tests, documentation, or measurements\n   replace the search for an underlying behavioral defect.\n8. For each remaining concern, state its priority, location, problem, impact,\n   and evidence. Distinguish demonstrated defects from questions, evidence\n   requests, requirements, and judgment calls. Do not prescribe a correction\n   unless the user asks for one.\n\nAggregate the three axes without suppressing a finding merely because another\naxis passes. Give the explicit Fit verdict defined by the review guide.\n\n<!-- File: .agents/skills/release-audit/agents/openai.yaml (Tokens: ~11 | Category: anthropic-skill) -->\npolicy:\n  allow_implicit_invocation: false\n\n<!-- File: .agents/skills/release-audit/references/classification-rules.md (Tokens: ~2121 | Category: anthropic-skill) -->\n# Classification Helpers\n\nThis reference is loaded during Phases 3, 4, and 5 of the skill. It defines concrete path and naming rules the audit relies on when analyzing commits and CHANGELOG entries.\n\n## Public API surface (Phase 4a, 4e)\n\nUsed to decide whether a symbol is \"genuinely new\" vs. \"pre-existed and got extended\":\n\nNewton exposes its public surface through per-topic re-export modules discovered dynamically by `docs/generate_api.py`:\n\n- `api_modules()` imports `newton`, starts with the top-level module, and adds every module-valued name exported through `newton.__all__`.\n- Each discovered module's own `__all__` list or tuple defines its public symbols. `public_symbols()` rejects missing declarations, invalid containers, and non-string entries.\n- `solver_submodule_pages()` adds public solver submodules and recursively exposed module trees under `newton.solvers`.\n- There is no fixed `MODULES` constant. Inspect `docs/generate_api.py`, `newton/__init__.py`, and `newton/solvers.py` at both refs so additions such as a new top-level public module or nested experimental solver namespace are included.\n\nRepresentative modules include `newton.geometry`, `newton.solvers`, and `newton.viewer`. Each public module re-exports from `newton/_src/<topic>/...`. `newton._src` is internal (`CODING_GUIDELINES.rst`: examples and docs must not import from `newton._src`).\n\n**To determine if `newton.X` existed at base**:\n- Inspect module-valued exports in `newton.__all__` at base and target using the `api_modules()` rules above.\n- For top-level symbols: `git show <base>:newton/__init__.py` and check `from ._src.<submodule> import X` / `__all__`.\n- For submodule public attributes (e.g., `newton.geometry.Mesh`): `git show <base>:newton/geometry.py` and check imports / `__all__`.\n- For nested solver modules: apply `solver_submodule_pages()` reachability rules to `newton.solvers` at the relevant ref.\n- For method additions on an existing class (e.g., `SolverXPBD.update_contacts`): resolve the class's real source file (e.g., `newton/_src/solvers/xpbd.py`) and `ast`-walk it at base.\n\n**Public-API declaration and exposure check (Phase 4a addition)**: inspect every discovered public module at HEAD. Its `__all__` must be a list or tuple containing only strings. For every genuinely new symbol, collect all public-module `__all__` declarations that contain it. Zero memberships raise a 🕵️ Private-only flag; one establishes the canonical public import path; more than one raises a duplicate-public-export policy finding listing all paths. Reason: `CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one public module's `__all__` and forbids examples/docs from importing `newton._src`.\n\n## No kernel-scope builtin registry\n\nNewton has no separate builtin registry to audit. All user-facing symbols are ordinary Python classes, functions, enums, and constants defined in `newton/_src/**` and re-exported through the public modules above. Skip kernel-scope symbol extraction.\n\n## Paths that trigger Phase 4f semantic-change review\n\nCommits touching these paths get per-commit judgment (Phase 4f). Not every change in them is a semantic shift — the audit reads the diff and decides:\n\n- `newton/_src/solvers/**` — solver implementations (XPBD, MuJoCo, Featherstone, VBD, implicit MPM). Changes can alter convergence, contact handling, step semantics.\n- `newton/_src/sim/**` — integrators, collision pipeline, model building, state transfer. Changes can alter per-step dynamics or contact ordering.\n- `newton/_src/math/**` — math helpers, raycast, quaternion utilities. Changes can shift numerical output.\n- `newton/_src/geometry/**` — geometry primitives, SDF / mesh representations, support functions. Changes can shift contact normals, distances, or inside/outside tests.\n\nTypical NOT-SEMANTIC-SHIFTING signals in these paths:\n- Pure internal refactors, renames of internal identifiers.\n- Comment or formatting changes.\n- Performance optimizations that preserve observable output (e.g., vectorization, precomputed AABBs).\n- Caching / memoization where the cached value is equivalent.\n- Test-only changes.\n- Build-system touches.\n- Bug fixes where the previous behavior was demonstrably wrong.\n\nTypical SEMANTIC-SHIFTING signals:\n- Algorithm swaps that produce different numerical results (e.g., switching SDF construction from winding-number to parity).\n- Default parameter value changes that affect physics (e.g., changing MPM quadrature, contact stiffness, solver iteration defaults).\n- Ordering / determinism changes that affect contact reduction or constraint solving.\n- Convergence criteria changes (different tolerance, different iteration bound behavior).\n- Unit / frame-of-reference changes for authored values (e.g., \"stop multiplying joint damping by 180/π\").\n- Control-flow changes that alter when callbacks / registered hooks / user kernels are invoked.\n\n**Never attempt to build and run Newton at base vs. HEAD for verification.** Newton's output depends on Warp codegen, MuJoCo, and GPU state; reliable head-to-head numerical verification in a one-shot audit is out of scope. When in doubt, route the commit to a \"Review candidates\" section in the report's review notes rather than speculating in Breaking Changes.\n\n## Heuristic paths commonly relevant (reference only)\n\nThese are noted here so the audit can pattern-match when reading commits, but the skill does NOT use them to produce an appendix-style commit audit. Purpose is recognition, not bucketing:\n\n- `.github/**`, `.pre-commit-config.yaml`, `uv.lock`, `.python-version` — infrastructure, not user-facing.\n- `asv.conf.json`, `asv/**`, root-level `_bench_*.py` — benchmark harness.\n- `docs/**`, root-level `*.md`, `CHANGELOG.md`, `changelog/**` — documentation.\n- `newton/examples/**` — example scripts. New files here are user-facing (a new example is a release-notable addition). Changes to existing examples are typically not release-notable unless they change the example's registered name or behavior.\n- `newton/_src/**` other than the solver / sim / math / geometry paths above — internal Python implementation.\n- `pyproject.toml`, `uv.lock`, and files matched by `project.license-files` — dependency and license-audit inputs. New external dependency names, direct requirement scope changes, new resolved package names, and notice-file changes belong in \"Dependency & License Audit\". Version bumps are not release-notable on their own; dependency changes may also belong in \"Behavioral & Support Changes\" if a user-visible pin moves (e.g., `mujoco-warp ~=3.7.0`).\n\n## Newton-specific rename and parameter-reorder recognition (Phase 4d, 5a)\n\nNewton's CHANGELOG does NOT use the `**Breaking:**` literal marker. Instead, migration-required changes appear in `### Changed` with prose like:\n\n- \"Rename `X.old_name` to `X.new_name`. Old name still accepted as keyword argument but emits a `DeprecationWarning`.\"\n- \"Reorder `X()` parameters so `a` precedes `b`.\"\n- \"Migrate all Y logic to Z, all Y functions now return ...\"\n\nWhen Phase 4d / 5a encounter these patterns, treat them as migration-required changes (Kind `rename` or `parameter reorder` in the Changes-to-Existing-API table). Check that the entry includes migration guidance (`Use ...`, `in favor of ...`, `prefer ...`). If guidance is missing, raise a ⬆️ flag in the language review.\n\n## Deprecation policy (Phase 4d)\n\n`CODING_GUIDELINES.rst`: breaking changes require a deprecation first. A prior released `### Deprecated` entry is the preferred evidence. A matching runtime `DeprecationWarning` at the base ref also proves that users received a deprecation window, even if the released CHANGELOG omitted it. The warning may be emitted directly or by a shared helper / decorator that clearly applies to the removed API or behavior.\n\nWhen Phase 4d cannot find the prior Deprecated entry:\n- Resolve the symbol or legacy behavior in code at the base ref.\n- Run a targeted `git grep` for `DeprecationWarning` / `deprecated` in the candidate path and inspect the warning context.\n- If the candidate calls or applies a shared deprecation helper / decorator, resolve that name and inspect its definition at the base ref. Verify that the candidate's call site connects the helper to the exact removed API or behavior and that the helper emits `DeprecationWarning`. A generic helper's existence or import alone is not evidence.\n- If a matching direct or helper-mediated runtime warning exists, record the base ref, warning text, and the direct source path or connected helper application / emission paths. Do not emit a policy violation; flag the missing released CHANGELOG entry as a documentation gap.\n- If no matching warning exists, surface `🚨 Policy: removed without prior deprecation` in the Breaking Changes section and cite the Removed entry in full.\n- Note whether the current CHANGELOG's own `### Deprecated` section also names the same symbol. Deprecating and removing in the same release is a policy violation because the warning did not ship in a prior release.\n\nA release manager reading the report should see one of three resolved outcomes:\n1. Prior CHANGELOG entry found: report its release version.\n2. Runtime `DeprecationWarning` found at base: deprecation policy satisfied, with a non-blocking CHANGELOG documentation flag.\n3. Neither found: block the release or add a deprecation shim for one more release cycle.\n\nDo not infer a policy violation from CHANGELOG evidence alone. The code-level check is mandatory before raising the blocking flag.\n\n<!-- File: .agents/skills/release-audit/references/language-review-examples.md (Tokens: ~2258 | Category: anthropic-skill) -->\n# CHANGELOG Language Review Examples\n\nLoaded during Phase 5 of the skill. Use these examples to calibrate the language-review pass: flagging entries whose language would confuse end users, whose refs look wrong, or whose content violates Newton's conventions.\n\n## What to flag\n\n### 🗣️ Internal / implementation language\n\nFlag entries that reference:\n\n- **Internal module paths**: `newton._src.foo`, `newton._src.solvers.xpbd.internal_helper`.\n- **Warp-internal helpers** that leaked into user-facing prose: e.g. `warp.fem.geometry.closest_point` (a Newton internal refactor may cite this; it is internal to Warp).\n- **Private identifiers** with leading underscores: `_foo`, `Model._finalize`.\n- **Implementation-detail verbs** without a user-visible outcome: \"Refactor internal dispatch path\", \"Reorganize private helpers\", \"Rewrite foo bar\".\n\nGood examples (user-facing):\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes from any collision shape, and a viewer toggle to visualize gap + margin wireframes in the GL viewer.\n>\n> Use pre-computed local AABB for `CONVEX_MESH` shapes in `compute_shape_aabbs`, avoiding a per-frame support-function AABB computation.\n\nFlag these:\n\n> Inline a `wp.vec3`-specialized point-to-triangle squared-distance helper in the implicit-MPM rasterized collider, removing the dependency on Warp's internal `warp.fem.geometry.closest_point`.\n> *Reason:* references `warp.fem.geometry.closest_point`, which is Warp-internal. User-facing rewrite: \"Inline point-to-triangle distance in the implicit-MPM collider so it no longer depends on Warp's `warp.fem` module.\"\n>\n> Refactor `newton._src.solvers.xpbd._update_constraints` to unify storage path.\n> *Reason:* references internal module + private method. Implementation detail with no user-observable effect. Candidate for deletion from CHANGELOG, not rewording.\n\n### 📝 Too terse\n\nFlag entries that are too short to convey meaning or that omit enough context for a user to act on:\n\n- Under ~10 words AND no linked issue for context.\n- Entries like \"Fix bug in XPBD solver\" without specifying which bug or what the fix does.\n\nFlag:\n\n> Fix bug.\n> *Reason:* insufficient — user can't tell what was fixed.\n>\n> Improve solver performance.\n> *Reason:* no specifics; which solver, how much, under what conditions?\n\nDon't flag (long but load-bearing):\n\n> Fix MJCF importer in `compiler.angle=\"degree\"` mode: (1) stop multiplying joint `damping`/`stiffness` by `180/π` (MuJoCo stores these in `N·m·s/rad` and `N·m/rad` regardless of `angle`); (2) stop `deg2rad`-scaling the default `±MAXVAL` sentinel for joints without an explicit `range=`.\n\n### 🔗 Suspected wrong GH reference\n\nFlag when the CHANGELOG entry's topic doesn't match the commits that cite that GH number.\n\n**Tier-1 heuristic (always on, fully local):**\n\nFor entry \"Add support for Gaussian splats (GH-NNNN)\", fetch commits tagged `GH-NNNN` and look at their subjects and file paths. If every commit only touches `.github/**` or `docs/**`, the GH ref is likely wrong — the entry describes a model-builder API change, but nothing in those commits modifies the builder or geometry. Flag.\n\nDon't flag if:\n- Commits touch `newton/_src/geometry/**` or `newton/_src/sim/builder.py` for a geometry-addition entry → topic matches.\n- Commits touch `docs/**` and the `Added` or `Changed` entry describes that documentation → topic matches.\n- Commits touch `newton/_src/solvers/**` for a solver-capability entry → topic matches.\n\n**Tier-2 heuristic (only if `gh` CLI is installed + authenticated):**\n\nFor each GH ref, run `gh issue view <num> --json title,body`. Compare the issue's title/topic to the entry's description. If clearly unrelated (e.g., issue is \"Improve MuJoCo solver performance\", entry is \"Add USD tetmesh import\"), flag.\n\nSkip tier-2 silently if `gh` is absent or auth fails.\n\n### 🕵️ Private-only symbol\n\nFlag `### Added` entries whose named public symbol exists only under `newton._src.*` at HEAD and is not re-exported through a public module (see `classification-rules.md` for the module list).\n\nExample flag:\n\n> Add `newton.geometry.compute_offset_mesh()` for extracting offset surface meshes.\n> *Check:* grep `newton/geometry.py` at HEAD. If `compute_offset_mesh` is not re-exported, raise 🕵️. If it is (the expected case), no flag.\n\nRationale: `CODING_GUIDELINES.rst` forbids examples and docs from importing `newton._src`. A user-facing symbol that lives only in `_src` cannot be used by Newton's own examples and is a maintenance liability.\n\n### ⬆️ Missing migration guidance (Newton-specific)\n\n`changelog/README.md`: for `Deprecated`, `Changed`, and `Removed` entries, include migration guidance such as \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n\nFlag `### Deprecated`, `### Removed`, and `### Changed` entries that name a rename / removal / reorder but do NOT express migration direction. Direction can be expressed with one of these phrases (case-insensitive): `use`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`, `prefer`. The phrase must identify a non-empty replacement target, normally as a backtick-delimited symbol. Direction can also be expressed structurally — an imperative `Rename X to Y`, an arrow `X → Y`, or a parameter-rename table — which counts as migration guidance even when none of the listed phrases appear verbatim (see the `ModelBuilder.add_shape_ellipsoid` example below).\n\nFlag:\n\n> Remove `SolverXPBD.legacy_substep()`.\n> *Reason:* no migration guidance. User does not know which method replaces it.\n>\n> Deprecate `Model.geo_meshes`.\n> *Reason:* no replacement named. Should read \"Deprecate `Model.geo_meshes` in favor of `Model.shapes`.\"\n>\n> Remove `Model.foo`; switch to improve performance.\n> *Reason:* \"switch to\" does not name a replacement target.\n\nDon't flag:\n\n> Deprecate `SensorContact.net_force` in favor of `SensorContact.total_force` and `SensorContact.force_matrix`\n> *Reason:* migration guidance present (\"in favor of ...\").\n>\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`. Old names are still accepted as keyword arguments but emit a `DeprecationWarning`\n> *Reason:* rename is explicit and the old-name behavior is documented.\n\n### 🏷️ Naming-convention drift (Newton-specific)\n\n`CODING_GUIDELINES.rst`: \"Prefix-first naming for autocomplete: `ActuatorPD` (not `PDActuator`), `add_shape_sphere()` (not `add_sphere_shape()`).\"\n\nFlag `### Added` entries whose newly-named public symbol puts the discriminator before the prefix. Examples of names to flag:\n\n- `PDActuator`, `VelocityActuator` → should be `ActuatorPD`, `ActuatorVelocity`\n- `SphereShape`, `CapsuleShape` → should be `ShapeSphere`, `ShapeCapsule`\n- `add_sphere_shape()`, `add_mesh_shape()` → should be `add_shape_sphere()`, `add_shape_mesh()`\n\nBefore flagging, cross-check against existing sibling symbols in the same module. If the rest of the module uses `Foo<Kind>` rather than `<Kind>Foo`, the new symbol should match the established pattern whichever direction it goes. Prefer consistency over a mechanical reading of the rule when the module has an entrenched local convention; call out the exception to `CODING_GUIDELINES.rst` explicitly.\n\n## Judgment philosophy\n\n**Err on \"mention, don't block\"**: flagging should raise a question for human review, not gate the report. The audit appendix shows flagged entries and a one-line reason; a human decides.\n\n**Don't auto-rewrite**: The audit flags the entry, never modifies it. Before the\nTowncrier build, the release manager updates pending fragments during changelog\nmaintenance; after release, corrections to dated history require explicit\nmaintainer approval.\n\n**Prefer false positives over false negatives**: a flag that turns out to be fine costs a 5-second eyeball. A missed wrong-ref or jargon-leak ships to users.\n\n**Exception for 🚨 policy flags.** The `🚨 Policy: removed without prior deprecation` flag (Phase 4d) is NOT a false-positive-tolerant flag. Only raise it after both an exhaustive search of prior released CHANGELOG sections and a targeted code search at the base ref fail to find deprecation evidence. A matching runtime `DeprecationWarning` satisfies the deprecation-window policy even when the CHANGELOG entry was forgotten; flag that case as `🧾 Deprecation omitted from CHANGELOG` instead.\n\n## Row format (for the report)\n\n| Entry (excerpt) | Flag | Why |\n|---|---|---|\n| \"Inline a `wp.vec3`-specialized ...\" | 🗣️ Internal language | References `warp.fem.geometry.closest_point` in user-facing prose |\n| \"Fix crash\" | 📝 Too terse | 2 words, no context link |\n| \"Add `newton.foo.bar` (GH-NNNN)\" | 🔗 Wrong ref? | Commits tagged GH-NNNN touch only CI files |\n| \"Deprecate `Model.foo`\" | ⬆️ Missing migration guidance | No \"in favor of\" replacement named |\n| \"Add `PDActuator`\" | 🏷️ Naming-convention drift | Should be `ActuatorPD` per prefix-first rule |\n| \"Add `newton.utils._x`\" | 🕵️ Private-only | Named symbol lives only in `newton._src`, not re-exported |\n| \"Remove deprecated `Model.foo`\" | 🧾 Deprecation omitted from CHANGELOG | Runtime warning exists at the base ref, but no released Deprecated entry records it |\n\nEntry excerpt should be ~60-80 chars so the table stays scannable. Keep the full entry text in the detail sections (never truncate there).\n\n<!-- File: .agents/skills/release-audit/references/render-rules.md (Tokens: ~2260 | Category: anthropic-skill) -->\n# Rendering Rules\n\nThis reference is loaded during Phase 7b of the release-audit skill. It defines the hard constraints and conventions for how the report is formatted when the template is filled in. Phase-flow logic lives in `SKILL.md`; this file is pure reference material.\n\n## Key rendering rules\n\n- Full commit URLs: `https://github.com/newton-physics/newton/commit/<full-sha>`.\n- Full issue URLs: `https://github.com/newton-physics/newton/issues/<num>`.\n- Preserve `diff` fence blocks for signature diffs.\n- Anomaly banner appears ONLY if any commit has `main_equivalent_sha: null`.\n- **Table of contents** sits immediately after the Release Highlights section (so the front matter reads: scope → version control → counts → bake → highlights → TOC → body). Link every top-level `##` section and every per-symbol / per-topic `###` heading under them.\n- **Document Version Control** appears near the top after the report scope metadata. For gist revisions, summarize the immediately preceding revision's audited head and commit count, list only materially changed report sections, and direct prior reviewers to those sections. Keep the report body current by replacing superseded conclusions rather than retaining them as history. For first publication, label it as the initial report. Include the section in the table of contents.\n- **Behavioral & Support Changes** section: group by topic with short descriptive titles (e.g., \"Deterministic contact ordering\", \"Dependency pins\", \"Build requirements\"). The audit synthesizes the titles from the entry content.\n- **Dependency & License Audit** section: render immediately after Behavioral & Support Changes and before Fixed. Use one complete `scripts/license_audit.py` output as-is except for global output-style cleanup. Never combine tables from a `--skip-pypi` run with prose from a separate live query. If a live host-side run succeeds, it replaces the entire deferred result. Keep uncertainty text such as \"not checked\", \"not evaluated (--skip-pypi)\", or \"not declared\"; do not replace it with guessed license metadata.\n- **Existing resolved package license cells stay concise.** Preserve standard license expressions and review statuses emitted by the helper. For legacy or verbose nonstandard values, keep the helper's package-metadata link instead of copying full license text into the report.\n- **Existing resolved package changes stay collapsed.** Keep the Existing Resolved Package Version-Set Changes table inside the helper's closed GFM `<details>` block. Leave the subsection heading and row-count summary visible, but do not add the `open` attribute; readers expand the long table only when needed.\n- **Experimental is a neutral stability label.** Never attach a warning emoji merely because an API is experimental. In Breaking Changes, use `Experimental:` without an emoji. Reserve `⚠️` for stable API or behavior changes that need an explicit acceptability review, and `🚨` for policy violations. The mixed Breaking Changes section heading itself has no warning emoji.\n- **Release highlights are significance-gated.** Keep 3-6 release-defining capabilities, workflows, broad behavioral shifts, or material compatibility decisions. Breaking or experimental status alone is not enough; omit routine deprecation cleanup, narrow signature changes, and minor dependency metadata follow-ups from highlights.\n\n## Output style — hard constraints on the generated report\n\n1. **No em dashes (`—`) anywhere in the report output.** Use colons, parentheses, or rewrite the sentence. This includes headings, bullet points, table cells, prose. Check every line before writing.\n\n2. **No internal skill terminology in the output.** The reader does not know what \"Phase 4f\", \"Phase 5a\", \"tier-1 heuristic\", or similar skill-internal names refer to. If a section needs explanation of how flags were produced, write it in plain user terms (e.g., \"Flagged because commits tagged with this GH ref don't touch any solver code\" instead of \"Tier-1 topic mismatch from Phase 5a\").\n\n3. **No mention of previously-shipped patch-release fixes.** The commit-list tool already scopes to `<base>..<head>`, so patch-release content is excluded automatically; do not manufacture a comparison to it.\n\n4. **No \"end of report\" or similar terminal markers.** The last section is the last section. No \"— end —\", no \"Thanks for reading\", no concluding paragraph, no closing quote.\n\n5. **Every GH ref is a markdown hyperlink** to `https://github.com/newton-physics/newton/issues/NNNN`. Plain-text `GH-NNNN` tokens, paren-grouped lists like `(GH-1287, GH-1298, ...)`, and shorthand like `(multiple GHs)` / `(see CHANGELOG)` are NOT acceptable, even when many refs bunch into one bullet or cell.\n\n6. **Signature and docstring render as a single fenced code block**, shaped like Python source so users see them in one glance. The exact shape depends on the kind of symbol.\n\n   **Functions and methods:**\n\n   ```python\n   newton.geometry.compute_offset_mesh(shape: ShapeFlags, offset: float) -> Mesh\n   \"\"\"Extract the offset surface mesh of a collision shape.\n\n   Longer description if present in the real docstring.\n   \"\"\"\n   ```\n\n   **Classes with only a constructor** (simple data holders or context managers):\n\n   ```python\n   class TetMesh:\n       \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n       Longer description if present.\n       \"\"\"\n\n       def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n   ```\n\n   **Classes with additional public methods**: list EVERY public (non-dunder, non-leading-underscore) method with its signature, plus the class docstring and each method's docstring if present. Do not just show `__init__`.\n\n   ```python\n   class SolverXPBD:\n       \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n       Short description of the solver's scope and typical use.\n       \"\"\"\n\n       def __init__(self, model: Model, iterations: int = 10)\n\n       def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n       \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n       def update_contacts(self, contacts: Contacts) -> None\n       \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n   ```\n\n   **Enum / IntEnum / IntFlag classes:** list every member with its integer value and its attribute docstring or comment, plus the class docstring. Do not show a constructor for enums.\n\n   ```python\n   class ShapeFlags(IntFlag):\n       \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n       VISIBLE = 1 << 0\n       \"\"\"Shape is rendered by viewers.\"\"\"\n\n       COLLIDE_SHAPES = 1 << 1\n       \"\"\"Shape participates in shape-shape collision.\"\"\"\n   ```\n\n   Extract member docstrings from the source using `ast` attribute-docstring form (`\"\"\"...\"\"\"` immediately following the assignment). If the member uses a `#:` comment or a trailing `#` comment, preserve that instead. If there is no per-member doc, show the member without one.\n\n   Do NOT separate \"Signature\" and \"Docstring\" into two headed subsections. Do NOT blockquote the docstring line by line; it lives inside the code block as Python source.\n\n7. **API summary tables** include a Description column AND a short-form signature in the Symbol cell. The Symbol cell shows the call shape WITHOUT type annotations so readers can skim the args at a glance. Defaults ARE included. The column order for New API tables is: `Symbol | Description | GH | Bake`. Examples of Symbol cells:\n\n   - Function: `newton.geometry.compute_offset_mesh(shape, offset)`\n   - Method: `SolverXPBD.update_contacts(contacts)`\n   - Class with constructor: `newton.TetMesh(vertices, tets)`\n   - Enum / flag (no call form): `newton.ShapeFlags`\n   - Decorator: `@newton.experimental`\n\n   Description is a short (≤ 10 word) phrase summarizing what the symbol does, pulled from the first sentence of its docstring or the CHANGELOG entry.\n\n8. **New API tables are grouped by Kind.** Render one table per Kind (\"Functions\", \"Classes\", \"Methods on existing classes\", \"Enums / flags\", \"Examples\"). Newton's \"Examples\" kind specifically covers additions under `newton/examples/**` that ship a user-runnable `python -m newton.examples <name>` entry.\n\n9. **Changes-to-Existing-API table columns**: `API | Kind | Breaking | Description | GH | Commits | Bake`. The API cell uses the same short-form call-shape convention as rule 7 (parameter names + defaults, no annotations). Description is a short phrase. Kind values include: `signature change`, `new parameter`, `capability extension`, `rename` (Newton-specific), `parameter reorder` (Newton-specific), `removed`, `deprecated`, `semantic change`. For any entry tagged experimental in Phase 4g, the Breaking cell reads `Experimental`. For any Removed entry, the Description also includes the deprecation-window fact from Phase 4d, using either the released CHANGELOG version (for example, \"Deprecated in 1.0.0; removed here.\") or the base-ref runtime-warning evidence.\n\n   **Bake-cell format (tables only).** Render the Bake column as `🟢 47d`, `🟡 12d`, `🟠 4d` — emoji, space, number-and-`d` joined with no intervening space. The joined `<N>d` form keeps the bucket/duration pair on one line when a narrow Markdown table wraps. For per-symbol detail blocks and prose, continue to spell out `🟢 47 days in main`; the compact form is for table cells only.\n\n10. **Audit appendix rendering is conditional.** If only one of the audit sections (CHANGELOG-orphan entries / language-review flags / Phase 4f semantic-review candidates) has any content, do not render an \"Audit Appendix\" umbrella heading. Just render the non-empty sections with their own top-level headings (e.g., `## CHANGELOG Review Notes`, `## Semantic-Change Review Candidates`). Only use an umbrella when two or more subsections are non-empty.\n\n11. **No Phase names anywhere.** If the report needs to explain a flag, write it in user-facing terms. Never write \"Phase 4e\", \"Phase 5\", etc.\n\n12. **Dependency/license section is always rendered.** If there are no package-name changes or in-tree notice changes, keep the helper's no-change sentence. Do not drop the section, because release managers use it as evidence that the audit ran.\n\n<!-- File: .agents/skills/release-audit/references/report-template.md (Tokens: ~5909 | Category: anthropic-skill) -->\n# Newton {{VERSION_STRING}} {{REPORT_KIND}} Report\nGenerated: {{REPORT_DATE}}\n\n<!-- {{REPORT_KIND}} is \"Pre-Release\", \"Release Candidate\", or \"Retrospective\",\n     chosen in Phase 1 from the argument, version string, and head ref.\n     {{VERSION_STRING}} is the raw version (e.g. \"1.2.0.dev0\" for pre-release,\n     \"1.2.0rc1\" for RC, \"1.1.0\" for retrospective). -->\n\n- Mode: {{MODE_DESCRIPTION}}\n- Head: {{HEAD_REF}} @ `{{HEAD_SHA_SHORT}}`\n- Base: {{BASE_REF}} @ `{{BASE_SHA_SHORT}}`\n- Commits in range: {{N_COMMITS}}\n\n<!-- {{MODE_DESCRIPTION}} is a one-liner:\n     Pre-release: \"Pre-release audit of unreleased work on main\"\n     RC: \"Release candidate readiness review (release branch cut)\"\n     Retrospective: \"Retrospective audit of shipped release v<version>; calibration\n                     pass cross-references the audit's flags against post-target history\" -->\n\n## Document Version Control\n\n{{DOCUMENT_VERSION_CONTROL}}\n\n<!-- Keep this section short and reviewer-oriented.\n\n     For a first publication, state that this is the initial report and name the\n     audited head and commit count.\n\n     For a revised gist, compare the prior report's audited head and commit count\n     with the current values, then list only the report sections whose conclusions\n     materially changed. Tell prior reviewers where to focus. End by stating that\n     every other finding was revalidated and that the report body contains only\n     current conclusions rather than retaining superseded text.\n\n     Do not use this section as a historical changelog. Gist history preserves old\n     revisions; this section is a compact review map for the immediately preceding\n     revision. -->\n\n\n**Headline counts**\n\n- {{N_NEW_API}} new public APIs\n- {{N_BREAKING}} breaking changes\n- {{N_CHANGED}} changes to existing API\n- {{N_BEHAVIORAL}} behavioral / support changes\n- {{N_FIXED}} fixes\n- {{N_EXAMPLES}} new examples\n\n**Bake distribution**\n\n| Bucket | Commits |\n|---|---:|\n| 🟢 > 14 days in main | {{N_BAKE_GREEN}} |\n| 🟡 7 to 14 days | {{N_BAKE_YELLOW}} |\n| 🟠 < 7 days | {{N_BAKE_ORANGE}} |\n\n{{ANOMALY_BANNER_IF_ANY}}\n\n<!-- Anomaly banner appears ONLY when any commit has main_equivalent_sha: null. Example:\n     > ⚠️ **N commits in the release have no equivalent on main. Investigate: these\n     > shipped without nightly/main-branch bake.**\n-->\n\n---\n\n## Release highlights\n\n{{HEADLINE_SUMMARY}}\n\n<!-- The audit's qualitative synthesis of what would land in the official release\n     notes. Drafted in Phase 7a. NOT release notes: a reviewer's preview so the\n     release manager can see at a glance whether the real release notes will\n     match expectations and spot items that need a keep/defer decision.\n\n     Shape: one short intro paragraph (2-3 sentences) followed by 3-6 bulleted\n     highlight items. Each bullet starts with a bold 2-6 word headline, then a\n     colon and a one-sentence rationale (what it is and why it matters).\n\n     Include status/risk markers inline only when they apply:\n       - 🟠 `N days` bake (if the headline item's minimum bake is < 7 days)\n       - Experimental (neutral label, no warning emoji, and only when the item\n         independently clears the significance bar)\n       - ⚠️ Stable change (a non-experimental API or behavior change that needs\n         a deeper release-manager acceptability decision)\n\n     Do NOT include counts (\"4 new APIs were added\"): that's already in the\n     headline counts block above. Highlights are qualitative.\n     Do NOT promote an item only because it is breaking or experimental. Routine\n     compatibility removals after a valid deprecation window, narrow signature\n     shifts, and dependency metadata follow-ups belong in the detailed sections.\n\n     Example shape (do NOT copy verbatim; pick items that are actually headline\n     material in THIS release):\n\n     Newton 1.2 lands Gaussian splat geometry, deterministic contact ordering, and\n     a new texture-based SDF pipeline that replaces NanoVDB for mesh-mesh collision.\n     One stable default change needs an explicit acceptability decision before cut.\n\n     - **Gaussian splat geometry** ([GH-NNN](...)): `Gaussian`, `ModelBuilder.add_shape_gaussian()`,\n       and USD import unlock radiance-field-style rendering as a first-class shape.\n       🟢 30 days bake.\n     - **Deterministic contact ordering** ([GH-NNN](...)): `deterministic` flag on\n       `CollisionPipeline` and `NarrowPhase` makes contact output GPU-thread-schedule\n       independent via radix sort and fingerprint tiebreaking. Required for reproducible\n       RL training. 🟢 22 days bake.\n     - **Texture-based mesh SDF** ([GH-NNN](...), [GH-NNN](...)): replaces NanoVDB\n       volumes in the mesh-mesh collision pipeline; faster and CPU-compatible. Every\n       GH ref is an individual hyperlink; never collapse to \"(multiple GHs)\" or a\n       plain-text comma list.\n     - **⚠️ Stable change: particle contacts enabled by default** ([GH-NNN](...)):\n       existing scenes can change trajectories, so the release manager should confirm\n       the new default and preservation path are acceptable.\n     - **Experimental: differentiable rigid contacts** ([GH-NNN](...)): gradients\n       with respect to body poses via `CollisionPipeline` when `requires_grad=True`;\n       contact-pipeline API may change in 1.3.\n     - **RJ45 plug-socket insertion example**: demonstrates SDF contacts, latch joint,\n       and interactive gizmo; release notes should lead with the showcase.\n-->\n\n---\n\n## Contents\n\n{{CONTENTS_BULLETS}}\n\n<!--\nExpand the TOC to include every `###` heading rendered in the body, not\njust the `##` top-level sections. List each per-symbol / per-topic heading\nas a sub-bullet under its parent section. Example shape (replace with the\nreal symbols / topics present in this specific report):\n\n- [Document Version Control](#document-version-control)\n- [New API](#new-api)\n  - [`newton.<symbol>`](#newtonsymbol)\n  - [`newton.<submodule>.<symbol>`](#newtonsubmodulesymbol)\n  - ...\n- [Breaking Changes](#breaking-changes)\n  - per-entry heading as sub-bullet\n- [Changes to Existing API](#changes-to-existing-api)\n  - per-entry heading as sub-bullet\n- [Behavioral & Support Changes](#behavioral--support-changes)\n  - per-topic heading as sub-bullet\n- [Dependency & License Audit](#dependency--license-audit)\n- [Schema & Importer Support](#schema--importer-support)\n- [Fixed](#fixed)\n- [Calibration Notes](#calibration-notes) (retrospective mode only)\n  - per-flag-class sub-bullet\n- [CHANGELOG Review Notes](#changelog-review-notes) (only if the conditional\n  appendix renders content)\n\nThe sample symbol names above are illustrative placeholders; do NOT ship them\nas-is. GitHub auto-renders a floating outline panel, but an explicit TOC\nstill helps raw-text readers.\n-->\n\n---\n\n## New API\n\n{{NEW_API_TABLES_BY_KIND}}\n\n<!-- Render one summary table per Kind. Columns: Symbol | Description | GH | Bake.\n     Kind groupings for Newton: \"Functions\", \"Classes\", \"Methods on existing classes\",\n     \"Enums / flags\", \"Constants\", \"Examples\". If only one Kind has entries, one\n     table is fine.\n\n     The Symbol cell uses a short-form call shape (no type annotations; defaults\n     included). Examples:\n     - `newton.geometry.compute_offset_mesh(shape, offset)`\n     - `newton.TetMesh(vertices, tets)`\n     - `SolverXPBD.update_contacts(contacts)`  (method on existing class)\n     - `newton.ShapeFlags`  (no parens for enums, decorators)\n     - `newton.examples.basic_pendulum`  (example module; the Symbol cell links to\n       the runnable name `python -m newton.examples basic_pendulum`). -->\n\n{{NEW_API_DETAIL_BLOCKS}}\n\n<!-- Per-symbol block template. Headings use the symbol name alone (no colons/em dashes).\n     The single fenced code block underneath holds signature-shaped content and\n     the docstring.\n\nSimple data class (constructor-only rendering):\n\n### `newton.TetMesh`\n\nLinks: [GH-NNN](...), commits: [abc1234](...), [def5678](...)\nSource: `newton/_src/geometry/tetmesh.py`\nBake: 🟢 47 days in main\n\n```python\nclass TetMesh:\n    \"\"\"Tetrahedral mesh geometry for soft-body simulation.\n\n    Holds per-vertex positions and per-tet index quads; builders accept this\n    shape via ModelBuilder.add_shape_tetmesh.\n    \"\"\"\n\n    def __init__(self, vertices: wp.array[wp.vec3], tets: wp.array[wp.vec4i])\n```\n\nClass with multiple public methods (interface-style): list every public method\nwith its signature and docstring, not just __init__.\n\n### `newton.solvers.SolverXPBD`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 30 days in main\n\n```python\nclass SolverXPBD:\n    \"\"\"Position-based-dynamics solver with XPBD constraints.\n\n    Supports rigid bodies, particles, cloth, and soft-body elements with a\n    common substepping loop.\n    \"\"\"\n\n    def __init__(self, model: Model, iterations: int = 10)\n\n    def step(self, state_in: State, state_out: State, control: Control, dt: float) -> None\n    \"\"\"Advance the simulation by dt seconds.\"\"\"\n\n    def update_contacts(self, contacts: Contacts) -> None\n    \"\"\"Populate contacts.force with per-contact spatial forces from XPBD impulses.\"\"\"\n```\n\nEnum / IntFlag: list every member with its value and per-member doc.\n\n### `newton.ShapeFlags`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/geometry/flags.py`\nBake: 🟡 12 days in main\n\n```python\nclass ShapeFlags(IntFlag):\n    \"\"\"Flags controlling collision and visibility of a shape.\"\"\"\n\n    VISIBLE = 1 << 0\n    \"\"\"Shape is rendered by viewers.\"\"\"\n\n    COLLIDE_SHAPES = 1 << 1\n    \"\"\"Shape participates in shape-shape collision.\"\"\"\n\n    COLLIDE_GROUND = 1 << 2\n    \"\"\"Shape participates in ground-plane collision.\"\"\"\n```\n\nMethod added to an existing class: the heading names the fully-qualified\nmethod path. The fenced block shows only that method, not the whole class.\n\n### `newton.solvers.SolverXPBD.update_contacts`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/_src/solvers/xpbd.py`\nBake: 🟢 21 days in main\n\n```python\ndef update_contacts(self, contacts: Contacts) -> None\n\"\"\"Populate contacts.force with per-contact spatial forces.\n\nDerives linear force and torque [N, N·m] from XPBD constraint impulses\naccumulated during the most recent step. Call after step().\n\"\"\"\n```\n\nExample (runnable under `python -m newton.examples <name>`): the Source cell\npoints to the example module; list the one-liner user invocation and the\nheadline simulation topic.\n\n### `newton.examples.robot.example_robot_humanoid`\n\nLinks: [GH-NNN](...), commit: [sha](...)\nSource: `newton/examples/robot/example_robot_humanoid.py`\nBake: 🟢 19 days in main\n\nRun:\n\n```\npython -m newton.examples example_robot_humanoid\n```\n\nShort paragraph explaining what the example demonstrates (the solver used,\nwhat the user will see, any dependencies like MuJoCo assets).\n-->\n\n---\n\n## Breaking Changes\n\n{{BREAKING_ENTRIES}}\n\n<!-- Flat list. Do NOT group under \"Author-labeled\" / \"Unlabeled\" / \"Semantic\"\n     subheadings. Every entry is simply a confirmed breaking change, regardless\n     of how it was identified. The audit collects entries from four sources:\n     (1) CHANGELOG Changed entries whose prose describes a rename / parameter\n         reorder / signature shift (Newton does not use a **Breaking:** marker;\n         recognition is prose-based),\n     (2) CHANGELOG Removed entries (implicitly breaking; flag as 🚨 Policy only\n         if neither a prior Deprecated entry nor a matching runtime warning at\n         the base ref is found),\n     (3) public-surface AST diffs between base and HEAD that aren't covered by\n         a CHANGELOG Changed / Removed entry,\n     (4) solver / integrator / math / geometry commits whose diff the audit reads\n         as clearly semantic-shifting (a numerical-output shift that a user\n         would observe). Ambiguous candidates go to \"Semantic-Change Review\n         Candidates\" in the review notes, NOT here.\n\n     Warning semantics:\n     - Prefix a non-experimental entry heading with `⚠️` when the stable API or\n       behavior change needs a deeper acceptability decision (for example, a\n       changed default, output semantics, or unshimmed signature shift).\n     - Prefix experimental entry headings with `Experimental:` and no warning\n       emoji. Their looser compatibility contract is context, not an alarm.\n     - Planned removals after a valid shipped deprecation window need no warning\n       emoji unless their breadth or remaining migration risk warrants review.\n     - Keep `🚨 Policy` for removals with no prior deprecation evidence.\n\n     Per-entry render format:\n\n     ### <heading: symbol name or short descriptive title>\n\n     Links: [GH-NNN](...), commit(s): [sha](...). 🟢 N days baked in main.\n\n     [If signature diff applies, a fenced diff block.]\n     [If behavior shift, a before/after code snippet synthesized from the diff\n      and the commit message.]\n\n     [1-3 sentences of explanatory prose in plain user-facing language.]\n\n     [Full CHANGELOG text blockquoted, if the entry came from CHANGELOG.]\n\n     [For removals backed only by a runtime warning at the base ref: a one-line\n      deprecation-window note plus a non-blocking CHANGELOG documentation flag.]\n\n     [For 🚨 Policy: removed without prior deprecation entries: a one-line\n      callout stating that neither released CHANGELOG nor base-ref code contains\n      deprecation evidence and what the release manager should do about it.]\n\n     Illustrative example (do not copy verbatim):\n\n     ### `ModelBuilder.add_shape_gaussian` parameter reorder\n\n     Links: [GH-NNN](https://github.com/newton-physics/newton/issues/NNN),\n     commit: [abc1234](https://github.com/newton-physics/newton/commit/abc1234). 🟢 22 days baked in main.\n\n     The `xform` argument now precedes `gaussian` to match every other\n     `add_shape_*` method on `ModelBuilder`. Callers that relied on positional\n     arguments must switch to keyword form. Passing a `Gaussian` as the second\n     positional argument still works but emits a `DeprecationWarning`.\n\n     Before:\n     ```python\n     builder.add_shape_gaussian(body_idx, gaussian, xform=my_xform)\n     ```\n\n     After:\n     ```python\n     builder.add_shape_gaussian(body_idx, xform=my_xform, gaussian=gaussian)\n     ```\n-->\n\n---\n\n## Changes to Existing API\n\n<!-- Covers CHANGELOG Changed, Removed, Deprecated, plus capability extensions\n     routed here from the new-API classification pass (e.g., \"Add support for X\n     in existing Y\"). -->\n\n{{CHANGED_SUMMARY_TABLE}}\n\n<!-- Columns: API | Kind | Breaking | Description | GH | Commits | Bake\n     Kind values: signature change, new parameter, capability extension, rename,\n     parameter reorder, removed, deprecated, semantic change. Description is a\n     short phrase (≤ 10 words). Breaking cell values: Yes / No / Experimental. -->\n\n{{CHANGED_DETAIL_BLOCKS}}\n\n<!-- Per-entry template (signature change). Use a colon in the heading, not an em dash.\n\n### `SolverMuJoCo`: new `enable_multiccd` parameter\n\nBreaking: **No** (additive keyword-only default)\nLinks: [GH-NNN](...), commit: [5c5f67e9](...)\nBake: 🟢 38 days in main\n\n```diff\n- def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True)\n+ def __init__(self, model: Model, ..., use_mujoco_contacts: bool = True, enable_multiccd: bool = False)\n```\n\n**From CHANGELOG**\n> Add `enable_multiccd` parameter to `SolverMuJoCo` for multi-CCD contact generation\n> (up to 4 contact points per geom pair).\n\nCapability extension (existing API gains a new option/behavior):\n\n### `ModelBuilder.add_shape_*`: per-shape color\n\nLinks: [GH-NNN](...), commit: [abcdef12](...)\nBake: 🟢 35 days in main\n\nEvery `add_shape_*` method gains a `color=` keyword argument; `Model.shape_color`\nholds the authored per-shape display color for runtime edits; mesh shapes fall\nback to `Mesh.color` when available.\n\n```diff\n- def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True)\n+ def add_shape_sphere(self, body: int, radius: float, ..., is_visible: bool = True, color: Vec3 | None = None)\n```\n\n**From CHANGELOG**\n> <full CHANGELOG text blockquoted>\n\nRename (Newton-specific kind, soft deprecation via DeprecationWarning):\n\n### `ModelBuilder.add_shape_ellipsoid`: parameter rename\n\nBreaking: **Yes** (source break if old names used positionally)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 28 days in main\n\n```diff\n- def add_shape_ellipsoid(self, body: int, a: float, b: float, c: float, ...)\n+ def add_shape_ellipsoid(self, body: int, rx: float, ry: float, rz: float, ...)\n```\n\nOld names `a`, `b`, `c` are still accepted as keyword arguments but emit a\n`DeprecationWarning`. Positional callers must switch to keyword form.\n\n**From CHANGELOG**\n> Rename `ModelBuilder.add_shape_ellipsoid()` parameters `a`, `b`, `c` to `rx`, `ry`, `rz`.\n> Old names are still accepted as keyword arguments but emit a `DeprecationWarning`.\n\nRemoved symbol:\n\n### `Model.geo_meshes`: removed\n\nLinks: [GH-NNN](...), commit: [sha](...)\nDeprecation window: Deprecated in 1.0.0; removed here.\n\n```diff\n- geo_meshes: list[Mesh]\n```\n\n**From CHANGELOG (prior deprecation in 1.0.0)**\n> Deprecate `Model.geo_meshes` in favor of `Model.shapes`. Will be removed in a\n> future release.\n\n**From CHANGELOG (removal)**\n> <full CHANGELOG text blockquoted>\n\nExperimental-softened entry (symbol was shipped as experimental in a prior release; change here is technically source-breaking but the stability bar was advertised up front):\n\n### `SensorTiledCamera`: RenderContext reorganization\n\nBreaking: **Experimental** (since 1.0.0)\nLinks: [GH-NNN](...), commit: [sha](...)\nBake: 🟢 40 days in main\n\n`SensorTiledCamera` landed as an experimental sensor in 1.0.0; this release\nsplits `RenderContext` into `RenderConfig` (config types) and `utils` (runtime\naccess), deprecates the old names, and adjusts default Gaussian sorting modes.\n\n```diff\n- class SensorTiledCamera:\n-     render_context: RenderContext\n+ class SensorTiledCamera:\n+     render_config: RenderConfig\n+     utils: SensorTiledCameraUtils\n```\n\n**From CHANGELOG (1.0.0 introduction, still experimental)**\n> Add `SensorTiledCamera` (experimental): GPU-tiled camera sensor for multi-agent RL.\n\n**From CHANGELOG (this release)**\n> <full CHANGELOG text blockquoted>\n-->\n\n---\n\n## Behavioral & Support Changes\n\n<!-- Group by topic with short descriptive section headings synthesized from\n     the entry content. Use colons in headings if separation is needed.\n     Related topics should live together.\n\n     Example headings (illustrative, choose based on actual content):\n     - \"Python minimum version bumped\"\n     - \"MuJoCo / mujoco-warp dependency pins\"\n     - \"Deterministic contact ordering\"\n     - \"USD import: visibility honored\"\n     - \"Mesh SDF construction: parity path\"\n     - \"Asset pinning for reproducible builds\"\n\n     Each topic: a short paragraph summary, links, commits, bake. -->\n\n{{BEHAVIORAL_SECTIONS}}\n\n---\n\n## Dependency & License Audit\n\n{{DEPENDENCY_LICENSE_AUDIT}}\n\n<!-- Render the markdown emitted by scripts/license_audit.py. This section is\n     always present. It compares direct dependencies, resolved lockfile package\n     names, version changes, and declared license-file pathspecs across the\n     release range. Use one complete helper result; never combine a\n     `--skip-pypi` table with prose from a separate live query. Preserve \"not\n     checked\", \"not evaluated (--skip-pypi)\", and \"not declared\" license\n     metadata exactly when package-index lookup was unavailable, deferred, or\n     inconclusive. Keep the helper's Existing Resolved Package Version-Set\n     Changes table inside its closed `<details>` block so the long table is\n     collapsed by default. -->\n\n---\n\n## Schema & Importer Support\n\n{{SCHEMA_IMPORTER_SUPPORT}}\n\n<!-- Render the Phase 4h table, or state that no relevant features were found. -->\n\n---\n\n## Fixed\n\n{{FIXED_TABLE}}\n\n<!-- Columns: Fix | GH | Commits | Bake\n     Keep the full CHANGELOG text in the Fix column; no truncation.\n     Do NOT mention fixes from previously-shipped patch releases. The commit-list\n     tool scopes to <base>..<head> so those are already excluded. -->\n\n{{CALIBRATION_NOTES}}\n\n<!-- Retrospective mode only. Pre-release / RC mode must leave\n     {{CALIBRATION_NOTES}} empty (template consumers should strip the whole\n     placeholder line, not leave a stray section heading).\n\n     Retrospective mode renders a ## Calibration Notes section here, immediately\n     after Fixed and before the optional audit appendix. Shape:\n\n     ## Calibration Notes\n\n     One-paragraph headline: overall validated / invalidated / unresolved counts\n     across all flag classes, plus a one-sentence takeaway on what the calibration\n     suggests about skill precision for this release.\n\n     ### 🚨 Missing-deprecation\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `Model.foo` | Validated | No prior Deprecated entry or matching runtime warning at the base ref; symbol stayed removed through 1.1.2. |\n     | `Model.bar` | Invalidated | Deprecated in 1.0.0 under `### Deprecated` — the audit's search missed it (lowercase `model.bar` in the entry). |\n\n     ### 🕵️ Private-only\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n     | `newton._src.utils._helper` | Validated | Re-exported as `newton.utils.helper` in [1.1.1](commit-link). |\n\n     ### ⬆️ Missing-migration-guidance\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### 🏷️ Naming-convention drift\n\n     | Flag subject | Outcome | Evidence |\n     |---|---|---|\n\n     ### Semantic-change review candidates\n\n     | File / feature | Outcome | Evidence |\n     |---|---|---|\n     | `newton/_src/solvers/xpbd.py` contact-ordering diff | Validated | [1.1.1](commit-link) fixes \"convergence regression on stacked bodies\" — consistent with the flagged change's hypothesis. |\n\n     ### Deprecation follow-through\n\n     | Deprecated in this release | Followed through | Evidence |\n     |---|---|---|\n     | `Model.geo_meshes` | Followed through in 1.2.0 | Removed entry cites `Use Model.shapes`; matches the promised migration path. |\n     | `SensorContact.net_force` | Still deprecated | Symbol remains in the public surface through 1.2.1 with DeprecationWarning. |\n\n     Closing note (one or two sentences): what the calibration tells the reader\n     about Newton's release hygiene for this specific release.\n-->\n\n---\n\n{{OPTIONAL_APPENDIX}}\n\n<!-- Render conditionally based on content and wrap each non-empty section in\n     a GFM <details> block so it collapses by default (the umbrella content is\n     reference material, not headline reading).\n\n     Three cases:\n\n     1. Both CHANGELOG-orphan list AND language-review flags are empty:\n        Render nothing. No appendix heading, no trailing section.\n\n     2. Exactly ONE is non-empty: Render that one as a top-level section\n        (no \"Audit Appendix\" umbrella) with the table inside <details>.\n\n        ## CHANGELOG Entries Without Matching Commits\n        <details>\n        <summary>N entries (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        | full entry text | ... | ... |\n\n        </details>\n\n     3. Both are non-empty: Render an umbrella section; each subsection gets\n        its own <details>.\n\n        ## Audit Appendix\n\n        <details>\n        <summary>N CHANGELOG entries without matching commits (click to expand)</summary>\n\n        | Entry | GH refs | Suspected reason |\n        |---|---|---|\n        ...\n\n        </details>\n\n        <details>\n        <summary>N CHANGELOG entries flagged for review (click to expand)</summary>\n\n        | Entry | Flag | Why |\n        |---|---|---|\n        ...\n\n        </details>\n\n     Column rules for BOTH tables: full entry text (no truncation).\n     Flag glyphs: 🔗 (suspected wrong GH ref), 🗣️ (internal language),\n                  📝 (too terse or missing context),\n                  🕵️ (private-only symbol not re-exported through a public module),\n                  ⬆️ (Deprecated / Removed / rename entry missing migration guidance),\n                  🏷️ (new public symbol violates Newton's prefix-first naming),\n                  🧾 (runtime deprecation shipped but the released CHANGELOG omitted it),\n                  🚨 (removed without prior CHANGELOG or runtime deprecation evidence;\n                      policy violation surfaced in Breaking Changes and listed here\n                      for auditability).\n     An entry with multiple flags appears once per flag. -->\n\n<!-- Report ends here. Do NOT append \"end of report\", a closing quote, a thanks\n     note, or any terminal marker. -->\n\n<!-- File: .agents/skills/release-audit/SKILL.md (Tokens: ~11570 | Category: anthropic-skill) -->\n---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\n---\n\n# Release Audit\n\nGenerates a markdown audit of a Newton release for keep/defer decisions (or, in retrospective mode, for skill calibration). Three modes, auto-detected in Phase 1:\n\nRead `CODING_GUIDELINES.rst` and `REVIEW_GUIDELINES.rst` from the\nrepository root before auditing. They define the canonical coding, API, and\nreview policies. This skill performs the final cross-release reconciliation;\nit does not replace pull-request review, and a prior review pass does not make\nany audit phase optional. In retrospective mode, using the current guides is\nintentional: calibrate the current audit policy against evidence pinned to the\ntarget tag. Do not claim historical noncompliance unless the requirement also\nexisted at that tag.\n\n- **Pre-release**: spot-check while work is still landing on main. No release branch cut. Version string is `X.Y.Z.devN`.\n- **Release-candidate**: readiness review after the release branch is cut. Version string is `X.Y.ZrcN` or head is `release-X.Y`.\n- **Retrospective**: audit an already-shipped release (e.g., `v1.1.0`) against its predecessor, with a Calibration Notes section (Phase 7) that checks the audit's flags against what subsequent patch/minor releases actually did. Triggered by passing a bare released-version argument that matches an existing git tag.\n\n**Output:** a single markdown report, filed according to the destination chosen in Phase 1:\n- **Secret gist** (default when `gh` is available and authenticated): stable filename `newton-<version-string>-<prerelease|rc|retrospective>-report.md`, stable description `Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report`. Later runs against the same version revise the same gist in place; prior versions are preserved in the gist's git history.\n- **Local markdown file** (fallback when `gh` unavailable, or opt-in when `gh` available): dated path at `$(git rev-parse --show-toplevel)/newton-<version-string>-<prerelease|rc|retrospective>-report-<YYYY-MM-DD>.md`. Not auto-committed; user moves, shares, or deletes as desired.\n\n**Inputs inferred from repo state:**\n- Pre-release / RC: target version from `pyproject.toml` (`version = \"...\"`). `newton/_version.py` reads from installed metadata at runtime and is not a static source.\n- Retrospective: target version from the user's argument. `pyproject.toml` is ignored.\n- Base = latest tag matching previous minor's line (`vX.Y-prev.*`, latest patch).\n- Head (pre-release / RC) = `upstream/release-<target>` if it exists, else `upstream/main`. Head (retrospective) = the `vX.Y.Z` tag itself.\n\n**Reference documents to load on demand** (via `Read`):\n- `references/report-template.md` — fill this in during Phase 7b (the `{{HEADLINE_SUMMARY}}` placeholder is drafted in Phase 7a).\n- `references/render-rules.md` — rendering conventions and output style hard constraints for Phase 7b.\n- `references/classification-rules.md` — path/symbol rules used in Phases 3-5.\n- `references/language-review-examples.md` — Phase 5 language-review calibration.\n\n## Phase 1 — Align on scope\n\n1. **Determine the mode.** Look at any target-version argument supplied with the invocation:\n\n   - **Argument present AND matches an existing tag** (`git rev-parse --verify v<arg>` or `git rev-parse --verify <arg>` succeeds, AND the resolved name looks like `vX.Y.Z` / `vX.Y.ZrcN`): **Retrospective mode**. The argument is the already-shipped target version. Skip `pyproject.toml` entirely; the tag is authoritative. Do not run the pre-release / RC reconciliation in step 4.\n   - **Argument present but does NOT match any tag**: treat as a version override for the upcoming release. Use it as if it came from `pyproject.toml`, then fall through to the pre-release / RC detection below.\n   - **No argument**: read the version string from `pyproject.toml` — the top-level `[project]` table's `version = \"...\"` line.\n\n   Normalize the selected version by removing one leading `v`, if present. Before using it in a title, filename, or path, require the normalized value to match `^[0-9]+\\.[0-9]+\\.[0-9]+(?:rc[0-9]+|\\.dev[0-9]+)?$`. If it does not match, stop and report the unsupported version. Do not construct an output path from an unvalidated version string.\n\n   Record the report date at the same time. In retrospective mode, use the target tag's creator date:\n   ```bash\n   git for-each-ref --format='%(creatordate:short)' refs/tags/v<version>\n   ```\n   This returns the tagger date for an annotated tag and the commit date for a lightweight tag. For pre-release and RC modes, use the current date (`date +%F`).\n\n   For the non-retrospective path, parse the version string to extract the target minor (e.g., `1.2.0.dev0` → target `1.2`) and pre-classify mode:\n   - If the version string contains `\"rc\"` (e.g., `1.2.0rc1`) → **RC mode candidate**: this is a release-candidate readiness report.\n   - If the version string contains `\"dev\"` (e.g., `1.2.0.dev0`) → **Pre-release mode candidate**: this is an early-stage audit of unreleased work.\n   - Otherwise → pre-release mode (default), but record the raw version string so the header can show it as-is.\n\n2. **Enumerate previous-minor tags** (applies to all modes):\n   ```bash\n   git tag --list 'v<prev-major>.<prev-minor>.*' --sort=-v:refname\n   ```\n   where `<prev-major>.<prev-minor>` is `target - 0.1` (e.g., for target `1.2`, previous minor is `1.1`). Retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`; release-candidate and other prerelease tags are not release baselines. Take the first remaining result as the base candidate. Ignore pre-1.0 `beta-*` tags when a stable `vX.Y.Z` line exists.\n\n   **Major-boundary fallback.** When `target.minor == 0` (e.g., `2.0.0`), the `target - 0.1` computation yields a minor line that never existed (`1.9`), and the tag list comes back empty. In that case, enumerate the highest minor line of the previous major instead:\n   ```bash\n   git tag --list 'v<target-major - 1>.*' --sort=-v:refname\n   ```\n   Apply the same exact stable-release filter, then take the first result (the last-patch of the last-minor of the previous major) as the base candidate. If both the primary and fallback searches return empty (which should only happen on a never-released line), surface that to the user in step 6 rather than silently proceeding.\n\n   For **retrospective mode** with target `X.Y.Z`: the base is the last `vX.Y-prev.*` tag strictly before `vX.Y.Z`. Also check whether `X.Y.Z` is itself a patch release (`.Z > 0`): if so, the \"base\" could be either the previous patch on the same minor (`vX.Y.<Z-1>`) OR the previous minor's latest. Present both in step 6 and let the user pick — a patch retrospective usually wants patch-on-patch; a minor-release retrospective wants previous-minor's last patch.\n\n3. **Probe for the head**:\n   - **Retrospective mode**: head is the `vX.Y.Z` tag directly. Resolve with `git rev-parse --verify v<target>`.\n   - **Pre-release / RC**:\n     ```bash\n     git rev-parse --verify upstream/release-<target>\n     ```\n     If this succeeds, head = `upstream/release-<target>` and this is also a strong signal for **RC mode** (the branch-cut has happened). Otherwise try `origin/release-<target>`; otherwise head = `upstream/main` (falling back to `origin/main`, then `main`) which is **pre-release mode**. Record whichever fallback was used for the report header.\n\n4. **Reconcile mode** from version string and head (skipped for retrospective mode; its mode is already fixed):\n   - Version says RC AND head is a release branch → **RC report** (strong match).\n   - Version says RC but head is main (branch not cut yet) → **RC report** (version is authoritative; note the mismatch in the header).\n   - Version says dev AND head is a release branch → **RC report** (branch cut implies we're past the dev window).\n   - Version says dev AND head is main → **Pre-release report**.\n\n5. **Probe `gh` availability and look up any existing matching gist.**\n\n   First run:\n   ```bash\n   gh --version && gh auth status\n   ```\n   If either fails → `gh` unavailable; destination will be a local markdown file only; skip the rest of this step.\n\n   Both succeeded → compute the stable gist title for this report:\n   ```text\n   Newton <version-string> <Pre-Release|Release Candidate|Retrospective> Report\n   ```\n   (e.g., `Newton 1.2.0rc1 Release Candidate Report`, `Newton 1.2.0.dev0 Pre-Release Report`, `Newton 1.1.0 Retrospective Report`). No date. The gist filename and description are stable so later runs can find the same gist and revise it; gist git history preserves prior versions automatically.\n\n   Run `gh gist list --limit 1000` and filter rows whose description exactly matches that stable title. Capture the matching gist IDs; display URLs are `https://gist.github.com/<id>`. Record the match count (0, 1, or N ≥ 2) for step 6.\n\n6. Present proposal in chat and **wait for explicit user confirmation** of refs AND output destination. Mandatory pause.\n\n   Lead with the mode-specific intro line:\n   - Pre-release: `Generating **pre-release report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>**. **<N>** commits in range.`\n   - RC: `Generating **release-candidate report** for Newton **<version>**. Base **<base-ref>** → Head **<head-ref>** (release branch cut). **<N>** commits in range.`\n   - Retrospective: `Generating **retrospective report** for Newton **<version>** (already shipped). Base **<base-ref>** → Head **v<version>**. **<N>** commits in range. Calibration pass will cross-reference the audit's flags against subsequent patch / minor releases.`\n\n   For retrospective mode with a patch-target (when `.Z > 0`), also present the base choice explicitly:\n   > Base candidates for retrospective of `vX.Y.Z`:\n   > 1. `vX.Y.<Z-1>` (patch-on-patch: what changed since the previous patch on the same minor)\n   > 2. `v<prev-major>.<prev-minor>.<latest-patch>` (minor-boundary: what changed since the previous minor)\n   >\n   > Pick (1) or (2), or specify a different base.\n\n   Append the output block for the current `gh` / match state:\n\n   **`gh` unavailable:**\n   > Output: markdown file at repo root (`gh` not available). Confirm, or specify different refs?\n\n   **`gh` available, 0 matches:**\n   > Output: (a) new secret gist [default], (b) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, 1 match:**\n   > Output: (a) revise existing gist `<url>` [default], (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   **`gh` available, N matches (N ≥ 2):**\n   > Multiple existing gists share the stable title:\n   > 1. `<url-1>` — updated `<time-1>`\n   > 2. `<url-2>` — updated `<time-2>`\n   > ...\n   >\n   > Output: (a) revise gist by number, (b) new secret gist, (c) local markdown file at repo root. Confirm refs + pick.\n\n   Do not run any further phase until the user confirms refs and (when `gh` is available) chooses destination. Translate the user's reply into exactly one of the destination tokens `local`, `new-gist`, `revise-gist:<id>` and record it for Phase 7c. Letters `(a)`, `(b)`, `(c)` are positional within the current branch's prompt, not global: resolve them against the option list you just showed the user. For the N-match branch, the user picks a gist by the number you listed (e.g., \"revise 2\" → `revise-gist:<id-of-listed-row-2>`), or says new / local.\n\n## Phase 2 — Gather ground truth\n\n1. Run the commit-list tool:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n     --base <base-ref> \\\n     --head <head-ref> \\\n     --report-date \"<report-date>\" \\\n     --main-ref <resolved-main-ref>\n   ```\n   from the repo root (`$(git rev-parse --show-toplevel)`). Use the date recorded in Phase 1 so retrospective bake time is measured as of the audited release rather than as of today. Capture stdout as the `commit_list_json`.\n\n2. Run the dependency and license audit helper:\n   ```bash\n   uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py \\\n     --base <base-ref> \\\n     --head <head-ref>\n   ```\n   from the repo root. The helper requires Python 3.11+ for stdlib TOML parsing and exits with a clear preflight error on older Python versions. Capture stdout as `dependency_license_audit_md`. The helper compares:\n   - Direct requirements in `pyproject.toml`, grouped by runtime and optional extra.\n   - Resolved package names, duplicate variants, and version sets in `uv.lock` when present.\n   - `project.license` and `project.license-files` metadata in `pyproject.toml`.\n   - In-tree notice files matched by the `project.license-files` pathspecs declared at the base or head ref.\n   - Version-specific PyPI license metadata for newly introduced package names and changed locked package versions when network access is available. If metadata lookup fails, keep the helper's \"not checked\" text and surface that uncertainty rather than filling in a guessed license. If the helper was run with `--skip-pypi`, treat package-index metadata as deliberately deferred, not as per-package review failures.\n\n   Use one helper invocation as the source of the entire dependency/license section. Do not splice prose from a live metadata check onto tables produced by `--skip-pypi`. If a sandboxed or deferred run used `--skip-pypi` and a later host-side run can reach package indexes, replace the complete section with the default host-side output. Use `--skip-pypi` only as a fallback when a live metadata pass cannot be completed.\n\n   In Existing Resolved Package Version-Set Changes, the helper keeps standard license expressions and review statuses inline. Legacy or verbose nonstandard license text is rendered as a compact package-metadata link rather than copied into the report. The helper wraps this potentially long table in a closed `<details>` block; keep it collapsed by default so it does not dominate report scrolling.\n\n   The helper is intentionally stdlib-only. Do not replace it with a dependency inventory tool during the audit run: Newton avoids new release-only dependencies, and this script needs deterministic comparisons across arbitrary git refs without installing the target environment. External tools such as `pip-licenses`, `cyclonedx-py`, `pip-audit`, or `syft` can supplement a deeper investigation, but they do not replace this git-ref diff over `pyproject.toml`, `uv.lock`, declared license files, and version-specific PyPI metadata.\n\n   Interpretation rules for `dependency_license_audit_md`:\n   - A newly introduced external direct dependency or new resolved package name is license-relevant even when it lives behind an optional extra. Do not dismiss optional dependencies; state the extra or install path that pulls them in.\n   - A package that first appears in the lockfile only beneath a direct dependency already declared at the base is resolved-set churn, not a new dependency. The helper renders it in Existing Resolved Package Version-Set Changes with `(not resolved)` as the base and attributes the existing direct root. Reserve New Resolved Packages for packages introduced by a new direct dependency root or packages whose root cannot be established.\n   - A new optional extra whose dependencies are all already present is a support/install-surface change, but not a new package-license change.\n   - Existing package version bumps are not new licenses by themselves. The helper separates direct requirement moves from transitive-only churn; only elevate version bumps to release highlights or Behavioral & Support Changes when the package pin or compatibility constraint is user-visible.\n   - In-tree notice-file additions, removals, or modifications under the declared `project.license-files` pathspecs always appear in the dependency/license section. If a notice file is missing for a new bundled asset or vendored component, flag it in CHANGELOG Review Notes.\n   - If the helper reports license metadata as \"not checked\" due to lookup failure or \"not declared\" for a new package, keep that wording and mark it as needing release-manager review. Do not infer a license from package authorship or project name.\n   - If the helper reports \"not evaluated (--skip-pypi)\", say that package-index metadata was deferred and should be checked before final release sign-off. Do not turn that into a per-package review list.\n   - If a new package is proprietary, copyleft, commercial, unknown, not declared, or not checked due to lookup failure, mention that in the release highlights only when users can install it through a published extra or documented workflow.\n\n3. Load the pending or released changelog source by mode:\n   - **Pre-release / RC**: user-facing release scope is the rolling\n     `## [<target-version>]` section in `CHANGELOG.md`, when already assembled,\n     plus any later `.md` fragments on the resolved head. Before the first\n     Towncrier build, use the fragments plus legacy `[Unreleased]` entries.\n     Enumerate `changelog/*.md` with\n     `git ls-tree -r --name-only <head> -- changelog`, exclude `README.md`,\n     and read each file with `git show <head>:<path>`. Inventory `.skip` files\n     separately. Read `CHANGELOG.md` with `git show <head>:CHANGELOG.md`. If the\n     target's dated section exists, collect it through the next dated heading\n     and treat it as the assembled baseline. Otherwise, legacy entries are\n     between `<!-- towncrier release notes start -->` and the next dated `##`\n     heading.\n     If the audited head is the checked-out clean working tree, also run:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Use the draft output as the canonical preview for fragments not yet folded\n     into the rolling section; it does not modify `CHANGELOG.md` or delete\n     fragments. Audit the assembled baseline and draft additions together.\n   - **Retrospective**: read the target tag's changelog with\n     `git show v<target>:CHANGELOG.md`. Locate the `## [<target-version>]`\n     header and collect content up to the next dated `##` heading.\n\n4. Parse entries. Infer a fragment's section from its filename type (`added`,\n   `changed`, `deprecated`, `removed`, or `fixed`); the file content is one\n   entry without a leading bullet. Parse legacy or dated Markdown under the\n   corresponding five `###` headings. For every entry, extract:\n   - **Raw text (FULL — never truncate)**: the full bullet content (may span multiple lines).\n   - **Section**: one of the five names above.\n   - **Source path**: the fragment path or `CHANGELOG.md`.\n   - **Fragment identifier**: the numeric issue or leading-`+` orphan prefix\n     from the filename. Same-category counters do not change the identifier.\n   - **GH refs**: regex `GH-(\\d+)` over the bullet text. Dedup. (Newton commits and CHANGELOG entries sometimes also reference `#NNNN` as a bare PR number; capture these too.)\n   - **Migration hint**: does the prose contain a migration phrase (`use <new>`, `in favor of`, `renamed to`, `replaced by`, `switch to`, `migrate to`)? Record a boolean.\n\n   **Newton does NOT use a `**Breaking:**` literal marker in CHANGELOG** (unlike Warp). Do not rely on its presence. Breaking-change detection in Newton comes from: (a) the `### Removed` section (implicitly breaking), (b) signature-diff AST analysis (Phase 4e), and (c) reading `### Changed` prose for rename / parameter-reorder / signature-shift language (Phase 4d).\n\n## Phase 3 — Cross-reference\n\n1. **Build the commit ↔ CHANGELOG join** on GH-ref overlap:\n   - For each CHANGELOG entry with at least one GH ref, find commits (from `commit_list_json`) whose `gh_refs` intersect.\n   - For each pending fragment, find the commit that added its exact path:\n     ```bash\n     git log --reverse --diff-filter=A --format='%H|%s|%cs' \\\n       <base-ref>..<head-ref> -- changelog/<fragment-filename>\n     ```\n     Numeric identifiers link to issues, not necessarily to the implementing\n     pull request, so the fragment-addition commit is the authoritative join.\n   - For legacy entries and any fragment still lacking a backing commit, put\n     the distinctive substring in `entry_text` without interpolating it into\n     shell source, then search exact text across both storage forms:\n     ```bash\n     git log --reverse -S\"$entry_text\" \\\n       --format='%H|%s|%cs' <base-ref>..<head-ref> -- CHANGELOG.md changelog\n     ```\n     The first commit that is not a Towncrier build, synchronization, or another\n     changelog-only edit usually is the code change associated with the entry.\n     Record that as the backing commit.\n   - After these two passes, any CHANGELOG entry still with no matching commit is a genuine orphan case (deferred/dropped). Keep full entry text; do not truncate in the report.\n\n2. **Do NOT build an audit trace of unmatched commits.** The old \"commits without CHANGELOG entries\" appendix adds noise without value. Commits that don't map to a CHANGELOG entry are not surfaced in the report.\n\n## Phase 4 — Analyze API surface\n\n### 4a — Determine what is genuinely NEW API\n\nFor each CHANGELOG `Added` entry, extract the named symbol(s) — text in backticks matching `newton.*`, bare `ClassName`, bare `snake_case_name()`, or `ClassName.method()` patterns.\n\nFor EACH named symbol, check if it existed at base. Newton exposes user-facing symbols through multiple public re-export modules (not a single `__init__.py`). See `references/classification-rules.md` → \"Public API surface\" for the discovery rules. `docs/generate_api.py::api_modules()` discovers top-level public modules from module-valued names in `newton.__all__`; `solver_submodule_pages()` adds public solver module trees. There is no fixed `MODULES` constant. Inspect this discovery code plus `newton/__init__.py` and `newton/solvers.py` at both refs because the exported module set may grow or shrink between releases.\n\nTo check presence at base, run `git show <base>:<path>` for each relevant public module and grep its imported names. For method additions on an existing class (e.g., `SolverXPBD.update_contacts()`), inspect the class body at base in its real source (resolved via `_src/`). For retrospective mode, \"HEAD\" in the symbol-resolution text below means the `v<target>` tag, not the working tree. Use `git show v<target>:<path>` everywhere the pre-release / RC flow uses the working tree.\n\nClassification:\n- **Genuinely new** (symbol was not present at base) → **New API** section.\n- **Existed at base** (entry is adding a new parameter, option, or capability to something that already existed) → **Changes to Existing API** section with a \"capability extension\" or \"new parameter\" kind. Cite the backing commit's signature diff.\n- **Does not name a single symbol** (e.g., \"Interactive example browser in the GL viewer with tree-view navigation\") and describes a cross-cutting capability → **Behavioral & Support Changes** section unless one of the mentioned symbols is genuinely new (in which case split: put the new symbol in New API, the capability description in Behavioral).\n\n**If an entry mentions multiple symbols where some are new and some pre-existed** (e.g., \"Add `newton.geometry.compute_offset_mesh()` and a viewer toggle\"), split: the genuinely new symbols each get a New API entry; the extensions to existing symbols each get a Changes entry.\n\n**Public-API declaration and exposure check.** At HEAD, inspect every public\nmodule discovered by `api_modules()` and `solver_submodule_pages()`. Each module\nmust define `__all__` as a list or tuple containing only strings; a missing or\ninvalid declaration is a policy finding in \"CHANGELOG Review Notes\". For every\nsymbol that passes the \"genuinely new\" test, collect its memberships across\nthose declarations:\n\n- No memberships: report 🕵️ Private-only. The symbol exists only under\n  `newton._src.*` and was not re-exported through a public module.\n- One membership: the symbol has a canonical public import path.\n- More than one membership: report a duplicate-public-export policy finding\n  and list every public module that exports it.\n\n`CODING_GUIDELINES.rst` requires each public symbol to appear in exactly one\npublic module's `__all__` and forbids examples/docs from importing\n`newton._src`. Do not treat the private-only finding as a hard block on the\nentry; surface it so the release manager can confirm the symbol was intended\nto be public. Treat missing or invalid declarations and duplicate exports as\npolicy findings that require an explicit release decision.\n\n### 4b — Resolve New API signatures + docstrings\n\nFor each symbol confirmed as new:\n\n1. Find its real source module by following the re-export in the public module (e.g., `newton/solvers.py` → `newton/_src/solvers/xpbd.py`).\n2. `ast.parse` the source module; find the `FunctionDef` / `ClassDef` / `AsyncFunctionDef`.\n3. Extract the signature by re-stringifying the args (preserve type annotations).\n4. Extract the docstring verbatim via `ast.get_docstring(node)`.\n5. Render as shown in the template.\n\nNewton has no kernel-scope builtins layer to extract (no `add_builtin()` registry like Warp). All user-facing symbols live in Python modules and `ast` resolves them directly.\n\n### 4c — Symbol resolution fallbacks\n\n- **Symbol in backticks doesn't resolve at HEAD**: render the entry with a ⚠️ note: \"Couldn't resolve `<symbol>` in source — verify entry names a real public symbol.\" Do not fabricate a header like `newton.*(no symbol)*`. Use the entry's natural subject as the section title.\n- **Entry describes a topic, not a symbol** (e.g., \"Interactive example browser in the GL viewer\"): use a short descriptive title summarized from the entry (e.g., \"Interactive example browser\"), not a synthetic `newton.*` name.\n- **Header naming rule**: section headers in the report should be either real fully-qualified symbols (`newton.solvers.SolverXPBD.update_contacts`) OR short descriptive titles extracted from the entry. Never `newton.*`, `newton.(something)`, or similar stub patterns.\n\n### 4d — Changed / Removed / Deprecated signature diffs\n\nFor each CHANGELOG entry in Changed / Removed / Deprecated (plus any \"capability extension\" entries routed here from 4a):\n\n- Compute signatures at base and HEAD (same resolution as 4b).\n- For signature-shape changes: render a fenced `diff` block showing `-` and `+` lines.\n- For semantic-only changes (no signature shift) where the prose describes a rename / reorder / behavioral flip: skip the diff block; include the backing commit's URL and the full CHANGELOG text.\n- For Removed entries: show the old signature on a `-` line; omit `+`.\n\n**Deprecation-window lookup for Removed entries.** Newton's policy (per `CODING_GUIDELINES.rst`) is: *breaking changes require a deprecation first*. Every Removed entry needs evidence of a deprecation in a prior release. Start with the released CHANGELOG, then fall back to code-level runtime-warning evidence at the base ref. For every Removed entry (and every Changed entry whose prose describes a removal), search CHANGELOG.md for the matching prior Deprecated entry:\n\n1. Extract distinctive tokens from the Removed entry: the named symbol(s) in backticks and, if the entry carries a GH ref, that ref number.\n2. Scan the appropriate released-version sections of CHANGELOG.md for a `### Deprecated` bullet that names the same symbol(s) OR the same GH ref. The search scope depends on mode:\n   - **Pre-release / RC**: scan all dated sections, top-down. Pending fragments and legacy current-cycle entries do not prove a prior shipped deprecation.\n   - **Retrospective** (current target is `X.Y.Z`): scan ONLY the sections strictly below `## [X.Y.Z]` in CHANGELOG.md — the prior-release sections. Do NOT consider `## [Unreleased]` or later-version sections; they were written after `X.Y.Z` shipped and cannot have preceded it. Top-down within the allowed range.\n   The FIRST such entry (highest version, since CHANGELOG is reverse-chronological) is the deprecation introduction.\n3. If a matching CHANGELOG entry is found, record: (a) the release version heading that contains the Deprecated entry (e.g., `1.0.0`), (b) the full Deprecated entry text.\n4. If no matching prior CHANGELOG entry is found, check for a code-level runtime deprecation at the base ref. Resolve candidate source paths using the removed symbol, legacy parameter, or literal value, then grep those paths for deprecation warnings and inspect the surrounding source:\n   ```bash\n   git grep -n -F '<distinctive-symbol-or-legacy-value>' <base-ref> -- newton\n   git grep -n -E 'DeprecationWarning|deprecated' <base-ref> -- <candidate-paths>\n   git show <base-ref>:<candidate-path>\n   ```\n   If the candidate uses a shared deprecation helper or decorator, resolve the imported name and inspect its definition at the base ref too:\n   ```bash\n   git grep -n -F '<helper-or-decorator-name>' <base-ref> -- newton\n   git show <base-ref>:<helper-definition-path>\n   ```\n   Count this as prior-deprecation evidence when a runtime `DeprecationWarning` at the base ref clearly applies to the exact removed symbol or behavior, either through a direct `warnings.warn(...)` call or through a shared helper / decorator. For helper-mediated evidence, verify both sides of the connection: the candidate path applies or calls the helper for the removed API, and the helper definition emits `DeprecationWarning` for the calling mode or behavior being removed. For example, `@deprecate_nonkeyword_arguments` is evidence for removing positional-argument support only when it decorates that callable at the base ref; it is not evidence that the callable itself was deprecated. A generic helper that merely exists or is imported, a warning elsewhere in the same file, a docstring without a runtime warning, or a warning added only after the base release does not count. Record the warning text, the helper application path, and the warning-emission path. The base ref proves the deprecation shipped by that release; only claim an earlier introduction version if the same connected evidence is verified at that earlier tag.\n5. In the rendered Removed entry, include one of these deprecation-window lines:\n   - CHANGELOG evidence: `Deprecated in X.Y.Z; removed here.`\n   - Runtime-only evidence: `Runtime deprecation present in <base-ref>; removed here. No matching prior CHANGELOG Deprecated entry was found.`\n   - No evidence: `No prior deprecation found in released CHANGELOG sections or in code at <base-ref> — Newton's policy requires deprecation before removal.`\n   Do NOT fabricate a version.\n\nThe deprecation window belongs in BOTH the Breaking Changes entry for the removal AND the Changes-to-Existing-API row (in the Description cell or as an appended sentence in the detail block). A reader should never have to ask \"was this deprecated first, and for how long?\"\n\n**Missing-deprecation flag.** Surface `🚨 Policy: removed without prior deprecation` only when BOTH checks fail: no prior Deprecated entry exists in a previously-released CHANGELOG section, and no matching direct or helper-mediated runtime `DeprecationWarning` exists at the base ref. This fires whether or not the current release's own `### Deprecated` section also names the symbol because a warning added only in the removal release did not ship in a prior release. The release manager needs this to block the release or add migration tooling.\n\nIf a matching runtime warning exists at the base ref but the released CHANGELOG has no corresponding Deprecated entry, the deprecation window is real. Do not emit a policy violation. Instead, add a non-blocking `🧾 Deprecation omitted from CHANGELOG` review note with the base ref, warning text, and the direct source path or connected helper application / emission paths so the release-note gap remains visible.\n\n**Exception: `1.0.0` pre-stable cleanup.** Removed entries in the `1.0.0` release (and `1.0.0rcN`) are exempt from the deprecation-first policy — PRs labeled `1.0-release` are the pre-stable API cleanup and were not required to go through a prior deprecation window. When the target version is `1.0.0` or `1.0.0rcN`, do not emit the `🚨 Policy` flag or the \"No prior **Deprecated** entry found\" line for its Removed entries. Still render the deprecation-window line if a matching Deprecated entry happens to exist; otherwise note `1.0 pre-stable cleanup; no prior deprecation required.`\n\n### 4e — Signature-AST diff for unlabeled migration-required changes\n\nIndependently of CHANGELOG content, compute the public API surface at base vs. HEAD by walking every symbol re-exported from the public modules in 4a:\n\n- Base: `git show <base-ref>:<module.py>` for each public module and for every real-source module it re-exports from → parse with `ast`. Resolve each re-export's real signature at base.\n- Target: same as Base, but at the target ref — the working tree in pre-release / RC mode, or `git show v<target>:<module.py>` in retrospective mode. Do NOT read the working tree in retrospective mode; later commits on `main` would otherwise be falsely attributed to `vX.Y.Z`.\n- For each symbol whose signature shape changed AND whose matching CHANGELOG entry (if any) doesn't indicate a rename / parameter shift / removal → add to Breaking Changes section as \"unlabeled signature change — please verify\".\n\n**Exception: Removed symbols are breaking by definition.** A symbol that appears in CHANGELOG's `Removed` section does NOT need prose hedging to be valid. Do NOT flag Removed entries as \"unlabeled breaking\" — the section name itself communicates the breakage. Removed entries surface in the Breaking Changes callout and in the Changes-to-Existing-API section (as \"removed\" kind), but the report must not whinge about missing Breaking labels on them.\n\n**Exception: additive keyword-only parameters with defaults are not migration-required.** A signature change that only adds new kwargs with defaults after `*` is additive; do not surface in Breaking Changes. It belongs in Changes-to-Existing-API with Kind `new parameter` and Breaking `No`.\n\n### 4f — Semantic-change candidates from solver / integrator commits\n\nNewton has no native C++/CUDA code (unlike Warp); there is no build-and-run verification step. However, changes to solver internals, integrators, collision pipelines, and math helpers can still change observable numerical behavior without altering any signature.\n\nFor each commit in `commit_list_json` that touches paths under `newton/_src/solvers/**`, `newton/_src/sim/**` (integrator / collision code), or `newton/_src/math/**`:\n\n1. Skip if the commit is already mapped to a CHANGELOG entry explicitly describing the semantic shift.\n2. Read the commit's diff: `git show --stat <sha>` then `git show <sha>` for small diffs, or read specific hunks for large ones.\n3. **Triage** into one of three buckets:\n   - **Clearly not semantic-breaking** → drop. Examples: renaming internal symbols, comment / format changes, pure internal refactors, performance optimizations that preserve output, test-only changes, bug fixes where the pre-fix behavior was itself a bug.\n   - **Clearly semantic-shifting** with an obvious user-observable numerical / behavioral change visible from the diff alone → include in Breaking Changes with a short \"Before / After\" explanation derived from the diff and commit message.\n   - **Ambiguous** — the diff suggests the change could affect numerical output but the audit cannot establish from reading alone whether users would notice → add a concise entry in a \"Review candidates\" subsection of CHANGELOG Review Notes (NOT Breaking Changes). Include the commit, the touched file(s), and a one-sentence hypothesis. Do not speculate in Breaking Changes.\n\n**Do NOT attempt to build and run Newton at base vs. HEAD.** Newton's solver outputs depend on Warp, MuJoCo, and GPU state; reproducing a numerical diff in a one-shot audit is not reliable and not worth the setup cost. When in doubt, route to the review-candidates list and leave verification to the release manager.\n\n### 4g — Experimental-marker cross-reference\n\nSome Newton features ship with an explicit `experimental` note in the CHANGELOG entry that introduced them (e.g., \"Add differentiable rigid contacts (experimental)\") or in docstrings. Changes to those features do NOT carry the same stability contract as changes to stable APIs. The report must reflect that so the release manager does not over-weight the concern.\n\nFor each entry in Breaking Changes, Changes to Existing API, and Removed (as collected through 4a–4f), determine whether the affected symbol or feature area is currently experimental:\n\n1. Collect candidate symbols / feature-area phrases from the entry: backticked identifiers, class names, and (for topic-style entries) the most distinctive descriptive noun phrase.\n2. Search CHANGELOG.md in released-version sections for bullets that name one of the candidates AND contain the literal substring `experimental` (case-insensitive). Also match via GH ref if the current entry and a prior experimental entry share a GH number. Scope:\n   - **Pre-release / RC**: all dated sections.\n   - **Retrospective** (current target is `X.Y.Z`): everything below `## [X.Y.Z]`. The stability-promotion check (step 3 below) likewise only considers versions strictly before `X.Y.Z`.\n3. If a match exists AND there is no subsequent CHANGELOG bullet in a later released version explicitly promoting the symbol to stable (e.g., \"Promote X out of experimental\", \"Stabilize Y\"), the symbol is still experimental. Record: (a) the release version that introduced the symbol as experimental, (b) the full text of that introduction bullet.\n4. Also check the module source at HEAD for an in-code `.. experimental` / `Experimental:` / `experimental_api` / `@experimental` annotation on the symbol's declaration. If present, treat as experimental regardless of CHANGELOG signal.\n\nTag every matched entry internally as `experimental=True`. Do not alter the CHANGELOG text itself.\n\n**How the tag changes rendering:**\n- Breaking Changes heading for the entry: prefix with `Experimental:` and do not use a warning emoji. Include a short sentence reminding readers that the symbol is opt-in and has a looser stability contract, with the release where the experimental marker was introduced.\n- Changes-to-Existing-API table: the Breaking column shows `Experimental` rather than `Yes`.\n- Release Highlights bullet (Phase 7a): if the item independently clears the significance bar, use a neutral `Experimental:` label without a warning emoji. Experimental status alone does not make an item a highlight.\n\n**Never drop the entry from the detailed audit.** Experimental status changes the stability interpretation, not the underlying API diff. A removed or signature-changed experimental symbol still appears in Breaking Changes and Changes to Existing API, but it is not presented as a release-manager warning.\n\n### 4h — Schema and importer completeness\n\nApply the guides' schema/importer policy to new or substantially changed\nauthorable features across the audited range, including existing-API extensions\nand commits without changelog entries. Inspect schema definitions/proposal\nrevisions, parsing, compatible schema-package versions, and behavioral tests at\nthe audited ref; schema representation alone is not complete support.\n\nRender **Schema & Importer Support** with columns\n`Feature | Disposition | Evidence / remaining work`:\n\n- **Supported**: record the supported subset and cite schema-to-builder-to-runtime\n  evidence, tests against equivalent builder-created models, and verified schema\n  semantics.\n- **Explicitly deferred**: cite review acceptance, reason, issue, owner, and\n  target milestone, plus the remaining limitation.\n- **Not applicable**: explain why the feature is runtime-only or non-authorable.\n- **Gap / decision required**: identify missing support, evidence, or accepted\n  deferral details for a keep/defer decision.\n\nFor retrospective audits, distinguish current-policy gaps from violations of\nrequirements in force at the target tag.\n\n## Phase 5 — Review CHANGELOG language and bake\n\n### 5a — Language review\n\nRead `references/language-review-examples.md`. For EACH CHANGELOG entry, apply LLM judgment:\n\n- **🔗 Wrong ref (tier-1)**: for every GH ref in the entry, fetch the mapped commits' subjects and paths. If the entry topic doesn't match the commits' actual scope, flag.\n- **🔗 Wrong ref (tier-2)**: if `gh --version` and `gh auth status` both succeed, run `gh issue view <num> --json title,body` per ref and compare issue title to entry topic. Skip silently if `gh` unavailable.\n- **🗣️ Internal language**: internal module paths (`newton._src.*`), private identifiers with a leading underscore, Warp-internal types (`wp.types.*` that are not documented user types), implementation-detail verbs (\"refactor\", \"reorganize\", \"rewrite\") without a user-visible outcome.\n- **📝 Too terse**: under ~10 words with no context, or missing migration guidance in a Deprecated / Changed entry that names a rename or removal.\n- **🕵️ Private-only symbol**: the CHANGELOG `### Added` entry names a symbol that exists only in `newton._src.*` at HEAD and is not re-exported through a public module. See Phase 4a.\n- **⬆️ Missing migration guidance** (Newton-specific): entries in `### Deprecated`, `### Removed`, or `### Changed` (where the prose indicates rename / reorder / removal) MUST include migration guidance per `changelog/README.md` (\"Use `Y` instead\", \"in favor of `Y`\", \"switch to `Y`\"). Flag entries that rename or remove symbols without pointing to the replacement.\n- **🏷️ Naming-convention drift** (Newton-specific): new public symbols in `### Added` whose names violate Newton's prefix-first convention (e.g., `PDActuator` should be `ActuatorPD`; `add_sphere_shape()` should be `add_shape_sphere()`). See `CODING_GUIDELINES.rst`.\n\nRecord flagged entries. Keep the FULL entry text in the audit table — do not truncate.\n\n### 5b — Bake aggregation\n\nFrom `commit_list_json`:\n- Bucket each commit's `days_in_main` into **🟢 (>14 days)**, **🟡 (7–14 days)**, **🟠 (<7 days)**. Commits whose `days_in_main` is `null` (no main equivalent) skip bucketing — do NOT coerce `null` to `0` or compare it to a numeric threshold; those commits are accounted for in the next bullet instead.\n- Count anomalies: commits with `main_equivalent_sha == null`. If non-zero, prepare the ⚠️ banner for the report header.\n\n### 5c — Dependency and license audit\n\nUse `dependency_license_audit_md` from Phase 2 as the report's `{{DEPENDENCY_LICENSE_AUDIT}}` section. Apply the interpretation rules listed with the helper invocation in Phase 2.\n\n## Phase 6 — Calibration Notes (retrospective mode only)\n\n**Skip this phase entirely in pre-release / RC mode.** There is no shipped history to calibrate against.\n\nIn retrospective mode, the Phase 3–5 output is a set of flags and classifications that would have surfaced had the skill been run *before* `X.Y.Z` shipped. The point of calibration is to check those flags against what *actually* happened after the release — did the concerns hold up? The output of this phase is a \"Calibration Notes\" section in the report (Phase 7b renders it).\n\n### 6a — Enumerate post-target history\n\nIdentify releases that shipped strictly after `X.Y.Z`:\n\n```bash\ngit tag --list 'v*' --sort=v:refname\n```\n\nBefore selecting post-target history, retain only tags matching the exact stable-release form `^v[0-9]+\\.[0-9]+\\.[0-9]+$`. Exclude release-candidate and other prerelease suffixes. From that filtered, sorted list, drop everything up to and including `vX.Y.Z` and keep the rest. Typical post-target history for a minor release `vX.Y.0` is:\n- `vX.Y.1`, `vX.Y.2`, ... (patch releases on the same minor)\n- `vX.Y+1.0`, `vX.Y+1.1`, ... (the next minor and its patches)\n\nFor each post-target tag, read its CHANGELOG section (the `## [<version>]` block in `CHANGELOG.md` at HEAD, or via `git show <tag>:CHANGELOG.md` if the section has since been edited). Parse the five subsections (`Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`) the same way Phase 2 does.\n\nAlso collect the commits in each post-target range (`<prior-tag>..<tag>`) — one full `list_commits.py` invocation per range, with the same required args as Phase 2. `--main-ref` reuses the main ref resolved in Phase 1 (don't rely on the script's `upstream/main` default; Phase 1 may have fallen back to a different remote):\n\nFor each retained post-target tag, derive `<post-target-release-date>` with the same `git for-each-ref --format='%(creatordate:short)'` command used in Phase 1. This keeps any soak-time metadata relative to that release rather than the day the retrospective audit happens.\n\n```bash\nuv run --no-project python .agents/skills/release-audit/scripts/list_commits.py \\\n  --base <prior-tag> \\\n  --head <tag> \\\n  --report-date \"<post-target-release-date>\" \\\n  --main-ref <resolved-main-ref>\n```\n\nThese commits become the evidence pool for validating the Phase 4f semantic-change candidates.\n\n### 6b — Cross-reference audit flags against post-target history\n\nFor each flag class, run the check below and record one of three outcomes per flag:\n- **Validated** — subsequent history confirms the audit concern was real.\n- **Invalidated** — subsequent history contradicts the audit concern (false positive).\n- **Unresolved** — no post-target evidence either way (flag stands as-is, but the reader can treat it as lower-confidence).\n\nThe calibration section groups results by flag class and, within each, by outcome. Never drop a flag from the original report body because of calibration — the calibration is a separate layer of commentary.\n\n**🚨 Missing-deprecation (Removed without prior evidence):**\n- Validated if: (a) no prior released CHANGELOG section names the deprecation, (b) no matching direct or helper-mediated runtime `DeprecationWarning` exists at the retrospective base ref, and (c) the symbol stays removed. Users actually lost the API without a deprecation window.\n- Invalidated if: a prior Deprecated entry existed that the audit missed. Re-scan CHANGELOG scope with fuzzier matching (different casing, plural / singular, alternate backtick placement). Report the missed entry with its version.\n- Invalidated if: the base ref contains a matching direct or helper-mediated runtime `DeprecationWarning`. Report the warning text and the direct source path or connected helper application / emission paths, and classify the missing CHANGELOG bullet as a documentation gap rather than a deprecation-policy violation.\n- Invalidated if: a later patch (`vX.Y.<Z+1>`) added the symbol *back* (revert). Name the revert commit and note \"removal reverted in vX.Y.<Z+1>\".\n\n**🕵️ Private-only (new public API with `_src`-only reachability):**\n- Validated if: a later release adds a re-export for the symbol through a public module (`newton.<module>.py`). Cite the release and the re-export commit.\n- Invalidated if: the symbol stays reachable only via `_src` in every post-target release AND no issues reference it — it was probably intentional internal-only despite its position in the Added section. Note this as \"intended internal; CHANGELOG language could have been clearer\".\n- Unresolved if: the symbol was removed / renamed before re-export resolution.\n\n**⬆️ Missing-migration-guidance:**\n- Validated if: a later release's CHANGELOG bullet (in `### Changed` or `### Fixed`) retroactively points to the replacement, OR a subsequent issue references users stuck on the migration. The second signal is only available if `gh issue list` returns matches for the symbol name; probe with `gh issue list --search \"<symbol>\" --state all --json number,title`.\n- Invalidated if: the migration was handled by a runtime `DeprecationWarning` with a clear message (grep the code at `v<target>` for the warning text).\n- Unresolved: default.\n\n**🏷️ Naming-convention drift:**\n- Validated if: a later release renames the symbol to match Newton's prefix-first rule, typically with a DeprecationWarning on the old name. Cite the rename commit and the release.\n- Invalidated if: the symbol stays and matches the *local* module convention rather than the global prefix-first rule (e.g., a module of siblings that all use `<Kind>Foo`). Note which convention it actually follows.\n- Unresolved: default.\n\n**Phase 4f semantic-change candidates** (the ones routed to \"Review Candidates\", not Breaking Changes):\n- Validated if: a later patch release's `### Fixed` entry touches the same file(s) and describes a symptom consistent with the candidate's hypothesis (e.g., \"Fix convergence regression in SolverXPBD step ordering\" after a candidate about solver step ordering). Cite the fix commit and the release.\n- Invalidated if: the file stayed stable for the rest of the minor line with no related bug reports. Probe `gh issue list --search \"<file-or-feature>\" --state all --json number,title,createdAt` if `gh` is authenticated — only count issues created after `v<target>`'s release date. Skip the probe silently if `gh` is unavailable.\n- Unresolved: default.\n\n**Deprecation-follow-through (new check, retrospective-only):** for every entry in `X.Y.Z`'s own `### Deprecated` section, check subsequent minor releases for the corresponding `### Removed` entry.\n- **Followed through** — a later minor removed the symbol as promised. Cite the release.\n- **Still deprecated** — symbol remains in the public surface with the deprecation warning in all later minors. No action required; just a fact.\n- **Silently dropped** — symbol was removed but no `### Removed` entry cites it (CHANGELOG hygiene bug in the later release). Flag this as a separate concern.\n\n### 6c — Compose the calibration narrative\n\nAggregate the per-flag outcomes into a short section with this shape:\n- One-paragraph headline: how many flags were validated / invalidated / unresolved overall, a\n\n<!-- [TRUNCATED AT 50KB] -->\n\n<!-- File: .agents/skills/release-changelog/SKILL.md (Tokens: ~1223 | Category: anthropic-skill) -->\n---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nPending user-facing changes live in Towncrier fragments under `changelog/`.\n`CHANGELOG.md` is generated only on a release branch. Shipped sections are\nimmutable; the assembled section for the pending release remains a rolling\ndocument until tagging. Follow `changelog/README.md` as the command and format\nauthority.\n\n## Audit pending changes\n\n1. Identify the release ref and comparison base. Audit `release-X.Y` once it\n   exists; otherwise audit the intended main ref.\n2. Protect released history. Diff `CHANGELOG.md` from the latest stable tag and\n   require explicit maintainer approval for edits to dated sections.\n3. Render a non-mutating preview, which also validates Towncrier's renderable\n   fragment filenames:\n   ```bash\n   uvx --from towncrier==25.8.0 towncrier build --draft \\\n     --version X.Y.Z --date YYYY-MM-DD\n   ```\n4. Compare the preview with the release audit and commit range from the previous\n   release. Inspect `.skip` reasons separately.\n5. Preserve information. Rephrase, split, merge, or recategorize fragments only\n   when the facts remain intact. Ask before deleting information or downgrading\n   a user-visible change.\n6. Use only `Added`, `Changed`, `Deprecated`, `Removed`, and `Fixed`, in that\n   order. Keep migration and retesting guidance in affected entries.\n7. Remove exact and semantic duplicates. When a feature and its fix both land\n   in one cycle, describe the final user-visible behavior once.\n8. Keep `Added` for new public APIs, options, features, examples, and docs. Put\n   existing-API behavior, warning, default, importer, and solver changes in\n   `Changed`, even when they expand support.\n9. Give every breaking, removed, deprecated, or default-changing entry a\n   concrete action. Never direct users to `newton._src`.\n10. A numeric fragment identifier is a GitHub issue number. Towncrier renders\n    its issue link automatically; do not rewrite it as a pull request number.\n\n## Assemble the release during RC stabilization\n\nAfter the initial release scope has been audited on `release-X.Y`, assemble the\ncurrent fragments early enough for maintainer review:\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\nuvx --from towncrier==25.8.0 towncrier build --yes \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit rm --ignore-unmatch \"changelog/*.skip\"\ngit add -A CHANGELOG.md changelog\n```\n\nReview and approve the draft before running the mutating command. Towncrier\ninserts the dated section below `[Unreleased]` and deletes rendered fragments.\nIt ignores `.skip` files, so remove those explicitly. Review the staged diff in\na changelog-only pull request labeled `release-management`.\n\nAfter assembly, apply the audit rules above to the dated section: verify\ncompleteness, grouping, deduplication, wording, categories, and migration\nguidance. Keep editorial cleanup in the changelog-management commits that will\nlater be synchronized to `main`.\n\nThe first Towncrier release requires one migration audit. The insertion marker\nsits above the legacy `[Unreleased]` entries so they remain under the first\ngenerated release title. Merge duplicate category headings without dropping or\nduplicating an entry. Later releases need no special handling.\n\nTreat the assembled section as a rolling document. For every later cherry-pick\nbefore tagging:\n\n1. Validate the new fragments and render them with `towncrier build --draft`.\n2. Fold the previewed entries into the existing dated section without creating\n   a second release heading.\n3. Delete exactly the consumed `.md` and `.skip` fragments, then stage\n   `CHANGELOG.md` and `changelog/`.\n4. Rerun the changelog cleanup and `release-audit` checks, and merge the update\n   as another changelog-only `release-management` pull request.\n\nFinal GA preparation verifies the completed section and confirms that no\nrelease-branch fragments remain. Do not postpone the full cleanup until GA.\n\n## Synchronize to main\n\nAfter tagging:\n\n1. Create a changelog-only branch from current `main`.\n2. Cherry-pick, in order, every changelog-management commit from `release-X.Y`:\n   the initial Towncrier build, editorial cleanup, and all later cherry-pick\n   additions.\n3. Confirm fragments deleted by those commits disappear while fragments added to\n   `main` after the branch cut remain under `changelog/`.\n4. Confirm the dated section matches the release tag and older history is\n   unchanged.\n5. Open a changelog-only pull request labeled `release-management`.\n\nDo not replace the whole file with the release-branch copy. The commits'\npath-level deletions are what preserve main-only fragments.\n\n## Checks\n\n```bash\nuvx --from towncrier==25.8.0 towncrier build --draft \\\n  --version X.Y.Z --date YYYY-MM-DD\ngit diff v<latest-release> -- CHANGELOG.md changelog\ngit diff --cached --name-status -- CHANGELOG.md changelog\nrg -ni \"removed|deprecated|in favor of|use .* instead|renam|replac|default|breaking\" \\\n  CHANGELOG.md changelog\n```\n\nConfirm that `[Unreleased]` is empty after the first migration, no dated history\nchanged, released entries appear exactly once, and post-cut main fragments\nsurvive synchronization.\n\n<!-- File: .agents/skills/release-notes/SKILL.md (Tokens: ~2274 | Category: anthropic-skill) -->\n---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nDraft concise GitHub Release notes that explain why a Newton release exists and\nwhat users should know. Do not reproduce the full changelog; link to it.\n\nWrite for external users moving from the previous final release to the current\nartifact without assuming they followed development or release candidates.\nFinal-release notes must not mention earlier RCs. Never mention or link internal\nrelease audits, audit gists, readiness reports, cutoff SHAs, bake durations,\naudit counts, or other audit-only metadata; use those sources as evidence only.\n\n## Workflow\n\n1. Identify the artifact, target version, and release type:\n   - **GitHub release description**: public release page. Follow Newton/Warp\n     release-page style and include user-actionable migration sections.\n   - **Internal release announcement**: short internal email/doc. Use release\n     metadata first, then grouped bullets such as `New Features`,\n     `Performance Improvements`, and `Developer Experience`.\n   - If the user wants both and the content should converge, keep one document\n     only when explicitly requested; otherwise maintain separate drafts.\n   - Patch / bugfix releases: emphasize fixes, compatibility, and stability.\n   - Minor / feature releases: emphasize major user-facing capabilities.\n   - RCs: state that this is a release candidate and what needs validation.\n     If drafting final-release text from an RC tag or release branch, do not\n     mention the RC; use the RC only as the temporary source of truth.\n2. Choose changelog source material from the authoritative release ref:\n   - After the Towncrier build or tagging, read the matching dated\n     `CHANGELOG.md` section from the release tag or release branch.\n   - Before the build, check out the release branch, validate its pending\n     fragments, and render a non-mutating preview:\n     ```bash\n     uvx --from towncrier==25.8.0 towncrier build --draft \\\n       --version X.Y.Z --date YYYY-MM-DD\n     ```\n     Draft from the preview and legacy `[Unreleased]` entries during the first\n     Towncrier transition. Do not run a mutating build merely to draft notes.\n   Do not rely on `main` unless the release is actually cut from `main`.\n3. Determine the previous release tag:\n   - Patch release `X.Y.Z`, `Z > 0`: use the highest earlier `vX.Y.<Z'>` tag.\n   - Feature release `X.Y.0`: use the highest `vX.<Y-1>.*` tag. If `Y == 0`,\n     use the highest tag from the previous major.\n4. Compare the release range against the previous release:\n   ```bash\n   git log --no-merges --oneline --cherry-pick --right-only v<previous>...v<target>\n   git diff --name-status v<previous>..v<target>\n   ```\n   Use the symmetric-difference `...` log form for counting and scanning commits\n   when a release branch contains cherry-picks; it avoids overstating scope with\n   equivalent patches already present in the previous release. Use the normal\n   `..` diff for changed files. If the final tag does not exist yet, use the\n   latest RC tag or `upstream/release-X.Y` as the temporary target.\n5. Inspect the PRs behind candidate highlights. Commit subjects usually carry\n   `(#NNNN)`; use PR bodies when needed to understand impact and any linked\n   issues.\n6. Check prior release-note and announcement formats when available:\n   - Newton release pages, e.g. `v1.2.0`, for the local public-release shape.\n   - Warp release pages for `Announcements`, `Upcoming removals`, and\n     acknowledgement patterns.\n   - Internal announcements for short internal release-email structure.\n7. Draft a high-level overview and a short highlights list. Keep only\n   consumer-relevant items. Omit CI, workflow, README layout, release-link\n   pinning, and other internal/docs polish unless the user explicitly asks or it\n   affects library users. When a validated release review supplies the\n   highlights, preserve its release-defining conclusions, ordering, and public\n   wording unless publication rules require a change. Rewrite audit-oriented\n   framing, remove audit-only metadata, and adapt references to the release-note\n   format without weakening the user-facing claims.\n8. Keep a review-ready release-branch draft. After tagging, refresh it against\n   the final tag and inspect the workflow-created draft GitHub Release. Publish\n   only after verifying the final artifact and links per `docs/guide/release.rst`.\n\n## Linking Rules\n\n- Link the changelog to the final release tag:\n  `https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor`\n- If drafting before the final tag exists, use `release-X.Y` or the RC tag\n  temporarily, but note that the published release should use the final tag.\n- Never link the changelog to `main` for a release branch unless `main` is the\n  authoritative release ref; `main` may have newer unreleased changes.\n- Add one GitHub reference to each highlight, usually the PR. Use an issue only\n  when there is no useful PR or the issue is the canonical context.\n- Avoid linking both an issue and a PR for the same highlight unless that extra\n  context is necessary.\n- In GitHub Release notes, render same-repository references as plain `#NNNN`\n  instead of full markdown links. GitHub auto-links them on the release page, and\n  the compact form matches Warp's release-note style.\n- Link in-tree examples or docs on the release tag URL, never `main`, so links\n  do not drift after publication.\n- For dependency summaries, prefer a link to the relevant `pyproject.toml`\n  compare over listing every changed constraint:\n  `https://github.com/newton-physics/newton/compare/v<previous>...v<target>?diff=split`\n  Mention only high-signal dependency changes in bullets.\n\n## Style\n\n- Start with a short paragraph naming the version, release type, and purpose.\n- Use a `## Highlights` section with typically 3-6 grouped bullets. Retain\n  additional release-defining highlights when the user explicitly requests them\n  or a validated release review establishes that they belong; do not drop a\n  significant theme merely to meet the usual count.\n- For bugfix releases, keep notes slim: no `## New features` section unless a\n  genuinely notable capability shipped in the patch. The highlights are a\n  categorized digest of fixes.\n- For feature releases, group related features by user workflow and order by\n  impact. Lead with the most important user-facing capability, not API names.\n- Prefer user impact over implementation detail.\n- Keep bullets compact: one bold label, one or two explanatory sentences, then\n  the `#NNNN` reference.\n- Treat the changelog as source material, not prose to copy. Translate internal\n  implementation terms into user-facing impact.\n- Include `## Announcements` only for changes users must act on, such as\n  removals, deprecations, platform-support changes, or dependency constraints.\n- For public feature releases, include focused sections for:\n  - breaking changes and removals,\n  - new deprecations,\n  - upcoming removals,\n  - dependency updates,\n  - acknowledgements.\n  Keep these concise; the changelog carries the exhaustive detail.\n- Include `## Notes` only for compatibility, install, or migration information\n  users need. Drop the section when there is nothing useful to say.\n- Include `## Acknowledgments` when there are meaningful contributions from\n  outside Newton maintainers and project-member groups. Omit trivial typo-only\n  or formatting-only changes.\n- For patch releases, say whether the release is intended to be API-compatible\n  with the previous patch/minor when that is true.\n- Avoid em dashes in rendered prose.\n- Keep raw Markdown soft-wrapped: use one physical line per paragraph and list item; let viewers wrap it to their window width.\n\n## Dependency Updates\n\nDo not default to a large table. Keep dependency updates high signal:\n\n- Call out major/minor runtime baseline bumps, new extras, dependency caps that\n  affect users, and removed caps when they unblock compatibility.\n- Link to the `pyproject.toml` compare for the complete detail.\n- If the prior patch release changed dependencies, compare against the closest\n  prior release tag, not the earlier minor tag.\n\n## Acknowledgments\n\nBefore listing outside contributors, verify they are not in Newton's maintainer\nor project-member groups.\n\n1. Read `newton-governance/CONTRIBUTORS.md` or the current governance source\n   when reachable. Treat it as the authority for maintainer and project-member\n   membership.\n2. If GitHub access is available and governance points to org teams, query the\n   current team slugs from GitHub rather than relying on a hardcoded list:\n   ```bash\n   gh api orgs/newton-physics/teams --paginate --jq '.[] | [.slug, .name] | @tsv'\n   gh api orgs/newton-physics/teams/<team-slug>/members --paginate --jq '.[] | .login'\n   ```\n   Prioritize teams named by governance, or teams whose current names clearly\n   identify maintainers, TSC, project members, or project-member organizations.\n3. Cross-check candidate PR authors with `gh pr view <number> --json author`\n   and commit emails. Commit email/company is a hint, not a substitute for the\n   team/governance check.\n4. Phrase the section accurately, for example \"outside the Newton maintainer\n   and project-member groups\" when that is the filter used.\n\n## Template\n\n```markdown\n# Newton vX.Y.Z\n\nNewton vX.Y.Z is a patch release following vX.Y.W. It focuses on bug fixes and\ncompatibility updates for the X.Y release line, especially around <areas>.\n\nFor the complete list of changes, see the [changelog](https://github.com/newton-physics/newton/blob/vX.Y.Z/CHANGELOG.md#anchor).\n\n## Highlights\n\n- **<User-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n- **<Another user-facing fix or improvement>.** <Brief impact statement.> (#NNNN)\n\n## Announcements\n\n<Only include this section when there is a removal, deprecation,\nplatform-support change, dependency constraint, or other user-actionable\nannouncement. Drop it otherwise.>\n\n## Notes\n\nThis release is intended to be API-compatible with Newton vX.Y.W. No breaking\nchanges are expected.\n```\n\n<!-- File: .claude/skills/code-review-newton/SKILL.md (Tokens: ~88 | Category: anthropic-skill) -->\n---\nname: code-review-newton\ndescription: Use when reviewing a Newton pull request, branch, commit range, work-in-progress change, or design proposal for project fit, requirements fidelity, and coding and repository standards.\n---\n\n# Review Newton Changes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/code-review-newton/SKILL.md`. If it is unavailable, stop\nwithout performing the review.\n\n<!-- File: .claude/skills/release-audit/SKILL.md (Tokens: ~277 | Category: anthropic-skill) -->\n---\nname: release-audit\ndescription: \"Use when auditing Newton's pending Towncrier fragments for keep/defer decisions, reviewing an RC for readiness, or calibrating against an already-shipped release.\"\ndisable-model-invocation: true\nargument-hint: \"[target-version]\"\nallowed-tools: Bash(git log *) Bash(git show *) Bash(git grep *) Bash(git tag *) Bash(git rev-parse *) Bash(git diff *) Bash(git ls-tree *) Bash(uvx --from towncrier==25.8.0 towncrier build --draft *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/list_commits.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/license_audit.py *) Bash(uv run --no-project python .agents/skills/release-audit/scripts/cleanup_report.py *) Bash(gh --version) Bash(gh auth status) Bash(gh gist create *) Bash(gh gist list *) Bash(gh gist view *) Bash(gh gist edit *) Bash(gh issue view *) Bash(gh issue list *) Read Write Grep Glob\n---\n\n# Release Audit\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-audit/SKILL.md`. If it is unavailable, stop without\nstarting the audit.\n\n<!-- File: .claude/skills/release-changelog/SKILL.md (Tokens: ~79 | Category: anthropic-skill) -->\n---\nname: release-changelog\ndescription: Use when auditing Newton changelog fragments, building a dated release changelog, or synchronizing a release build back to main.\n---\n\n# Newton Release Changelog\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-changelog/SKILL.md`. If it is unavailable, stop\nwithout modifying the changelog.\n\n<!-- File: .claude/skills/release-notes/SKILL.md (Tokens: ~83 | Category: anthropic-skill) -->\n---\nname: release-notes\ndescription: Use when drafting or reviewing Newton GitHub Release notes, release announcements, or high-level release summaries for patch, minor, RC, or final releases.\n---\n\n# Newton Release Notes\n\nFrom the repository root, read and follow the canonical workflow at\n`.agents/skills/release-notes/SKILL.md`. If it is unavailable, stop without\ndrafting or revising release text.\n</yakaai_skills>"}