Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/instructions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Agent Instructions & Skills Manifest

Provenance tracking for all Copilot instruction files and agent skills.

Legend: **upstream** = copied from awesome-copilot as-is · **customized** = forked
from awesome-copilot with local changes · **project-specific** = written for bdpl,
no upstream equivalent.

## Instructions

| File | Status | Source |
|------|--------|--------|
| `python.instructions.md` | **customized** | [awesome-copilot](https://github.com/github/awesome-copilot/blob/main/instructions/python.instructions.md) |
| `pytest.instructions.md` | **project-specific** | — |
| `code-review-generic.instructions.md` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/blob/main/instructions/code-review-generic.instructions.md) |
| `security-and-owasp.instructions.md` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/blob/main/instructions/security-and-owasp.instructions.md) |
| `agent-skills.instructions.md` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/blob/main/instructions/agent-skills.instructions.md) |
| `instructions.instructions.md` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/blob/main/instructions/instructions.instructions.md) |

## Skills

| Skill | Status | Source |
|-------|--------|--------|
| `add-disc-fixture` | **project-specific** | — |
| `gh-cli` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/tree/main/skills/gh-cli) |
| `gh-commit` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/tree/main/skills/gh-commit) |
| `make-repo-contribution` | **upstream** | [awesome-copilot](https://github.com/github/awesome-copilot/tree/main/skills/make-repo-contribution) |

## Local Modifications

Changes made to files forked from awesome-copilot. Keep this up to date when
making further edits so upstream syncs can be done safely.

### `python.instructions.md`

Upstream version is a generic PEP 8 guide. Customized to match bdpl's actual
tooling and conventions:

- **Line length**: 79 → 100 (matches `line-length = 100` in `pyproject.toml`)
- **Type hints**: Replaced `typing.List[str]` / `typing.Dict` / `typing.Optional`
guidance with modern syntax (`list[str]`, `dict[str, int]`, `X | None`)
- **Added project conventions section**: `from __future__ import annotations`,
`dataclasses` with `slots=True`, `struct` for binary parsing, `typer`/`rich`
- **String style**: Added double-quote preference (ruff format default)
- **Import sorting**: Added isort-style via ruff `I` rule
- **Tooling**: Added `ruff check .` and `ruff format .` as pre-commit steps
- **Comments**: Changed "write clear and concise comments for each function" to
"only comment code that needs clarification" (matches AGENTS.md style guide)
- **Docstring example**: Modernized to single-line summary style per PEP 257
- **Removed**: Over-commenting guidance, `typing` module recommendation,
mention of external dependency comments

## Upstream Sync Guide

When pulling updates from awesome-copilot:

- **upstream** — safe to overwrite with newer version
- **customized** — merge manually; check "Local Modifications" above for what to preserve
- **project-specific** — no upstream equivalent; maintained independently
118 changes: 118 additions & 0 deletions .github/instructions/pytest.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
description: 'Pytest conventions and testing patterns for the bdpl project'
applyTo: 'tests/**/*.py'
---

# Pytest Conventions

## Project Test Structure

```
tests/
├── conftest.py # Shared fixtures (_fixture_path, _analyze_fixture, disc fixtures)
├── test_disc_matrix.py # Cross-disc parametrized tests (6 parametrizations)
├── test_disc{N}_scan.py # Per-disc integration tests
├── test_fixture_integrity.py # Fixture file validation
├── test_reader.py # BinaryReader unit tests
├── test_mpls_parse.py # MPLS parser tests
├── test_clpi_parse.py # CLPI parser tests
├── test_index_bdmv.py # index.bdmv parser tests
├── test_movieobject_bdmv.py # MovieObject parser tests
├── test_ig_stream.py # IG stream parser tests
├── test_cli.py # CLI subprocess tests
└── fixtures/disc{N}/ # Bundled BDMV metadata fixtures
```

## Fixture Patterns

### Disc Analysis Fixtures (conftest.py)

- Use `@pytest.fixture(scope="session")` for disc analysis — parsing is expensive.
- Helper `_fixture_path(name)` resolves fixture directories and validates structure.
- Helper `_analyze_fixture(path)` runs `scan_disc()` and returns `DiscAnalysis`.
- Each disc gets a fixture like `disc3(request)` that calls `_analyze_fixture`.

```python
@pytest.fixture(scope="session")
def disc7(request):
"""Disc with commentary audio and creditless extras."""
path = _fixture_path("disc7")
if path is None:
pytest.skip("disc7 fixture not available")
return _analyze_fixture(path)
```

### Adding a New Disc Fixture

1. Create `tests/fixtures/disc{N}/` with PLAYLIST/, CLIPINF/, index.bdmv, MovieObject.bdmv.
2. Files go directly under `disc{N}/` — NOT under `disc{N}/BDMV/`.
3. Add the fixture to `conftest.py` with a descriptive docstring.
4. Add to ALL 6 parametrizations in `test_disc_matrix.py`.
5. Create `test_disc{N}_scan.py` with per-disc assertions.

## Test Patterns

### Per-Disc Integration Tests

Each disc test file follows a consistent structure:

```python
def test_episode_count(disc7):
assert len(disc7.episodes) == 6

def test_special_features(disc7):
cats = Counter(sf.category for sf in disc7.special_features)
assert cats["commentary"] == 2
assert cats["creditless_op"] == 1
```

### Matrix Tests (test_disc_matrix.py)

Cross-disc parametrized tests validate invariants across all fixtures:

```python
@pytest.mark.parametrize("fixture_name,expected", [
("disc1", 6),
("disc3", 5),
# ... all discs
])
def test_episode_count(fixture_name, expected, request):
da = request.getfixturevalue(fixture_name)
assert len(da.episodes) == expected
```

When adding a disc, update ALL parametrizations:
- `test_episode_count`
- `test_special_feature_count`
- `test_episode_numbering`
- `test_no_warnings` (or expected warnings)
- `test_playlist_classification_coverage`
- `test_episode_confidence`

### Unit Tests

Use small, focused tests with inline binary data or minimal fixtures:

```python
def test_read_u32(self):
r = BinaryReader(b"\x00\x01\x00\x02")
assert r.read_u32() == 0x00010002
```

## Running Tests

```bash
pytest tests/ -v # All tests
pytest tests/test_disc7_scan.py -v # Single disc
pytest tests/ -k "matrix" -v # Matrix tests only
pytest tests/ -x # Stop on first failure
```

## Conventions

- Use `assert` statements directly — no `self.assertEqual`.
- Group related assertions in a single test when they share expensive setup.
- Use `Counter` from `collections` for category breakdowns.
- Test names follow `test_{what}` pattern (e.g., `test_episode_count`, `test_special_features`).
- Skip tests gracefully when fixtures are unavailable (`pytest.skip`).
- Never commit copyrighted media (m2ts streams) — fixtures contain only structural metadata.
40 changes: 24 additions & 16 deletions .github/instructions/python.instructions.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,63 @@
---
description: 'Python coding conventions and guidelines'
description: 'Python coding conventions and guidelines for the bdpl project'
applyTo: '**/*.py'
---

# Python Coding Conventions

## Project-Specific Conventions

- Python 3.10+ required; use `from __future__ import annotations` in all modules.
- Use `dataclasses` with `slots=True` for data models.
- Use the `struct` module for binary parsing — no external binary-parsing deps.
- Use `typer` for CLI commands and `rich` for terminal output.
- Line length limit is **100 characters** (configured in `pyproject.toml` via ruff).
- Use double quotes for strings (configured via ruff format).
- Import sorting follows isort-style rules (ruff `I` rule).

## Python Instructions

- Write clear and concise comments for each function.
- Ensure functions have descriptive names and include type hints.
- Provide docstrings following PEP 257 conventions.
- Use the `typing` module for type annotations (e.g., `List[str]`, `Dict[str, int]`).
- Provide docstrings following PEP 257 conventions for public functions.
- Use modern Python type syntax (`list[str]`, `dict[str, int]`, `X | None`) — no `typing.List`/`typing.Dict`/`typing.Optional`.
- Break down complex functions into smaller, more manageable functions.
- Only comment code that needs clarification; avoid obvious comments.

## General Instructions

- Always prioritize readability and clarity.
- For algorithm-related code, include explanations of the approach used.
- Write code with good maintainability practices, including comments on why certain design decisions were made.
- Handle edge cases and write clear exception handling.
- For libraries or external dependencies, mention their usage and purpose in comments.
- Parsers should be robust — never crash on malformed binary data.
- Use consistent naming conventions and follow language-specific best practices.
- Write concise, efficient, and idiomatic code that is also easily understandable.

## Code Style and Formatting

- Follow the **PEP 8** style guide for Python.
- Maintain proper indentation (use 4 spaces for each level of indentation).
- Ensure lines do not exceed 79 characters.
- Follow **PEP 8** with the project's 100-character line limit.
- Maintain proper indentation (4 spaces).
- Place function and class docstrings immediately after the `def` or `class` keyword.
- Use blank lines to separate functions, classes, and code blocks where appropriate.
- Run `ruff check .` and `ruff format .` before committing.

## Edge Cases and Testing

- Always include test cases for critical paths of the application.
- Account for common edge cases like empty inputs, invalid data types, and large datasets.
- Include comments for edge cases and the expected behavior in those cases.
- Write unit tests for functions and document them with docstrings explaining the test cases.
- See `pytest.instructions.md` for project-specific testing patterns.

## Example of Proper Documentation

```python
def calculate_area(radius: float) -> float:
"""
Calculate the area of a circle given the radius.

"""Calculate the area of a circle given the radius.

Parameters:
radius (float): The radius of the circle.
radius: The radius of the circle.

Returns:
float: The area of the circle, calculated as π * radius^2.
The area of the circle, calculated as π * radius².
"""
import math
return math.pi * radius ** 2
Expand Down