diff --git a/.github/codeowners/README.md b/.github/codeowners/README.md index 03b827fe8..4534573e2 100644 --- a/.github/codeowners/README.md +++ b/.github/codeowners/README.md @@ -66,11 +66,11 @@ be merge-blocking. ## Migrated AIConfigurator Snapshot -The full AIC source import preserves `python/aisimulate/CODEOWNERS` and -`python/aisimulate/.github/codeowners/` as inactive provenance. GitHub only -discovers CODEOWNERS at the repository root, `.github/`, or `docs/`, so the -generated root file in this PR is the only active repository policy. The root -policy routes changes to those preserved ownership artifacts to AISimulate -Infra plus maintainers to keep the active and historical policies from being +The full AIC source import preserves `python/aisimulate/.github/codeowners/` as +inactive provenance, but its generated `CODEOWNERS` file is not retained. +GitHub only discovers CODEOWNERS at the repository root, `.github/`, or `docs/`, +so the generated root file is the only active repository policy. The root +policy routes changes to the preserved ownership tooling to AISimulate Infra +plus maintainers to keep the active and historical policies from being confused. The DevOps team is not listed in the active policy and is never a required code-owner approver. diff --git a/.github/codeowners/areas.yaml b/.github/codeowners/areas.yaml index 562315df1..09e7b5ade 100644 --- a/.github/codeowners/areas.yaml +++ b/.github/codeowners/areas.yaml @@ -9,6 +9,9 @@ areas: - label: maintainers github_team: "@ai-dynamo/access-aisimulate-maintain" path_globs: + - AGENTS.md + - CODE_OF_CONDUCT.md + - DEVELOPMENT.md - LICENSE - THIRD_PARTY_NOTICES.md - README.md @@ -171,6 +174,10 @@ shared: owners: [infra, maintainers] - glob: SECURITY.md owners: [infra, maintainers] + - glob: AGENTS.md + owners: [infra, maintainers] + - glob: DEVELOPMENT.md + owners: [infra, maintainers] - glob: .gitattributes owners: [infra, maintainers] # Imported AIC repository metadata is inactive in this monorepo, but changes @@ -190,12 +197,6 @@ shared: owners: [infra, maintainers] - glob: python/aisimulate/.pre-commit-config.yaml owners: [infra, maintainers] - - glob: python/aisimulate/AGENTS.md - owners: [infra, maintainers] - - glob: python/aisimulate/DEVELOPMENT.md - owners: [infra, maintainers] - - glob: python/aisimulate/SECURITY.md - owners: [infra, maintainers] - glob: python/aisimulate/eslint.config.js owners: [infra, maintainers] - glob: python/aisimulate/pyproject.toml @@ -212,8 +213,6 @@ shared: owners: [infra, maintainers] - glob: python/aisimulate/.github/workflows/codeowners.yml owners: [infra, maintainers] - - glob: python/aisimulate/CODEOWNERS - owners: [infra, maintainers] - glob: .github/codeowners/ owners: [infra, maintainers] - glob: .github/workflows/codeowners.yml diff --git a/.github/codeowners/test_aisimulate_policy.py b/.github/codeowners/test_aisimulate_policy.py index d57f8f2f9..57fa5bb35 100644 --- a/.github/codeowners/test_aisimulate_policy.py +++ b/.github/codeowners/test_aisimulate_policy.py @@ -140,7 +140,6 @@ def test_representative_routing_contract() -> None: INFRA, MAINTAINERS, } - assert _owners("python/aisimulate/CODEOWNERS") == {INFRA, MAINTAINERS} assert _owners("crates/core/deny.toml") == { FPE, MOCKER, @@ -150,6 +149,9 @@ def test_representative_routing_contract() -> None: } assert _owners("deny.toml") == {INFRA, MAINTAINERS} assert _owners("CODEOWNERS") == {INFRA, MAINTAINERS} + assert _owners("AGENTS.md") == {INFRA, MAINTAINERS} + assert _owners("DEVELOPMENT.md") == {INFRA, MAINTAINERS} + assert _owners("CODE_OF_CONDUCT.md") == {MAINTAINERS} assert _owners("README.md") == {MAINTAINERS} assert _owners("SECURITY.md") == {INFRA, MAINTAINERS} assert _owners("CONTRIBUTING.md") == {MAINTAINERS} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..f44ea52a8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,121 @@ +# AGENTS + +This file adds explicit repository-wide development guards. + +## Required First Step + +Before making any change under: + +- `python/aisimulate/src/aiconfigurator/generator/**` + +MUST read: + +- `python/aisimulate/.claude/rules/generator-development.md` + +## Required Collector First Step + +Before making any change under `python/aisimulate/collector/**` MUST read: + +- `python/aisimulate/.claude/rules/collector/layer_permissions.md` (layer + permission table, module boundary, dispatch-vs-skip rule) +- `python/aisimulate/.claude/rules/collector/failure_handling.md` + (observe-don't-predict doctrine, escalation decision tree) +- For case YAML work: + `python/aisimulate/.claude/rules/collector/case_authoring.md` + +For adding a new Collector operation, additionally follow +`python/aisimulate/.claude/skills/aic-collector-op-development/SKILL.md` +(consumer-contract, case-identity, deduplication, and validation gates). Skills are procedural +runbooks; if a skill and a `python/aisimulate/.claude/rules/` file ever +disagree, the rule file wins. + +## Required Third-Party Attribution + +Before adding code or other content copied, adapted, translated, or +substantially derived from an external project, MUST: + +- Identify the upstream repository, immutable commit or tag, original path, + and applicable license. This applies to source code, tests, configuration + files, patches, fixtures, documentation, and generated derivatives. +- Preserve all applicable upstream copyright, license, attribution, and NOTICE + material, and mark modified files as modified when the upstream license + requires it. +- Record the source URL and revision in the file header or an adjacent README. + For formats that cannot carry comments, use an adjacent attribution or + license file that is included in distributions. +- Add an entry to the root `THIRD_PARTY_NOTICES.md` identifying the derived + files, upstream source and immutable revision, copyright owner, applicable + license, and whether the files were modified. The root notice is canonical; + keep `python/aisimulate/THIRD_PARTY_NOTICES.md` byte-identical so the notice + is included in Python distributions. Run + `python3 scripts/check_packaged_legal_files.py` after either copy changes. +- Do not hand-edit generated attribution artifacts. Update their source or + generation process instead. + +The repository's Apache-2.0 license and NVIDIA copyright header do not replace +an upstream license or attribution requirement. Do not label third-party code +as exclusively NVIDIA-authored. If the source, revision, license, compatibility, +or required notice is unclear, stop and request maintainer or Open Source Review +Board guidance before committing the derived content. This is a required gate, +not optional documentation. + +## Cursor Cloud specific instructions + +### Project overview + +AISimulate is a Python and Rust CLI/SDK for predicting LLM serving behavior and +optimizing inference deployment configurations. See `README.md` for details. + +### Environment setup + +Python dependencies are managed via `uv` with the +`python/aisimulate/uv.lock` lockfile. The project environment lives at +`python/aisimulate/.venv/`. + +- **Install/refresh deps:** + `uv sync --project python/aisimulate --extra dev` +- **Performance data:** Current op profiles are parquet files under + `python/aisimulate/src/aiconfigurator_core/systems/data/////` + and are checked in directly. Legacy `*.txt` perf files, when present, use Git + LFS; run `git lfs pull` only when working with those legacy assets. + +### Lint / Test / Run + +- **Lint:** `python/aisimulate/.venv/bin/ruff check --config python/aisimulate/pyproject.toml python/aisimulate tests` + and `python/aisimulate/.venv/bin/ruff format --check --config python/aisimulate/pyproject.toml python/aisimulate tests` + (see `DEVELOPMENT.md`) +- **Unit tests:** `python/aisimulate/.venv/bin/pytest -c python/aisimulate/pytest.ini python/aisimulate/tests -m unit` + (no external deps or LFS data needed) +- **Build tests (PR subset):** `python/aisimulate/.venv/bin/pytest -c python/aisimulate/pytest.ini python/aisimulate/tests -m "unit or build"` + (requires LFS data for the `build`-marked tests) +- **CLI:** `aiconfigurator cli generate --model-path Qwen/Qwen3-32B-FP8 --total-gpus 8 --system h200_sxm` (works without LFS data) +### Known environment caveats + +1. **Legacy LFS data:** `github-cloud.githubusercontent.com` may be blocked by + network egress restrictions. If `git lfs pull` fails, tests that explicitly + exercise legacy text assets may fail; current parquet-backed workflows do + not depend on those legacy files. +2. **TTY tests:** 4 tests in + `python/aisimulate/tests/unit/cli/test_plain_output.py` may fail because the + agent runs in a non-TTY environment. +3. **Rust tests:** + `python/aisimulate/tests/unit/sdk/test_rust_engine_step.py` requires `cargo` + with network access to `crates.io`. It will fail if that domain is blocked. +4. **macOS pytest-timeout crash dialogs:** The `timeout = 120` setting in + `python/aisimulate/pytest.ini` uses SIGALRM by default, which triggers + "Python unexpectedly quit" crash reporter popups on macOS. Pass + `-p no:timeout` to disable it locally. +5. **torch-dependent tests:** + `python/aisimulate/tests/unit/sdk/database/test_moe_dispatch.py` requires + `torch` (not installed in the default dev venv). Ignore it with + `--ignore=python/aisimulate/tests/unit/sdk/database/test_moe_dispatch.py`. + +## CODEOWNERS + +The root `CODEOWNERS` is generated from `.github/codeowners/areas.yaml` - never +hand-edit it; CI fails on drift. Repository rules must require the `codeowners` +check to make failures merge-blocking. If the check fails on a new directory, +claim it in `areas.yaml`, regenerate with +`.github/codeowners/emit_codeowners.py`, and commit every changed source and +generated artifact together. The `aic-codeowners` skill covers all flows (who +reviews a change, gate failures, routing changes, external contributor grants). diff --git a/CODEOWNERS b/CODEOWNERS index 29fd9b8ed..1717a3d96 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -27,11 +27,14 @@ # === maintainers (@ai-dynamo/access-aisimulate-maintain) === /docs/ @ai-dynamo/access-aisimulate-maintain /LICENSE @ai-dynamo/access-aisimulate-maintain +/AGENTS.md @ai-dynamo/access-aisimulate-maintain /README.md @ai-dynamo/access-aisimulate-maintain /SECURITY.md @ai-dynamo/access-aisimulate-maintain +/DEVELOPMENT.md @ai-dynamo/access-aisimulate-maintain /CONTRIBUTING.md @ai-dynamo/access-aisimulate-maintain /CONTRIBUTORS.md @ai-dynamo/access-aisimulate-maintain /tests/conftest.py @ai-dynamo/access-aisimulate-maintain +/CODE_OF_CONDUCT.md @ai-dynamo/access-aisimulate-maintain /THIRD_PARTY_NOTICES.md @ai-dynamo/access-aisimulate-maintain # === forward-pass-engine (@ai-dynamo/aisimulate-forward-pass-engine-codeowners) === @@ -90,6 +93,7 @@ # --- Shared ownership: multi-team (any one approves; wins via last-match) --- /scripts/ @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain +/AGENTS.md @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /deny.toml @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /CODEOWNERS @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /Cargo.lock @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain @@ -99,6 +103,7 @@ /SECURITY.md @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /docs/sweeper/ @ai-dynamo/aisimulate-sweeper-codeowners @ai-dynamo/access-aisimulate-maintain /.gitattributes @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain +/DEVELOPMENT.md @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /tests/sweeper/ @ai-dynamo/aisimulate-sweeper-codeowners @ai-dynamo/access-aisimulate-maintain /docs/aic-sync.md @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /docs/core-api.md @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/access-aisimulate-maintain @@ -127,19 +132,15 @@ /tests/test_unified_cli.py @ai-dynamo/aisimulate-replay-codeowners @ai-dynamo/aisimulate-sweeper-codeowners @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/access-aisimulate-maintain /crates/core/src/perfmodel/ @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/.github/ @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain -/python/aisimulate/AGENTS.md @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /crates/core/tests/perfmodel/ @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/.gitignore @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain -/python/aisimulate/CODEOWNERS @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/pytest.ini @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain -/python/aisimulate/SECURITY.md @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /tests/test_stack_discovery.py @ai-dynamo/aisimulate-replay-codeowners @ai-dynamo/aisimulate-sweeper-codeowners @ai-dynamo/access-aisimulate-maintain /tests/test_host_offload_cli.py @ai-dynamo/aisimulate-replay-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/.dockerignore @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /.github/workflows/codeowners.yml @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /crates/core/src/engine/timing.rs @ai-dynamo/aisimulate-mocker-codeowners @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/.gitattributes @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain -/python/aisimulate/DEVELOPMENT.md @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/pyproject.toml @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/aisimulate-sweeper-codeowners @ai-dynamo/aisimulate-replay-codeowners @ai-dynamo/aisimulate-mocker-codeowners @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /crates/tests/public-api/Cargo.toml @ai-dynamo/aisimulate-forward-pass-engine-codeowners @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain /python/aisimulate/.coderabbit.yaml @ai-dynamo/aisimulate-infra-codeowners @ai-dynamo/access-aisimulate-maintain diff --git a/python/aisimulate/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md similarity index 99% rename from python/aisimulate/CODE_OF_CONDUCT.md rename to CODE_OF_CONDUCT.md index a0e54489d..3442957ed 100644 --- a/python/aisimulate/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -135,4 +135,4 @@ For answers to common questions about this code of conduct, see the FAQ at [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations \ No newline at end of file +[translations]: https://www.contributor-covenant.org/translations diff --git a/python/aisimulate/DEVELOPMENT.md b/DEVELOPMENT.md similarity index 55% rename from python/aisimulate/DEVELOPMENT.md rename to DEVELOPMENT.md index c96456c3b..6647547d2 100644 --- a/python/aisimulate/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,5 +1,5 @@ @@ -23,30 +23,28 @@ needed when developing against retained legacy `*.txt` perf assets or running their compatibility tests; for that work, install Git LFS and run `git lfs pull`. -### 2. Set Up Python Virtual Environment +### 2. Install Development Dependencies ```bash -# Create virtual environment -python3 -m venv .venv - -# Activate virtual environment -source .venv/bin/activate +uv sync --project python/aisimulate --extra dev ``` -### 3. Install Development Dependencies +This creates `python/aisimulate/.venv`, builds the unified native extension, +and installs the sole Python distribution together with its development tools. + +To activate the environment: ```bash -# Build the unified native extension and install the sole Python distribution -pip install -e "./python/aisimulate[dev]" +source python/aisimulate/.venv/bin/activate ``` -### 4. Install Pre-Commit Hooks +### 3. Install Pre-Commit Hooks ```bash -pre-commit install +pre-commit install --config python/aisimulate/.pre-commit-config.yaml ``` -This installs: +The development environment includes: - The `aisimulate` package and its `aiconfigurator`, `aiconfigurator_core`, and `aisimulate_core` compatibility namespaces in editable mode - All runtime dependencies @@ -54,12 +52,14 @@ This installs: ## AIConfigurator mirror boundaries -Keep upstream AIC Python code/data in `src/aiconfigurator/` and -`src/aiconfigurator_core/`. AISimulate-specific compatibility glue belongs in -`src/aisimulate_core/`, not in those mirrors. The corresponding Rust mirror is -`../../crates/core/src/perfmodel/`. See the repository's -[AIC synchronization guide](../../docs/aic-sync.md) before applying an upstream -AIC commit; packaging and CI changes are adapted manually rather than mirrored. +Keep upstream AIC Python code/data in +`python/aisimulate/src/aiconfigurator/` and +`python/aisimulate/src/aiconfigurator_core/`. AISimulate-specific compatibility +glue belongs in `python/aisimulate/src/aisimulate_core/`, not in those mirrors. +The corresponding Rust mirror is `crates/core/src/perfmodel/`. See the +repository's [AIC synchronization guide](docs/aic-sync.md) before applying an +upstream AIC commit; packaging and CI changes are adapted manually rather than +mirrored. ### Optional: Install Ruff Extension @@ -75,20 +75,20 @@ This project uses [Ruff](https://github.com/astral-sh/ruff) for linting and form ```bash # Check for linting issues -ruff check . +ruff check --config python/aisimulate/pyproject.toml python/aisimulate tests # Auto-fix linting issues -ruff check --fix . +ruff check --fix --config python/aisimulate/pyproject.toml python/aisimulate tests ``` #### Run Formatting ```bash # Check formatting -ruff format --check . +ruff format --check --config python/aisimulate/pyproject.toml python/aisimulate tests # Apply formatting -ruff format . +ruff format --config python/aisimulate/pyproject.toml python/aisimulate tests ``` ### Pre-commit Hooks @@ -98,7 +98,7 @@ Pre-commit hooks automatically run checks before each commit. #### Run Pre-commit Manually ```bash -pre-commit run --all-files +pre-commit run --all-files --config python/aisimulate/.pre-commit-config.yaml ``` ### Running Tests @@ -106,22 +106,23 @@ pre-commit run --all-files This project uses [pytest](https://docs.pytest.org/en/stable/) for testing. ```bash -# Run all tests -pytest tests +# Run repository-level tests +python -m pytest -c pytest.ini tests -# Run tests for a specific component -pytest tests/unit -pytest tests/e2e +# Run Python package tests +python -m pytest -c python/aisimulate/pytest.ini python/aisimulate/tests # GitHub PR / build subset (unit + a small stable E2E subset) -pytest -m "unit or build" +python -m pytest -c python/aisimulate/pytest.ini \ + python/aisimulate/tests -m "unit or build" ``` ## Data Collection (Advanced) Data collection is typically not required for development. The repository includes pre-collected performance databases for supported systems. -If you need to collect new data for a new GPU type or framework version, refer to the [Collector README](collector/README.md). +If you need to collect new data for a new GPU type or framework version, refer +to the [Collector README](python/aisimulate/collector/README.md). ## Contributing @@ -133,17 +134,20 @@ Before contributing, please read: ### Adding a New Model -Refer to [How to Add a New Model](docs/add_a_new_model.md). +Refer to [How to Add a New Model](python/aisimulate/docs/add_a_new_model.md). ### Running Automation Scripts -Refer to the [Automation README](tools/automation/README.md). +Explore the automation helpers under `python/aisimulate/tools/automation/`. ## Getting Help -- **Documentation**: Check the `docs/` directory -- **Issues**: Open an issue on [GitHub](https://github.com/ai-dynamo/aiconfigurator/issues) -- **Examples**: Explore `tools/simple_sdk_demo/` for SDK usage examples +- **Documentation**: Check the root `docs/` directory and + `python/aisimulate/docs/` +- **Issues**: Open an issue on + [GitHub](https://github.com/ai-dynamo/aisimulate/issues) +- **Examples**: Explore `python/aisimulate/tools/simple_sdk_demo/` for SDK usage + examples ## License diff --git a/README.md b/README.md index a59e90d3e..1164250ad 100644 --- a/README.md +++ b/README.md @@ -326,5 +326,5 @@ python -m pytest -c pytest.ini tests python -m pytest -c python/aisimulate/pytest.ini python/aisimulate/tests -m "unit or build" ``` -See [DEVELOPMENT.md](python/aisimulate/DEVELOPMENT.md) for environment and test details and +See [DEVELOPMENT.md](DEVELOPMENT.md) for environment and test details and [CONTRIBUTING.md](CONTRIBUTING.md) before sending a change. diff --git a/python/aisimulate/AGENTS.md b/python/aisimulate/AGENTS.md deleted file mode 100644 index 19b2ae63f..000000000 --- a/python/aisimulate/AGENTS.md +++ /dev/null @@ -1,69 +0,0 @@ -# AGENTS - -This file adds an explicit guard for generator rule edits. - -## Required First Step - -Before making any change under: -- `src/aiconfigurator/generator/**` - -MUST read: -- `.claude/rules/generator-development.md` - -## Required Collector First Step - -Before making any change under `collector/**` MUST read: -- `.claude/rules/collector/layer_permissions.md` (layer permission table, - module boundary, dispatch-vs-skip rule) -- `.claude/rules/collector/failure_handling.md` (observe-don't-predict - doctrine, escalation decision tree) -- For case YAML work: `.claude/rules/collector/case_authoring.md` - -For adding a new Collector operation, additionally follow -`.claude/skills/aic-collector-op-development/SKILL.md` (consumer-contract, -case-identity, deduplication, and validation gates). Skills are procedural -runbooks; if a skill and a `.claude/rules/` file ever disagree, the rule -file wins. - -## Cursor Cloud specific instructions - -### Project overview - -AIConfigurator is a Python CLI/SDK tool for optimizing LLM inference deployment configurations. See `README.md` for full details. - -### Environment setup - -Dependencies are managed via `uv` with a `uv.lock` lockfile. The virtual environment lives at `.venv/`. All commands below assume `.venv/bin/` is on PATH or you prefix with `.venv/bin/`. - -- **Install/refresh deps:** `python3 -m uv sync --extra dev` -- **Performance data:** Current op profiles are parquet files under - `aic-core/src/aiconfigurator_core/systems/data/////` - and are checked in directly. Legacy `*.txt` perf files, when present, use - Git LFS; run `git lfs pull` only when working with those legacy assets. - -### Lint / Test / Run - -- **Lint:** `ruff check .` and `ruff format --check .` (see `DEVELOPMENT.md`) -- **Unit tests:** `pytest -m unit` (868+ tests; no external deps or LFS data needed) -- **Build tests (PR subset):** `pytest -m "unit or build"` (requires LFS data for the `build`-marked tests) -- **CLI:** `aiconfigurator cli generate --model-path Qwen/Qwen3-32B-FP8 --total-gpus 8 --system h200_sxm` (works without LFS data) -### Known environment caveats - -1. **Legacy LFS data:** `github-cloud.githubusercontent.com` may be blocked by - network egress restrictions. If `git lfs pull` fails, tests that explicitly - exercise legacy text assets may fail; current parquet-backed workflows do - not depend on those legacy files. -2. **TTY tests:** 4 tests in `tests/unit/cli/test_plain_output.py` may fail because the agent runs in a non-TTY environment. -3. **Rust tests:** `tests/unit/sdk/test_rust_engine_step.py` requires `cargo` with network access to `crates.io`. It will fail if that domain is blocked. -4. **macOS pytest-timeout crash dialogs:** The `timeout = 120` setting in `pytest.ini` uses SIGALRM by default, which triggers "Python unexpectedly quit" crash reporter popups on macOS. Pass `-p no:timeout` to disable it locally: `.venv/bin/pytest -m unit -p no:timeout` -5. **torch-dependent tests:** `tests/unit/sdk/database/test_moe_dispatch.py` requires `torch` (not installed in the default dev venv). Ignore it with `--ignore=tests/unit/sdk/database/test_moe_dispatch.py`. - -## CODEOWNERS - -The root `CODEOWNERS` is generated from `.github/codeowners/areas.yaml` - never -hand-edit it; CI fails on drift. Repository rules must require the `codeowners` -check to make failures merge-blocking. If the check fails on a new directory, -claim it in `areas.yaml`, regenerate with -`emit_codeowners.py`, and commit every changed source and generated artifact -together. The `aic-codeowners` skill covers all flows (who reviews a change, -gate failures, routing changes, external contributor grants). diff --git a/python/aisimulate/CODEOWNERS b/python/aisimulate/CODEOWNERS deleted file mode 100644 index 70cf7726f..000000000 --- a/python/aisimulate/CODEOWNERS +++ /dev/null @@ -1,102 +0,0 @@ -# CODEOWNERS -- generated from .github/codeowners/areas.yaml. -# Do not hand-edit. Change areas.yaml and regenerate. -# -# GitHub reads this file; engineers don't. To see who reviews a change, run: -# python .github/codeowners/who_owns.py --codeowners CODEOWNERS --changed # owners of your PR's files -# python .github/codeowners/who_owns.py --codeowners CODEOWNERS ... # owners of specific paths -# -# Area index (base owner per subsystem; the catch-all owns everything else): -# devops @ai-dynamo/devops -# docs @ai-dynamo/maintainers-aiconfigurator -# generators @ai-dynamo/aiconfigurator-generators -# infra @ai-dynamo/aiconfigurator-infra -# runtime @ai-dynamo/aiconfigurator-runtime -# * @ai-dynamo/contributors-aiconfigurator (catch-all) -# -# Teams referenced (each must exist in the org before this file validates): -# @ai-dynamo/aiconfigurator-generators -# @ai-dynamo/aiconfigurator-infra -# @ai-dynamo/aiconfigurator-runtime -# @ai-dynamo/contributors-aiconfigurator -# @ai-dynamo/devops -# @ai-dynamo/maintainers-aiconfigurator - -* @ai-dynamo/contributors-aiconfigurator - -# === runtime (@ai-dynamo/aiconfigurator-runtime) === -/src/ @ai-dynamo/aiconfigurator-runtime -/aic-core/ @ai-dynamo/aiconfigurator-runtime -/collector/ @ai-dynamo/aiconfigurator-runtime - -# === generators (@ai-dynamo/aiconfigurator-generators) === -/tools/ @ai-dynamo/aiconfigurator-generators - -# === infra (@ai-dynamo/aiconfigurator-infra) === -/docker/ @ai-dynamo/aiconfigurator-infra -/uv.lock @ai-dynamo/aiconfigurator-infra -/.agents/ @ai-dynamo/aiconfigurator-infra -/.claude/ @ai-dynamo/aiconfigurator-infra -/.github/ @ai-dynamo/aiconfigurator-infra -/AGENTS.md @ai-dynamo/aiconfigurator-infra -/.gitignore @ai-dynamo/aiconfigurator-infra -/Cargo.toml @ai-dynamo/aiconfigurator-infra -/pytest.ini @ai-dynamo/aiconfigurator-infra -/SECURITY.md @ai-dynamo/aiconfigurator-infra -/.dockerignore @ai-dynamo/aiconfigurator-infra -/.gitattributes @ai-dynamo/aiconfigurator-infra -/DEVELOPMENT.md @ai-dynamo/aiconfigurator-infra -/pyproject.toml @ai-dynamo/aiconfigurator-infra -/.coderabbit.yaml @ai-dynamo/aiconfigurator-infra -/eslint.config.js @ai-dynamo/aiconfigurator-infra -/.pre-commit-config.yaml @ai-dynamo/aiconfigurator-infra - -# === docs (@ai-dynamo/maintainers-aiconfigurator) === -/docs/ @ai-dynamo/maintainers-aiconfigurator -/LICENSE @ai-dynamo/maintainers-aiconfigurator -/README.md @ai-dynamo/maintainers-aiconfigurator -/CONTRIBUTING.md @ai-dynamo/maintainers-aiconfigurator -/CONTRIBUTORS.md @ai-dynamo/maintainers-aiconfigurator -/CODE_OF_CONDUCT.md @ai-dynamo/maintainers-aiconfigurator -/THIRD_PARTY_NOTICES.md @ai-dynamo/maintainers-aiconfigurator - -# === Path overrides: a subsystem nested inside another area's tree. -# More specific, so they win via last-match over the area globs above. === -/tools/sanity_check/ @ai-dynamo/aiconfigurator-runtime -/tools/support_matrix/ @ai-dynamo/aiconfigurator-runtime -/tools/simple_sdk_demo/ @ai-dynamo/aiconfigurator-runtime -/src/aiconfigurator/cli/ @ai-dynamo/aiconfigurator-generators -/src/aiconfigurator/generator/ @ai-dynamo/aiconfigurator-generators - -# --- Shared ownership: multi-team (any one approves; wins via last-match) --- -/src/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/maintainers-aiconfigurator -/tests/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/aiconfigurator-generators @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/tools/ @ai-dynamo/aiconfigurator-generators @ai-dynamo/maintainers-aiconfigurator -/docker/ @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/uv.lock @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/.agents/ @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/.claude/ @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/.github/ @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/AGENTS.md @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/aic-core/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/maintainers-aiconfigurator -/.gitignore @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/CODEOWNERS @ai-dynamo/devops -/Cargo.toml @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/collector/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/maintainers-aiconfigurator -/pytest.ini @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/SECURITY.md @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/.dockerignore @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/.gitattributes @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/DEVELOPMENT.md @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/pyproject.toml @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/.coderabbit.yaml @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/eslint.config.js @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/tools/sanity_check/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/maintainers-aiconfigurator -/tools/support_matrix/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/maintainers-aiconfigurator -/tools/simple_sdk_demo/ @ai-dynamo/aiconfigurator-runtime @ai-dynamo/maintainers-aiconfigurator -/.pre-commit-config.yaml @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator -/src/aiconfigurator/cli/ @ai-dynamo/aiconfigurator-generators @ai-dynamo/maintainers-aiconfigurator -/src/aiconfigurator/generator/ @ai-dynamo/aiconfigurator-generators @ai-dynamo/maintainers-aiconfigurator -/docs/dynamo_deployment_guide.md @ai-dynamo/aiconfigurator-runtime @ai-dynamo/aiconfigurator-infra @ai-dynamo/maintainers-aiconfigurator - -# --- File-type ownership: unanchored patterns (wins via last-match at any depth) --- -deny.toml @ai-dynamo/devops diff --git a/python/aisimulate/CONTRIBUTING.md b/python/aisimulate/CONTRIBUTING.md deleted file mode 100644 index e69aba80c..000000000 --- a/python/aisimulate/CONTRIBUTING.md +++ /dev/null @@ -1,159 +0,0 @@ - - -# Contribution Guidelines - -Contributions that fix documentation errors or that make small changes -to existing code can be contributed directly by following the rules -below and submitting an appropriate PR. - -Contributions intended to add significant new functionality must -follow a more collaborative path described in the following -points. Before submitting a large PR that adds a major enhancement or -extension, be sure to submit a GitHub issue that describes the -proposed change so that the Dynamo team can provide feedback. - -- As part of the GitHub issue discussion, a design for your change - will be agreed upon. An up-front design discussion is required to - ensure that your enhancement is done in a manner that is consistent - with Dynamo's overall architecture. - -- The Dynamo project is spread across multiple GitHub Repositories. - The Dynamo team will provide guidance about how and where your enhancement - should be implemented. - -- Testing is a critical part of any Dynamo - enhancement. You should plan on spending significant time on - creating tests for your change. The Dynamo team will help you to - design your testing so that it is compatible with existing testing - infrastructure. - -- If your enhancement provides a user visible feature then you need to - provide documentation. - - -# Join the Community - -Join the community on [Discord](https://discord.gg/mRJ2KNzwYE) to get help, share your ideas, and stay updated on the latest news and developments. - -# Contribution Rules - -- The code style convention is enforced by common formatting tools - for a given language (such as clang-format for c++, ruff for python). - See below on how to ensure your contributions conform. In general please follow - the existing conventions in the relevant file, submodule, module, - and project when you add new code or when you extend/fix existing - functionality. - -- Avoid introducing unnecessary complexity into existing code so that - maintainability and readability are preserved. - -- Try to keep code changes for each pull request (PR) as concise as possible: - - - Fillout PR template with clear description and mark applicable checkboxes - - - Avoid committing commented-out code. - - - Wherever possible, each PR should address a single concern. If - there are several otherwise-unrelated things that should be fixed - to reach a desired endpoint, it is perfectly fine to open several - PRs and state in the description which PR depends on another - PR. The more complex the changes are in a single PR, the more time - it will take to review those changes. - - - Make sure that the build log is clean, meaning no warnings or - errors should be present. - - - Make sure all tests pass. - - - Reviewers are auto-requested from the team that owns the areas your - PR touches (see the generated `CODEOWNERS`). To preview them: - `python .github/codeowners/who_owns.py --codeowners CODEOWNERS --changed`. - If the `codeowners` check fails because your PR adds a directory no - area claims, add a one-line claim in `.github/codeowners/areas.yaml`, - regenerate, and commit both files (see `.github/codeowners/README.md` - or the `aic-codeowners` skill). Never edit `CODEOWNERS` directly - it - is generated. - - -- Make sure that you can contribute your work to open source (no - license and/or patent conflict is introduced by your code). - You must certify compliance with the - [license terms](https://github.com/ai-dynamo/aiconfigurator/blob/main/LICENSE) - and sign off on the [Developer Certificate of Origin (DCO)](https://developercertificate.org) - described below before your pull request (PR) can be merged. - -- Thanks in advance for your patience as we review your contributions; - we do appreciate them! - -# Developer Certificate of Origin - -Dynamo is an open source product released under -the Apache 2.0 license (see either -[the Apache site](https://www.apache.org/licenses/LICENSE-2.0) or -the [LICENSE file](./LICENSE)). The Apache 2.0 license allows you -to freely use, modify, distribute, and sell your own products -that include Apache 2.0 licensed software. - -We respect intellectual property rights of others and we want -to make sure all incoming contributions are correctly attributed -and licensed. A Developer Certificate of Origin (DCO) is a -lightweight mechanism to do that. - -The DCO is a declaration attached to every contribution made by -every developer. In the commit message of the contribution, -the developer simply adds a `Signed-off-by` statement and thereby -agrees to the DCO, which you can find below or at [DeveloperCertificate.org](http://developercertificate.org/). - -``` -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. -``` - -We require that every contribution to Dynamo is signed with -a Developer Certificate of Origin. Additionally, please use your real name. -We do not accept anonymous contributors nor those utilizing pseudonyms. - -Each commit must include a DCO which looks like this - -``` -Signed-off-by: Jane Smith -``` -You may type this line on your own when writing your commit messages. -However, if your user.name and user.email are set in your git configs, -you can use `-s` or `--signoff` to add the `Signed-off-by` line to -the end of the commit message. diff --git a/python/aisimulate/CONTRIBUTORS.md b/python/aisimulate/CONTRIBUTORS.md deleted file mode 100644 index 371e010ce..000000000 --- a/python/aisimulate/CONTRIBUTORS.md +++ /dev/null @@ -1,12 +0,0 @@ -# Contributors - -External contributors who hold area-scoped **codeownership** in this -repository. Each person below has earned review and approval rights over -one or more subsystem areas, and is added as a co-owner on those areas' -paths alongside the owning NVIDIA team. - -Generated from `.github/codeowners/external_contributors.yaml`. Do not -hand-edit — update that file and regenerate (see -`.github/codeowners/README.md`). - -_No external contributors yet._ diff --git a/python/aisimulate/README.md b/python/aisimulate/README.md index a8eb206ee..6ce087ea2 100644 --- a/python/aisimulate/README.md +++ b/python/aisimulate/README.md @@ -517,8 +517,9 @@ aiconfigurator cli support --model-path Qwen/Qwen3-32B-FP8 --system h100_sxm --b We welcome contributions from the community! Check out the below resources to get started: -- [DEVELOPMENT.md](DEVELOPMENT.md) - Set up your development environment, run tests, and follow our coding standards -- [CONTRIBUTING.md](CONTRIBUTING.md) - Contribution guidelines and requirements +- [DEVELOPMENT.md](https://github.com/ai-dynamo/aisimulate/blob/main/DEVELOPMENT.md) - Set up your development environment, run tests, and follow our coding standards +- [CONTRIBUTING.md](https://github.com/ai-dynamo/aisimulate/blob/main/CONTRIBUTING.md) - Contribution guidelines and requirements +- [CODE_OF_CONDUCT.md](https://github.com/ai-dynamo/aisimulate/blob/main/CODE_OF_CONDUCT.md) - Community standards - [Discord](https://discord.gg/mRJ2KNzwYE) - Chat with team and community ### How To Add A New Model diff --git a/python/aisimulate/SECURITY.md b/python/aisimulate/SECURITY.md deleted file mode 100644 index a8429f222..000000000 --- a/python/aisimulate/SECURITY.md +++ /dev/null @@ -1,19 +0,0 @@ - - -# Report a Security Vulnerability - -To report a potential security vulnerability in any NVIDIA product, please use either: -* This web form: [Security Vulnerability Submission Form](https://www.nvidia.com/en-us/support/submit-security-vulnerability/), or -* Send email to: [NVIDIA PSIRT](mailto:psirt@nvidia.com) - -If reporting a potential vulnerability via email, please encrypt it using NVIDIA’s public PGP key ([see PGP Key page](https://www.nvidia.com/en-us/security/pgp-key/)) and include the following information: -1. Product/Driver name and version/branch that contains the vulnerability -2. Type of vulnerability (code execution, denial of service, buffer overflow, etc.) -3. Instructions to reproduce the vulnerability -4. Proof-of-concept or exploit code -5. Potential impact of the vulnerability, including how an attacker could exploit the vulnerability - -See https://www.nvidia.com/en-us/security/ for past NVIDIA Security Bulletins and Notices. diff --git a/tests/test_source_compliance.py b/tests/test_source_compliance.py index d45dcbd88..aebae8b6c 100644 --- a/tests/test_source_compliance.py +++ b/tests/test_source_compliance.py @@ -10,7 +10,25 @@ pytestmark = pytest.mark.unit -CHECK_COPYRIGHT = Path(__file__).resolve().parents[1] / "scripts" / "check_copyright.py" +ROOT = Path(__file__).resolve().parents[1] +PACKAGE_ROOT = ROOT / "python" / "aisimulate" +CHECK_COPYRIGHT = ROOT / "scripts" / "check_copyright.py" + +ROOT_ONLY_GOVERNANCE_FILES = ( + "AGENTS.md", + "CODEOWNERS", + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "CONTRIBUTORS.md", + "DEVELOPMENT.md", + "SECURITY.md", +) +PACKAGED_LEGAL_FILES = ("LICENSE", "THIRD_PARTY_NOTICES.md") +PACKAGED_README_ROOT_LINKS = ( + "DEVELOPMENT.md", + "CONTRIBUTING.md", + "CODE_OF_CONDUCT.md", +) @pytest.fixture @@ -41,3 +59,26 @@ def test_hash_stamped_patch_is_not_rewritten_as_owned_source(checker, tmp_path): path.write_text("diff --git a/a b/a\n") assert not checker.is_source(path) + + +@pytest.mark.parametrize("name", ROOT_ONLY_GOVERNANCE_FILES) +def test_repository_governance_file_lives_only_at_root(name): + assert (ROOT / name).is_file() + assert not (PACKAGE_ROOT / name).exists() + + +@pytest.mark.parametrize("name", PACKAGED_LEGAL_FILES) +def test_wheel_local_legal_file_matches_root(name): + canonical = ROOT / name + packaged = PACKAGE_ROOT / name + + assert canonical.is_file() + assert packaged.is_file() + assert packaged.read_bytes() == canonical.read_bytes() + + +@pytest.mark.parametrize("name", PACKAGED_README_ROOT_LINKS) +def test_packaged_readme_links_root_governance_to_github(name): + readme = (PACKAGE_ROOT / "README.md").read_text() + + assert f"https://github.com/ai-dynamo/aisimulate/blob/main/{name}" in readme