diff --git a/.gitignore b/.gitignore index 1813518..0b2b7ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Ignore everything by default. This working tree contains independent repositories. +# Ignore everything except the public ecosystem policy and qualification files. /* # Files owned by ml4t/ecosystem. diff --git a/AGENTS.md b/AGENTS.md index 4123a9e..63b1b79 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,23 +25,45 @@ Every other library's sandbox config grants write access to `ml4t-specs-dev/`; if the volume of specs work ever justifies one, change this paragraph first. +## Reloaded Maintenance + +The shared contributor policy also covers these independent repositories. Their own maintenance +agents own queues, reproductions, reviews, fixes, CI and documentation. Support covers bug, +security and compatibility fixes and preserves existing docs. Direct new features to current ML4T +libraries. They retain native qualification and documentation workflows; the current-library matrix +below does not automatically apply. + +| Public repository | Sibling release checkout | Private workspace | Migration partner | +|---|---|---|---| +| `stefan-jansen/zipline-reloaded` | `zipline-reloaded/` | `zipline-reloaded-dev/` | Backtest | +| `stefan-jansen/pyfolio-reloaded` | `pyfolio-reloaded/` | `pyfolio-reloaded-dev/` | Diagnostic | +| `stefan-jansen/alphalens-reloaded` | `alphalens-reloaded/` | `alphalens-reloaded-dev/` | Diagnostic | +| `stefan-jansen/empyrical-reloaded` | `empyrical-reloaded/` | `empyrical-reloaded-dev/` | Diagnostic | + ## Local Repository Model -The directory containing this repository also contains independent Git repositories: +The parent directory is a plain container, not a Git repository. Its children are independent +checkouts: +- `ml4t-ecosystem/` is this public standards and qualification repository. +- `ml4t-dev/` is the private coordinator workspace for shared setup, routing and cross-library work. - `ml4t-{library}/` is the local checkout of the public release repository. Its default branch, tags, workflows, package metadata, and release history belong to that library. - `ml4t-{library}-dev/` is a private development workspace for agent instructions, work units, research, issue drafts, and transitions. It may direct changes into the sibling release checkout. - Additional directories with suffixes such as a feature name are temporary worktrees or historical workspaces. Inspect their Git metadata before using them. -- The parent `ml4t/ecosystem` repository tracks only files allowed by its root `.gitignore`. Never - force-add a nested repository or development workspace. +- Reloaded release checkouts and their private sidecars follow the table above. +- Never add a sibling repository or private workspace to this repository. + +The coordinator owns shared policy and infrastructure. Individual library agents own their source +work and maintenance queues. Specs remains managed without a dedicated sidecar. Migration partners +provide expertise and measured evidence; they do not take ownership of the Reloaded queues. Before changing a library, read both this file and the target library or development workspace `AGENTS.md`. The more specific instructions apply within that repository. -Each library's release checkout also carries `docs/book-guide/index.md`: the authoritative +Each current library's release checkout also carries `docs/book-guide/index.md`: the authoritative chapter-to-API cross-reference (book notebook -> concept -> library API -> docs page). An agent mapping a book chapter to a library's surface should read that file first, not grep the seven repos. @@ -54,32 +76,17 @@ Use these authorities in order: 3. The library's root `AGENTS.md` for repository-specific commands and constraints. 4. `docs/standards/` in this repository for requirements shared by all libraries. 5. `status/` and `reviews/` for current and dated cross-library evidence. -6. `.workspace/` for local agent state only. It is not public policy and is not tracked here (see "Local agent state"). +6. The private development sidecar for agent state. It is not public policy. Do not treat a stale local tag, feature branch, development-workspace issue draft, or copied status table as current release evidence. ## Local agent state -Shared by Claude and Codex, and **untracked by design**: the root `.gitignore` -ignores everything not explicitly allowed, so none of this is published. - -| Path | What | -|---|---| -| `.workspace/memory/MEMORY_INDEX.md` | Index of curated memory: `status`, `last_referenced`, `tokens`, `anchors` per file | -| `.workspace/memory/*.md` | Curated memory, read on demand. Currently conventions, deployment, metrics, status | -| `.workspace/PROJECT_MAP.md` | Ecosystem overview, package relationships, tool stack | -| `.workspace/transitions/YYYY-MM-DD/HHMMSS.md` | Session progress, one file per event | -| `.workspace/work/` | Active work units | - -Read a memory file when its topic is relevant; the index says what exists and -whether it is current. This file does not `@`-include the index, unlike the -per-library `AGENTS.md` files: the index is untracked here, so an include would -dangle for anyone who clones the public repository. - -All of this moved out of `.claude/` on 2026-09-08. `.claude/` now holds only -Claude-specific configuration, and transitions are written by the `transition` -plugin's own hooks rather than a per-project one. +Shared coordinator memory, active work, transitions and agent-specific configuration belong in +the sibling private `ml4t-dev/` checkout. Library state belongs in its own sidecar. Curated memory +is read on demand; each sidecar includes only its memory index. This public guide does not include +private memory or depend on a private checkout being present for contributors. ## Standard Work Lifecycle @@ -122,6 +129,9 @@ See `docs/standards/issues-and-pull-requests.md` for the normative requirements. Each library owns its tutorials, how-to guides, reference pages, explanations, examples, and API documentation. The ecosystem repository owns the common process and index. +The requirements below apply to current libraries. Reloaded libraries preserve their existing +Sphinx documentation and deployment routes; changes to those are owned by their maintenance agent. + - Use MkDocs with the shared ML4T theme and navigation conventions. - Run `uv run mkdocs build --strict` for every documentation change and release. - Publish each library under its assigned `https://ml4trading.io/docs/{library}/` route. @@ -133,7 +143,7 @@ See `docs/standards/documentation.md` for the deployment contract and required c ## Compatibility and Release Qualification -Each library must pass installation, import, tests, type checking, and package builds on Python 3.12 +Each current library must pass installation, import, tests, type checking, and package builds on Python 3.12 through 3.14 on Linux, macOS, and Windows. Python 3.15 prereleases must pass core installation and non-hardware-dependent tests on all three systems unless a dependency-blocked library has a configured prerelease wait. A waiting library keeps a truthful upper bound and runs a visible @@ -159,7 +169,7 @@ pre-commit run --all-files Install hooks once with `pre-commit install`. Commit at coherent passing checkpoints, without waiting to be asked. -`ml4t/ecosystem` and the library repos it hosts are **public**, so a push here is a publication to +`ml4t/ecosystem` and the separate library repos are **public**, so a push here is a publication to outside contributors and downstream users, not a backup. Confirm before pushing unless the active task already authorizes publication. This is the narrow exception to the standing "push private repos freely" rule in `~/.claude/CLAUDE.md`; it applies because these repos are public, not because pushing diff --git a/README.md b/README.md index 7ee0512..ed0a67a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,21 @@ This repository does not contain library source code and is not a runtime depend [ecosystem documentation](https://ml4t.github.io/ecosystem/) or the tracked documents under `docs/standards/`, `status/`, `reviews/`, and `decisions/`. +## Repository layout and maintenance + +Keep `ml4t-ecosystem/` beside the independent library checkouts in a plain parent directory. +Private development workspaces are sibling repositories; they are not part of this public +checkout. `audit-workspaces` uses that parent by default, while configuration, templates and +public evidence remain in this repository. Use `--root` to audit another library directory. + +The shared [contribution policy](CONTRIBUTING.md) also covers Zipline Reloaded, Pyfolio Reloaded, +Alphalens Reloaded and Empyrical Reloaded. Each retains its own repository, maintenance owner, +native CI and documentation. Support covers bug, security and compatibility fixes and preserves +docs. New features belong in current ML4T libraries. Backtest supplies Zipline migration guidance; +Diagnostic supplies Pyfolio, Alphalens and Empyrical guidance. Migration claims require evidence +for the specific workflow. Stable-release qualification below applies to the seven current +libraries. + ## Stable-release policy ML4T supports every stable CPython release from Python 3.12 through the latest stable version on diff --git a/src/ml4t_ecosystem/cli.py b/src/ml4t_ecosystem/cli.py index 05eee10..124a7b9 100644 --- a/src/ml4t_ecosystem/cli.py +++ b/src/ml4t_ecosystem/cli.py @@ -38,7 +38,7 @@ def _parser() -> argparse.ArgumentParser: workspaces = subparsers.add_parser( "audit-workspaces", help="check local release checkouts and development sidecars" ) - workspaces.add_argument("--root", type=Path, default=ROOT) + workspaces.add_argument("--root", type=Path, default=ROOT.parent) workspaces.add_argument("--output", type=Path) monitor = subparsers.add_parser("monitor", help="check issue and pull-request response targets") diff --git a/tests/test_relocated_cli.py b/tests/test_relocated_cli.py new file mode 100644 index 0000000..4685811 --- /dev/null +++ b/tests/test_relocated_cli.py @@ -0,0 +1,46 @@ +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path + + +def test_cli_finds_sibling_repositories_after_controller_relocation(tmp_path: Path) -> None: + original = Path(__file__).resolve().parents[1] + container = tmp_path / "libraries" + controller = container / "ml4t-ecosystem" + for directory in ("src", "config", ".github"): + shutil.copytree( + original / directory, + controller / directory, + ignore=shutil.ignore_patterns("__pycache__"), + ) + (container / "ml4t-data").mkdir() + environment = {**os.environ, "PYTHONPATH": str(controller / "src")} + + def invoke(*arguments: str) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [sys.executable, "-m", "ml4t_ecosystem.cli", *arguments], + cwd=tmp_path, + env=environment, + capture_output=True, + text=True, + check=False, + ) + + configuration = invoke("validate-config") + assert configuration.returncode == 0, configuration.stderr + audit = invoke("audit-workspaces") + assert audit.returncode == 1, audit.stderr + data = json.loads(audit.stdout)["reports"][0] + assert data["root"] == str(container) + assert ( + next(check for check in data["checks"] if check["code"] == "release.exists")["status"] + == "pass" + ) + + target = tmp_path / "contributor-checkout" + templates = invoke("sync-templates", str(target), "--repository", "ml4t/data") + assert templates.returncode == 0, templates.stderr + assert (target / ".github/ISSUE_TEMPLATE/bug.yml").is_file()