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
1 change: 1 addition & 0 deletions .agents/skills/quantmind-dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Development workflow for contributing to the QuantMind codebase.
- Opening or updating a pull request → `references/pull-request.md`
- Implementing or refactoring anything under `quantmind/` →
`references/develop-components.md` (read it **before** writing code)
- Adding or editing a page under `contexts/` → `references/write-contexts.md`

A feature task usually chains all three: develop → commit → pull request.

Expand Down
15 changes: 7 additions & 8 deletions .agents/skills/quantmind-dev/references/develop-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,13 @@ When adding a source to an existing operation:

## Tests

- Location mirrors the module: `tests/<module>/test_<topic>.py`.
- Subclass `unittest.TestCase` (run via pytest).
- Mock external services (network, LLM APIs, filesystem where practical);
tests must pass offline.
- Cover the success path **and** at least one failure path per public
function.
- Coverage floor is enforced by `pytest --cov` in `scripts/verify.sh`; new
code should not lower branch coverage.
Follow the canonical [test standard](tests.md) before writing tests: where they
live, the offline-and-deterministic default suite, the change→test obligations,
and how live behavior goes in a `scripts/verify_<component>_e2e.py` slice rather
than a unit test. In short: mirror the module at `tests/<module>/test_<topic>.py`,
mock across boundaries so the suite passes offline, cover a success path **and**
a failure path per public function, and keep branch coverage from dropping (the
`pytest --cov` floor in `scripts/verify.sh`).

## Examples

Expand Down
72 changes: 72 additions & 0 deletions .agents/skills/quantmind-dev/references/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Writing tests for QuantMind

The canonical test standard. Read this before adding or changing tests. It
covers where tests live, why the default suite is offline, coverage, how live
behavior is verified, and the change→test obligations that keep coverage honest.

## Where tests live

- Mirror the module under test: `tests/<module>/test_<topic>.py`.
- Subclass `unittest.TestCase`, or `unittest.IsolatedAsyncioTestCase` for
`async` code. Everything runs via `pytest`.
- Put shared builders and fixtures in a module helper (e.g.
`tests/paper_helpers.py`), not inline in every test.

## The default suite is offline and deterministic

- No real network, no real LLM, no dependence on wall-clock or randomness.
- Mock only across a boundary: patch the SDK runner (`Runner.run` or
`run_with_observability`) for agents, patch the HTTP client for fetchers, use
an in-memory (`:memory:`) store. Use real objects for in-package types.
- Cover the success path **and** at least one failure path per public function
(typed errors, boundary rejection, timeout).
- Assert observable behavior and values, not implementation details you expect
to refactor.

## Coverage

- `pytest --cov=quantmind --cov-fail-under=75` runs inside `scripts/verify.sh`.
New code must not lower branch coverage.
- Coverage measures `quantmind/` only — `scripts/` and `tests/` are not
measured. Adding a test that only exists to raise a `scripts/` file's coverage
is pointless (see the next section).

## Live / end-to-end behavior

- Real-network or real-LLM behavior belongs in a bounded script
`scripts/verify_<component>_e2e.py`: gated on the required credential
(skip-not-fail when it is unset), bounded by `asyncio.wait_for`, over a small
fixture, ending in a clear PASS/FAIL line. Wire it into
`.github/workflows/e2e.yml` (path filters + schedule).
- **Do not unit-test a script.** No offline test should import a
`scripts/verify_*` module to assert its constants, model list, or wiring —
that only restates the source, rots on every edit, and adds no real coverage.
An e2e script is validated by *running* it in the e2e workflow, not by a
meta-test.

## Best practices

- One behavior per test; name it after the guarantee, not the mechanism.
- Reproduce a bug with a failing test **before** fixing it, then keep it as the
regression.
- For cross-provider or structured-output code, mock the SDK runner and assert
every branch offline — the strict path, the fallback path, and that unrelated
errors propagate — rather than reaching a real provider.
- Prefer table-free explicitness: a reader should see the input and the expected
outcome in the test body.

## Change → test obligations

| When you ... | Add or update |
|---|---|
| Add or change a public callable / flow | Offline success + failure tests in `tests/<module>/`; a magic-introspection test if it follows `(input, *, cfg)`. |
| Add a knowledge schema | Validation success + failure, plus a dump/load round-trip. |
| Add cross-provider or LLM-call behavior | Offline tests with the SDK runner mocked, covering every branch (e.g. strict output + json-object fallback + error propagation). |
| Add a public-network source or parser | Offline mocked parse / boundary / continuation tests **and** a `scripts/verify_<component>_e2e.py` slice. |
| Fix a bug | A regression test that fails before the fix and passes after. |
| Add or edit a `contexts/**/*.md` page | Keep `## Quick Summary` before `## Contents`, the Contents anchors matching the `##` sections, and any index links resolving — `tests/test_contexts.py` enforces this. |

## Required check

`bash scripts/verify.sh` (ruff, ruff-format, basedpyright, import-linter,
`pytest --cov`) must pass before every push. CI runs the same harness.
56 changes: 56 additions & 0 deletions .agents/skills/quantmind-dev/references/write-contexts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Writing contexts pages for QuantMind

The canonical standard for authoring or editing anything under `contexts/`. Read
it before adding or changing a design or dev page. `tests/test_contexts.py`
(part of `scripts/verify.sh`) enforces the structural rules below, so a page
that ignores them fails the build.

## When to add a page

- Add a design page only for real design content — an agreed behavior an
implementation must preserve. No placeholders, empty directories, or
speculative component pages.
- Organize by package or feature: `contexts/design/<package>/<topic>.md`. Do not
add an intermediate `components/` directory.
- Keep code the source of truth for behavior; a page explains decisions and
lists any current gap (state whether it is current, planned, or both).

## Required page structure

- Every `contexts/**/*.md` opens with `## Quick Summary`, then `## Contents`,
both within the first 80 lines and in that order.
- Quick Summary is the routing preview (Purpose / Read when / Load next or Owner
/ Status). It routes a reader; it does not replace reading the page in full.
- The `## Contents` links must **exactly** match the page's `##` section
headings, excluding Quick Summary and Contents. Anchors are GitHub-style:
lowercase, punctuation stripped, spaces and hyphens collapsed to one hyphen
(`## The Fallback Ladder` → `#the-fallback-ladder`).
- Register the page in its index and keep index links resolving: a design page
in the global index `contexts/design/README.md`; a dev route in
`contexts/dev/README.md`.
- Match the prose wrapping of the surrounding pages (existing contexts pages
hard-wrap at roughly 76 columns). The no-hard-wrap rule in `github-writing.md`
is for GitHub issue and PR bodies, not for contexts pages.

## Mermaid diagrams

GitHub renders a fenced ```` ```mermaid ```` block natively — embed the diagram,
never a pre-rendered image. A mermaid block adds no `##` heading, so it never
affects the Quick Summary / Contents anchor check. Keep diagrams compact:

- **Direction follows the diagram's story, not the screen.** Use `LR` for a
linear pipeline, ladder, or request path; use `TD` for a layered or
hierarchical structure (a subgraph-per-layer map).
- **Prefer `LR` whenever the flow is essentially linear.** Mermaid's default
node height is large, so a `TD` chart stacks tall and pushes the page down
several screens; GitHub instead scrolls a wide `LR` chart horizontally.
- **Short node text.** Push detail to edge labels or the prose beneath the
diagram. Quote any label with special characters (`()`, `/`, `=`, `→`).
- **Split past ~15–20 nodes**, or group with `subgraph`. Do not mix `TD` and
`LR` in one chart; use subgraphs if parts need different layouts.

## Required check

`tests/test_contexts.py` runs inside `bash scripts/verify.sh` and validates the
progressive-disclosure structure, the Contents/anchor match, and every index
link. Run it before pushing a contexts change.
1 change: 1 addition & 0 deletions .claude/skills/quantmind-dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Development workflow for contributing to the QuantMind codebase.
- Opening or updating a pull request → `references/pull-request.md`
- Implementing or refactoring anything under `quantmind/` →
`references/develop-components.md` (read it **before** writing code)
- Adding or editing a page under `contexts/` → `references/write-contexts.md`

A feature task usually chains all three: develop → commit → pull request.

Expand Down
15 changes: 7 additions & 8 deletions .claude/skills/quantmind-dev/references/develop-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,13 @@ When adding a source to an existing operation:

## Tests

- Location mirrors the module: `tests/<module>/test_<topic>.py`.
- Subclass `unittest.TestCase` (run via pytest).
- Mock external services (network, LLM APIs, filesystem where practical);
tests must pass offline.
- Cover the success path **and** at least one failure path per public
function.
- Coverage floor is enforced by `pytest --cov` in `scripts/verify.sh`; new
code should not lower branch coverage.
Follow the canonical [test standard](tests.md) before writing tests: where they
live, the offline-and-deterministic default suite, the change→test obligations,
and how live behavior goes in a `scripts/verify_<component>_e2e.py` slice rather
than a unit test. In short: mirror the module at `tests/<module>/test_<topic>.py`,
mock across boundaries so the suite passes offline, cover a success path **and**
a failure path per public function, and keep branch coverage from dropping (the
`pytest --cov` floor in `scripts/verify.sh`).

## Examples

Expand Down
72 changes: 72 additions & 0 deletions .claude/skills/quantmind-dev/references/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Writing tests for QuantMind

The canonical test standard. Read this before adding or changing tests. It
covers where tests live, why the default suite is offline, coverage, how live
behavior is verified, and the change→test obligations that keep coverage honest.

## Where tests live

- Mirror the module under test: `tests/<module>/test_<topic>.py`.
- Subclass `unittest.TestCase`, or `unittest.IsolatedAsyncioTestCase` for
`async` code. Everything runs via `pytest`.
- Put shared builders and fixtures in a module helper (e.g.
`tests/paper_helpers.py`), not inline in every test.

## The default suite is offline and deterministic

- No real network, no real LLM, no dependence on wall-clock or randomness.
- Mock only across a boundary: patch the SDK runner (`Runner.run` or
`run_with_observability`) for agents, patch the HTTP client for fetchers, use
an in-memory (`:memory:`) store. Use real objects for in-package types.
- Cover the success path **and** at least one failure path per public function
(typed errors, boundary rejection, timeout).
- Assert observable behavior and values, not implementation details you expect
to refactor.

## Coverage

- `pytest --cov=quantmind --cov-fail-under=75` runs inside `scripts/verify.sh`.
New code must not lower branch coverage.
- Coverage measures `quantmind/` only — `scripts/` and `tests/` are not
measured. Adding a test that only exists to raise a `scripts/` file's coverage
is pointless (see the next section).

## Live / end-to-end behavior

- Real-network or real-LLM behavior belongs in a bounded script
`scripts/verify_<component>_e2e.py`: gated on the required credential
(skip-not-fail when it is unset), bounded by `asyncio.wait_for`, over a small
fixture, ending in a clear PASS/FAIL line. Wire it into
`.github/workflows/e2e.yml` (path filters + schedule).
- **Do not unit-test a script.** No offline test should import a
`scripts/verify_*` module to assert its constants, model list, or wiring —
that only restates the source, rots on every edit, and adds no real coverage.
An e2e script is validated by *running* it in the e2e workflow, not by a
meta-test.

## Best practices

- One behavior per test; name it after the guarantee, not the mechanism.
- Reproduce a bug with a failing test **before** fixing it, then keep it as the
regression.
- For cross-provider or structured-output code, mock the SDK runner and assert
every branch offline — the strict path, the fallback path, and that unrelated
errors propagate — rather than reaching a real provider.
- Prefer table-free explicitness: a reader should see the input and the expected
outcome in the test body.

## Change → test obligations

| When you ... | Add or update |
|---|---|
| Add or change a public callable / flow | Offline success + failure tests in `tests/<module>/`; a magic-introspection test if it follows `(input, *, cfg)`. |
| Add a knowledge schema | Validation success + failure, plus a dump/load round-trip. |
| Add cross-provider or LLM-call behavior | Offline tests with the SDK runner mocked, covering every branch (e.g. strict output + json-object fallback + error propagation). |
| Add a public-network source or parser | Offline mocked parse / boundary / continuation tests **and** a `scripts/verify_<component>_e2e.py` slice. |
| Fix a bug | A regression test that fails before the fix and passes after. |
| Add or edit a `contexts/**/*.md` page | Keep `## Quick Summary` before `## Contents`, the Contents anchors matching the `##` sections, and any index links resolving — `tests/test_contexts.py` enforces this. |

## Required check

`bash scripts/verify.sh` (ruff, ruff-format, basedpyright, import-linter,
`pytest --cov`) must pass before every push. CI runs the same harness.
56 changes: 56 additions & 0 deletions .claude/skills/quantmind-dev/references/write-contexts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Writing contexts pages for QuantMind

The canonical standard for authoring or editing anything under `contexts/`. Read
it before adding or changing a design or dev page. `tests/test_contexts.py`
(part of `scripts/verify.sh`) enforces the structural rules below, so a page
that ignores them fails the build.

## When to add a page

- Add a design page only for real design content — an agreed behavior an
implementation must preserve. No placeholders, empty directories, or
speculative component pages.
- Organize by package or feature: `contexts/design/<package>/<topic>.md`. Do not
add an intermediate `components/` directory.
- Keep code the source of truth for behavior; a page explains decisions and
lists any current gap (state whether it is current, planned, or both).

## Required page structure

- Every `contexts/**/*.md` opens with `## Quick Summary`, then `## Contents`,
both within the first 80 lines and in that order.
- Quick Summary is the routing preview (Purpose / Read when / Load next or Owner
/ Status). It routes a reader; it does not replace reading the page in full.
- The `## Contents` links must **exactly** match the page's `##` section
headings, excluding Quick Summary and Contents. Anchors are GitHub-style:
lowercase, punctuation stripped, spaces and hyphens collapsed to one hyphen
(`## The Fallback Ladder` → `#the-fallback-ladder`).
- Register the page in its index and keep index links resolving: a design page
in the global index `contexts/design/README.md`; a dev route in
`contexts/dev/README.md`.
- Match the prose wrapping of the surrounding pages (existing contexts pages
hard-wrap at roughly 76 columns). The no-hard-wrap rule in `github-writing.md`
is for GitHub issue and PR bodies, not for contexts pages.

## Mermaid diagrams

GitHub renders a fenced ```` ```mermaid ```` block natively — embed the diagram,
never a pre-rendered image. A mermaid block adds no `##` heading, so it never
affects the Quick Summary / Contents anchor check. Keep diagrams compact:

- **Direction follows the diagram's story, not the screen.** Use `LR` for a
linear pipeline, ladder, or request path; use `TD` for a layered or
hierarchical structure (a subgraph-per-layer map).
- **Prefer `LR` whenever the flow is essentially linear.** Mermaid's default
node height is large, so a `TD` chart stacks tall and pushes the page down
several screens; GitHub instead scrolls a wide `LR` chart horizontally.
- **Short node text.** Push detail to edge labels or the prose beneath the
diagram. Quote any label with special characters (`()`, `/`, `=`, `→`).
- **Split past ~15–20 nodes**, or group with `subgraph`. Do not mix `TD` and
`LR` in one chart; use subgraphs if parts need different layouts.

## Required check

`tests/test_contexts.py` runs inside `bash scripts/verify.sh` and validates the
progressive-disclosure structure, the Contents/anchor match, and every index
link. Run it before pushing a contexts change.
16 changes: 9 additions & 7 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ on:
- 'quantmind/configs/structure.py'
- 'quantmind/flows/paper/**'
- 'quantmind/preprocess/outline.py'
- 'quantmind/utils/structured_output.py'
- 'pyproject.toml'
schedule:
- cron: "17 3 * * *"
Expand Down Expand Up @@ -96,6 +97,7 @@ jobs:
- 'quantmind/library/**'
- 'quantmind/preprocess/outline.py'
- 'quantmind/preprocess/format/pdf.py'
- 'quantmind/utils/structured_output.py'
- 'pyproject.toml'

news:
Expand Down Expand Up @@ -176,9 +178,9 @@ jobs:
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.structure == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 18
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}

steps:
- name: Checkout
Expand All @@ -201,17 +203,17 @@ jobs:
- name: Install project runtime dependencies
run: uv pip install --python .venv/bin/python -e .

- name: Check OpenAI credential
id: openai
- name: Check OpenRouter credential
id: openrouter
shell: bash
run: |
if [[ -n "${OPENAI_API_KEY}" ]]; then
if [[ -n "${OPENROUTER_API_KEY}" ]]; then
echo "available=true" >> "$GITHUB_OUTPUT"
else
echo "available=false" >> "$GITHUB_OUTPUT"
echo "::notice::Skipping structure-retrieval E2E because OPENAI_API_KEY is not configured."
echo "::notice::Skipping structure-retrieval E2E because OPENROUTER_API_KEY is not configured."
fi

- name: Run live structure-retrieval E2E
if: steps.openai.outputs.available == 'true'
if: steps.openrouter.outputs.available == 'true'
run: .venv/bin/python scripts/verify_structure_e2e.py
4 changes: 4 additions & 0 deletions contexts/design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ implementation must preserve.
| Mind | [Build and retrieve from a page-preserving structure tree](mind/retrieval.md) |
| Operations | [Public operation naming](operations/naming.md) |
| Operations | [Orchestration and construction altitude](operations/orchestration.md) |
| Utils | [Cross-provider structured output](utils/structured_output.md) |

## Organization Rules

Expand All @@ -51,3 +52,6 @@ implementation must preserve.
- Use code and tests to check current behavior. Keep `docs/` focused on
user-facing guides, examples, and catalogs; those pages may link here but
must not maintain a second copy of a design.
- Follow the [contexts authoring standard](../../.agents/skills/quantmind-dev/references/write-contexts.md)
when adding or editing a page — required page structure, index registration,
and Mermaid diagram guidance live there.
Loading
Loading