nirspy 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. nirspy-0.0.1/.github/ISSUE_TEMPLATE/bug.yml +65 -0
  2. nirspy-0.0.1/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. nirspy-0.0.1/.github/ISSUE_TEMPLATE/feature.yml +49 -0
  4. nirspy-0.0.1/.github/PULL_REQUEST_TEMPLATE.md +33 -0
  5. nirspy-0.0.1/.github/dependabot.yml +24 -0
  6. nirspy-0.0.1/.github/workflows/ci.yml +79 -0
  7. nirspy-0.0.1/.gitignore +70 -0
  8. nirspy-0.0.1/.python-version +1 -0
  9. nirspy-0.0.1/CHANGELOG.md +30 -0
  10. nirspy-0.0.1/CLAUDE.md +179 -0
  11. nirspy-0.0.1/CODE_OF_CONDUCT.md +16 -0
  12. nirspy-0.0.1/CONTRIBUTING.md +114 -0
  13. nirspy-0.0.1/LICENSE +28 -0
  14. nirspy-0.0.1/PKG-INFO +171 -0
  15. nirspy-0.0.1/README.md +103 -0
  16. nirspy-0.0.1/SECURITY.md +36 -0
  17. nirspy-0.0.1/docs/architecture.md +245 -0
  18. nirspy-0.0.1/docs/roadmap.md +143 -0
  19. nirspy-0.0.1/examples/data/.gitkeep +0 -0
  20. nirspy-0.0.1/examples/pipelines/basic-preproc.yml +20 -0
  21. nirspy-0.0.1/examples/pipelines/best-practices-block-design.yml +46 -0
  22. nirspy-0.0.1/pyproject.toml +102 -0
  23. nirspy-0.0.1/requirements.txt +86 -0
  24. nirspy-0.0.1/scripts/smoke_e1.py +67 -0
  25. nirspy-0.0.1/src/nirspy/__init__.py +3 -0
  26. nirspy-0.0.1/src/nirspy/blocks/__init__.py +70 -0
  27. nirspy-0.0.1/src/nirspy/blocks/analysis.py +339 -0
  28. nirspy-0.0.1/src/nirspy/blocks/load.py +232 -0
  29. nirspy-0.0.1/src/nirspy/blocks/manual_exclude.py +100 -0
  30. nirspy-0.0.1/src/nirspy/blocks/preprocessing.py +277 -0
  31. nirspy-0.0.1/src/nirspy/blocks/quality.py +234 -0
  32. nirspy-0.0.1/src/nirspy/blocks/registry.py +127 -0
  33. nirspy-0.0.1/src/nirspy/cli/__init__.py +0 -0
  34. nirspy-0.0.1/src/nirspy/cli/main.py +83 -0
  35. nirspy-0.0.1/src/nirspy/domain/__init__.py +27 -0
  36. nirspy-0.0.1/src/nirspy/domain/block.py +118 -0
  37. nirspy-0.0.1/src/nirspy/domain/cache.py +40 -0
  38. nirspy-0.0.1/src/nirspy/domain/data_types.py +42 -0
  39. nirspy-0.0.1/src/nirspy/domain/exceptions.py +74 -0
  40. nirspy-0.0.1/src/nirspy/domain/execution.py +117 -0
  41. nirspy-0.0.1/src/nirspy/domain/pipeline.py +162 -0
  42. nirspy-0.0.1/src/nirspy/domain/validation.py +59 -0
  43. nirspy-0.0.1/src/nirspy/engine/__init__.py +24 -0
  44. nirspy-0.0.1/src/nirspy/engine/cache_adapter.py +236 -0
  45. nirspy-0.0.1/src/nirspy/engine/exceptions.py +47 -0
  46. nirspy-0.0.1/src/nirspy/engine/mne_adapter.py +371 -0
  47. nirspy-0.0.1/src/nirspy/gui/__init__.py +5 -0
  48. nirspy-0.0.1/src/nirspy/gui/app.py +49 -0
  49. nirspy-0.0.1/src/nirspy/gui/callbacks/__init__.py +0 -0
  50. nirspy-0.0.1/src/nirspy/gui/callbacks/converter_callbacks.py +188 -0
  51. nirspy-0.0.1/src/nirspy/gui/callbacks/execution_callbacks.py +326 -0
  52. nirspy-0.0.1/src/nirspy/gui/callbacks/io_callbacks.py +116 -0
  53. nirspy-0.0.1/src/nirspy/gui/callbacks/param_callbacks.py +174 -0
  54. nirspy-0.0.1/src/nirspy/gui/callbacks/pipeline_callbacks.py +252 -0
  55. nirspy-0.0.1/src/nirspy/gui/callbacks/viz_callbacks.py +174 -0
  56. nirspy-0.0.1/src/nirspy/gui/components/__init__.py +1 -0
  57. nirspy-0.0.1/src/nirspy/gui/components/block_card.py +190 -0
  58. nirspy-0.0.1/src/nirspy/gui/components/block_catalog.py +82 -0
  59. nirspy-0.0.1/src/nirspy/gui/components/condition_selector.py +57 -0
  60. nirspy-0.0.1/src/nirspy/gui/components/condition_windows_editor.py +238 -0
  61. nirspy-0.0.1/src/nirspy/gui/components/converter_view.py +119 -0
  62. nirspy-0.0.1/src/nirspy/gui/components/error_display.py +39 -0
  63. nirspy-0.0.1/src/nirspy/gui/components/hrf_plot.py +152 -0
  64. nirspy-0.0.1/src/nirspy/gui/components/param_editor.py +409 -0
  65. nirspy-0.0.1/src/nirspy/gui/components/param_metadata.py +169 -0
  66. nirspy-0.0.1/src/nirspy/gui/components/pipeline_view.py +80 -0
  67. nirspy-0.0.1/src/nirspy/gui/components/probe_viewer.py +169 -0
  68. nirspy-0.0.1/src/nirspy/gui/components/qc_dashboard.py +98 -0
  69. nirspy-0.0.1/src/nirspy/gui/components/raw_data_plot.py +96 -0
  70. nirspy-0.0.1/src/nirspy/gui/components/run_button.py +80 -0
  71. nirspy-0.0.1/src/nirspy/gui/components/tooltips.py +127 -0
  72. nirspy-0.0.1/src/nirspy/gui/layouts.py +225 -0
  73. nirspy-0.0.1/src/nirspy/gui/pages/__init__.py +0 -0
  74. nirspy-0.0.1/src/nirspy/io/__init__.py +44 -0
  75. nirspy-0.0.1/src/nirspy/io/converters.py +826 -0
  76. nirspy-0.0.1/src/nirspy/io/oxysoft_txt.py +358 -0
  77. nirspy-0.0.1/src/nirspy/io/pipeline_runner.py +195 -0
  78. nirspy-0.0.1/src/nirspy/io/pipeline_schema.json +80 -0
  79. nirspy-0.0.1/src/nirspy/io/yaml_serializer.py +247 -0
  80. nirspy-0.0.1/tests/__init__.py +0 -0
  81. nirspy-0.0.1/tests/blocks/__init__.py +0 -0
  82. nirspy-0.0.1/tests/blocks/conftest.py +61 -0
  83. nirspy-0.0.1/tests/blocks/test_analysis.py +280 -0
  84. nirspy-0.0.1/tests/blocks/test_manual_exclude.py +96 -0
  85. nirspy-0.0.1/tests/blocks/test_preprocessing.py +179 -0
  86. nirspy-0.0.1/tests/blocks/test_quality.py +186 -0
  87. nirspy-0.0.1/tests/cli/__init__.py +0 -0
  88. nirspy-0.0.1/tests/cli/test_run.py +145 -0
  89. nirspy-0.0.1/tests/conftest.py +134 -0
  90. nirspy-0.0.1/tests/domain/__init__.py +0 -0
  91. nirspy-0.0.1/tests/domain/test_block.py +163 -0
  92. nirspy-0.0.1/tests/domain/test_cache.py +134 -0
  93. nirspy-0.0.1/tests/domain/test_data_types.py +68 -0
  94. nirspy-0.0.1/tests/domain/test_exceptions.py +133 -0
  95. nirspy-0.0.1/tests/domain/test_execution.py +403 -0
  96. nirspy-0.0.1/tests/domain/test_pipeline.py +249 -0
  97. nirspy-0.0.1/tests/domain/test_validation.py +139 -0
  98. nirspy-0.0.1/tests/engine/__init__.py +0 -0
  99. nirspy-0.0.1/tests/engine/test_average_epochs_empty.py +55 -0
  100. nirspy-0.0.1/tests/engine/test_cache_adapter.py +263 -0
  101. nirspy-0.0.1/tests/engine/test_mne_adapter.py +140 -0
  102. nirspy-0.0.1/tests/engine/test_ui_error_messages.py +94 -0
  103. nirspy-0.0.1/tests/gui/__init__.py +0 -0
  104. nirspy-0.0.1/tests/gui/test_app_factory.py +83 -0
  105. nirspy-0.0.1/tests/gui/test_builder.py +345 -0
  106. nirspy-0.0.1/tests/gui/test_condition_windows_editor.py +106 -0
  107. nirspy-0.0.1/tests/gui/test_converter_view.py +236 -0
  108. nirspy-0.0.1/tests/gui/test_execution.py +317 -0
  109. nirspy-0.0.1/tests/gui/test_hrf_plot.py +109 -0
  110. nirspy-0.0.1/tests/gui/test_param_editor_list.py +69 -0
  111. nirspy-0.0.1/tests/gui/test_param_editor_metadata.py +151 -0
  112. nirspy-0.0.1/tests/gui/test_security_5a.py +202 -0
  113. nirspy-0.0.1/tests/gui/test_smoke.py +225 -0
  114. nirspy-0.0.1/tests/io/__init__.py +0 -0
  115. nirspy-0.0.1/tests/io/test_converters_condnames.py +73 -0
  116. nirspy-0.0.1/tests/io/test_oxysoft_txt.py +149 -0
  117. nirspy-0.0.1/tests/io/test_pipeline_runner.py +89 -0
  118. nirspy-0.0.1/tests/io/test_yaml_serializer.py +200 -0
  119. nirspy-0.0.1/tests/test_smoke.py +7 -0
  120. nirspy-0.0.1/third_party/licenses/README.md +9 -0
@@ -0,0 +1,65 @@
1
+ name: Bug report
2
+ description: Report a defect in NIRSPY
3
+ title: "[bug] "
4
+ labels: ["bug", "triage"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to report a bug. Please fill in the
10
+ details below so we can reproduce it.
11
+
12
+ - type: textarea
13
+ id: what-happened
14
+ attributes:
15
+ label: What happened?
16
+ description: Clear description of the unexpected behaviour.
17
+ placeholder: When I run `nirspy run pipeline.yml ...` the output ...
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: expected
23
+ attributes:
24
+ label: What did you expect?
25
+ validations:
26
+ required: true
27
+
28
+ - type: textarea
29
+ id: reproduction
30
+ attributes:
31
+ label: Reproduction steps
32
+ description: Minimal pipeline.yml and dataset (or sample data ref).
33
+ render: shell
34
+ validations:
35
+ required: true
36
+
37
+ - type: input
38
+ id: nirspy-version
39
+ attributes:
40
+ label: NIRSPY version / commit
41
+ placeholder: "0.0.1 or commit sha"
42
+ validations:
43
+ required: true
44
+
45
+ - type: input
46
+ id: python-version
47
+ attributes:
48
+ label: Python version
49
+ placeholder: "3.11.5"
50
+ validations:
51
+ required: true
52
+
53
+ - type: input
54
+ id: os
55
+ attributes:
56
+ label: OS
57
+ placeholder: "Ubuntu 22.04 / Windows 11 / macOS 14"
58
+ validations:
59
+ required: true
60
+
61
+ - type: textarea
62
+ id: traceback
63
+ attributes:
64
+ label: Traceback / logs
65
+ render: python
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/BrunoFurlanetto/nirspy/security/advisories/new
5
+ about: Please report security issues privately via GitHub Security Advisories.
6
+ - name: Question / discussion
7
+ url: https://github.com/BrunoFurlanetto/nirspy/discussions
8
+ about: Open-ended questions, design discussion, "how do I…?"
@@ -0,0 +1,49 @@
1
+ name: Feature request
2
+ description: Propose a new feature or enhancement
3
+ title: "[feat] "
4
+ labels: ["feature", "triage"]
5
+ body:
6
+ - type: textarea
7
+ id: motivation
8
+ attributes:
9
+ label: Motivation
10
+ description: What problem does this solve? Who benefits?
11
+ validations:
12
+ required: true
13
+
14
+ - type: textarea
15
+ id: proposal
16
+ attributes:
17
+ label: Proposal
18
+ description: High-level description of what should be added or changed.
19
+ validations:
20
+ required: true
21
+
22
+ - type: textarea
23
+ id: alternatives
24
+ attributes:
25
+ label: Alternatives considered
26
+ description: Other approaches you thought about and why this one wins.
27
+
28
+ - type: dropdown
29
+ id: scope
30
+ attributes:
31
+ label: Affected layer
32
+ multiple: true
33
+ options:
34
+ - domain
35
+ - engine
36
+ - blocks
37
+ - io
38
+ - gui
39
+ - cli
40
+ - docs
41
+ - ci
42
+ validations:
43
+ required: true
44
+
45
+ - type: textarea
46
+ id: references
47
+ attributes:
48
+ label: References
49
+ description: Papers, Best Practices fNIRS sections, MNE-NIRS issues, etc.
@@ -0,0 +1,33 @@
1
+ <!-- Thank you for contributing to NIRSPY. -->
2
+
3
+ ## Summary
4
+
5
+ <!-- What does this PR change and why? -->
6
+
7
+ ## Type of change
8
+
9
+ - [ ] feat — new feature
10
+ - [ ] fix — bug fix
11
+ - [ ] refactor — no behaviour change
12
+ - [ ] test — tests only
13
+ - [ ] docs — documentation only
14
+ - [ ] chore — tooling / dependencies / CI
15
+
16
+ ## Linked issues / tasks
17
+
18
+ <!-- Closes #123, refs T-00X -->
19
+
20
+ ## Checklist
21
+
22
+ - [ ] `ruff check .` passes
23
+ - [ ] `mypy src/nirspy` passes
24
+ - [ ] `pytest` passes locally
25
+ - [ ] Tests added or updated for behavioural changes
26
+ - [ ] Public API changes documented in CHANGELOG.md
27
+ - [ ] Architecture rule (`domain → engine → gui`) respected
28
+ - [ ] No new GPL dependency introduced (project is BSD-3)
29
+
30
+ ## Reproducibility note
31
+
32
+ <!-- If this PR changes pipeline behaviour, confirm: same SNIRF + same
33
+ pipeline.yml produces the same numerical output. -->
@@ -0,0 +1,24 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ day: "monday"
8
+ open-pull-requests-limit: 5
9
+ labels:
10
+ - "dependencies"
11
+ groups:
12
+ python-deps:
13
+ patterns:
14
+ - "*"
15
+
16
+ - package-ecosystem: "github-actions"
17
+ directory: "/"
18
+ schedule:
19
+ interval: "weekly"
20
+ day: "monday"
21
+ open-pull-requests-limit: 3
22
+ labels:
23
+ - "dependencies"
24
+ - "ci"
@@ -0,0 +1,79 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ lint-and-test:
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ python-version: ["3.10", "3.11", "3.12"]
21
+
22
+ steps:
23
+ - uses: actions/checkout@v6
24
+
25
+ - name: Set up Python ${{ matrix.python-version }}
26
+ uses: actions/setup-python@v6
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+ cache: "pip"
30
+ cache-dependency-path: "pyproject.toml"
31
+
32
+ - name: Install uv
33
+ run: pip install uv
34
+
35
+ - name: Install project
36
+ run: uv pip install --system -e ".[dev]" pytest-cov
37
+
38
+ - name: Ruff
39
+ run: ruff check .
40
+
41
+ - name: Mypy
42
+ run: mypy src/nirspy
43
+
44
+ - name: Pytest
45
+ run: pytest --cov=nirspy --cov-report=xml --cov-report=term
46
+
47
+ - name: Upload coverage
48
+ if: matrix.python-version == '3.12'
49
+ uses: actions/upload-artifact@v7
50
+ with:
51
+ name: coverage-xml
52
+ path: coverage.xml
53
+ if-no-files-found: warn
54
+
55
+ publish:
56
+ name: Publish to PyPI
57
+ needs: lint-and-test
58
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
59
+ runs-on: ubuntu-latest
60
+ environment:
61
+ name: pypi
62
+ url: https://pypi.org/project/nirspy/
63
+ permissions:
64
+ id-token: write
65
+ steps:
66
+ - uses: actions/checkout@v6
67
+
68
+ - name: Set up Python
69
+ uses: actions/setup-python@v6
70
+ with:
71
+ python-version: "3.12"
72
+
73
+ - name: Build sdist + wheel
74
+ run: |
75
+ python -m pip install --upgrade build
76
+ python -m build
77
+
78
+ - name: Publish to PyPI (Trusted Publisher / OIDC)
79
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,70 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+ MANIFEST
23
+
24
+ # Virtual envs
25
+ .venv/
26
+ venv/
27
+ env/
28
+ ENV/
29
+
30
+ # uv
31
+ .uv/
32
+
33
+ # Testing / coverage
34
+ .pytest_cache/
35
+ .coverage
36
+ .coverage.*
37
+ htmlcov/
38
+ .tox/
39
+ .nox/
40
+ coverage.xml
41
+ *.cover
42
+
43
+ # Type checkers
44
+ .mypy_cache/
45
+ .ruff_cache/
46
+ .pyre/
47
+
48
+ # Cache
49
+ .cache/
50
+ diskcache/
51
+
52
+ # Docs build
53
+ site/
54
+
55
+ # IDE
56
+ .vscode/
57
+ .idea/
58
+ *.swp
59
+ *.swo
60
+ .DS_Store
61
+
62
+ # Env
63
+ .env
64
+ .env.local
65
+ .env.agents
66
+
67
+ # Project-specific
68
+ *.snirf.cache
69
+ examples/data/*.snirf
70
+ !examples/data/.gitkeep
@@ -0,0 +1 @@
1
+ 3.12.2
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ Todas as mudanças relevantes do projeto serão documentadas aqui.
4
+
5
+ Formato baseado em [Keep a Changelog](https://keepachangelog.com/),
6
+ versionamento por [SemVer](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-05-21
11
+
12
+ ### Added
13
+ - Camada `domain/`: `Pipeline`, `Block` Protocol, `DataType`, `BlockSpec`, `BlockResult`, `Context`, `CacheProtocol`, exceções (`NirspyError`, `ValidationError`, `ExecutionError`).
14
+ - Camada `engine/`: `MNEAdapter` com `load_snirf`, `raw_to_od`, `beer_lambert`, `bandpass_filter`, `scalp_coupling_index`, `prune_channels`, `block_average`. `DiskCacheAdapter` com `JSONDisk` (sem pickle, S-01).
15
+ - Blocos: `LoadSnirf`, `OpticalDensity`, `BeerLambert`, `BandpassFilter`, `ScalpCouplingIndex`, `PruneChannels`, `BlockAverage`, `ManualChannelExclude`.
16
+ - IO: `yaml_serializer.dump_pipeline`/`load_pipeline`, conversor `.nirs ↔ .snirf` (`io/converters.py`), conversor Oxysoft `.txt → .snirf` (`io/oxysoft_txt.py`).
17
+ - CLI: `nirspy run pipeline.yml --input X --output Y`, `nirspy serve`, `nirspy --version`.
18
+ - GUI: Dash app factory, layout de três painéis, builder de pipeline (catalog + reorder + remove + toggle), param editor enriquecido (labels, tooltips, ranges, Optional checkbox, multiselect de canais), visualização de execução (raw, probe, QC heatmap, HRF μM), tab Convert (`.nirs↔.snirf` + Oxysoft `.txt→.snirf`).
19
+ - **T-012 — Janelas temporais por condição em `BlockAverage`**: novo dataclass `ConditionWindow`, parâmetro `per_condition_windows`, método `MNEAdapter.create_epochs_per_condition`, editor GUI auto-populado a partir do SNIRF, YAML round-trip retrocompatível.
20
+ - Segurança Etapa 5A: validação de path SNIRF (S-02), sample-count guard (S-001), bloqueio de h5py external links (S-002), `O_EXCL` em escrita (S-003), opção `strip_pii` em conversores (I-001), serialização JSON em cache (S-01).
21
+ - Templates de issue/PR, política de segurança, dependabot, cache pip e cobertura no CI.
22
+
23
+ ### Changed
24
+ - CI: removido `pytest-dash` das dev deps (unmaintained, incompatível com selenium ≥4.10).
25
+ - CI: `mypy` agora bloqueia merge (era `continue-on-error`).
26
+ - `JSONDisk.store/fetch` delegam ao `Disk` base — corrige overwrite e persistência entre instâncias.
27
+ - `BlockAverageBlock.run`: keys desconhecidas em `per_condition_windows` viram `UserWarning` (em vez de raise) — pipeline robusta a troca de SNIRF com conjunto de condições diferente.
28
+
29
+ ### Removed
30
+ - `pytest-dash` das dev dependencies.
nirspy-0.0.1/CLAUDE.md ADDED
@@ -0,0 +1,179 @@
1
+ # CLAUDE.md — nirspy
2
+
3
+ > Configurações do projeto para o time de agentes.
4
+ > Complementa e sobrescreve o CLAUDE.md global quando necessário.
5
+
6
+ ---
7
+
8
+ ## Projeto
9
+
10
+ **Nome:** nirspy
11
+ **Descrição:** GUI fNIRS-first em Python — builder modular de pipeline sobre MNE-NIRS, distribuída como open source (BSD-3).
12
+ **Stack:** Python 3.10+ · Dash · Plotly · MNE-NIRS · uv · hatchling · pytest · ruff · mypy
13
+ **Repositório:** https://github.com/BrunoFurlanetto/nirspy.git
14
+ **Ambiente local:** `nirspy serve` → `http://127.0.0.1:8050`
15
+
16
+ ---
17
+
18
+ ## Vault (Obsidian)
19
+
20
+ **Path do projeto:** `Dev projects/nirspy`
21
+ **Memory:** `Dev projects/nirspy/Memory.md`
22
+ **Session Log:** `Dev projects/nirspy/session-log.md`
23
+ **Planejamentos:** `Dev projects/nirspy/features/`
24
+ **Visão e arquitetura:** `Dev projects/nirspy/visao-do-produto.md`, `Dev projects/nirspy/arquitetura.md`, `Dev projects/nirspy/roadmap.md`
25
+
26
+ ### Abertura de sessão
27
+
28
+ Ler em paralelo antes de qualquer task:
29
+
30
+ ```
31
+ mcp_obsidian: view → Dev projects/nirspy/Memory.md
32
+ mcp_obsidian: view → Dev projects/nirspy/session-log.md
33
+ mcp_obsidian: view → Dev projects/_memory.md (ADRs globais)
34
+ ```
35
+
36
+ Se a task envolve uma feature, ler também:
37
+ ```
38
+ mcp_obsidian: view → Dev projects/nirspy/features/<nome-da-feature>.md
39
+ ```
40
+
41
+ Sempre consultar `Dev projects/nirspy/arquitetura.md` antes de criar arquivos novos — a regra das três camadas (`domain` → `engine` → `gui`) é estrita.
42
+
43
+ ### Fechamento de sessão
44
+
45
+ Seguir protocolo condicional do CLAUDE.md global. Quando registrar:
46
+
47
+ ```
48
+ mcp_obsidian: str_replace → Dev projects/nirspy/session-log.md
49
+ ```
50
+
51
+ ADR novo (decisão de design): adicionar **antes** de fechar log:
52
+ ```
53
+ mcp_obsidian: str_replace → Dev projects/nirspy/Memory.md
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Branches protegidas
59
+
60
+ Nunca commitar diretamente nem criar branches a partir de:
61
+ - `main`
62
+
63
+ Orchestrator sempre confirma branch base com Lead antes de criar nova branch.
64
+
65
+ ### Convenção de branches
66
+ ```
67
+ feature/T-xxx-nome-curto
68
+ fix/T-xxx-descricao
69
+ chore/T-xxx-descricao
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Como rodar
75
+
76
+ ```bash
77
+ # setup
78
+ uv venv
79
+ uv pip install -e ".[dev]"
80
+
81
+ # dev server
82
+ nirspy serve
83
+
84
+ # testes
85
+ pytest
86
+
87
+ # lint + types
88
+ ruff check .
89
+ mypy src/nirspy
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Ownership dos agentes
95
+
96
+ Arquitetura em três camadas (`domain` → `engine` → `gui`) determina ownership.
97
+
98
+ | Agente | Pode criar/editar | Somente leitura |
99
+ |--------|-------------------|-----------------|
100
+ | `dev` | `src/nirspy/gui/`, `src/nirspy/cli/`, `src/nirspy/blocks/` (lógica não-engine), `src/nirspy/io/`, `examples/`, `docs/` | `domain/`, `engine/` (precisa contrato dba) |
101
+ | `dba` | `src/nirspy/domain/`, `src/nirspy/engine/`, `src/nirspy/blocks/` (camada de execução MNE), `examples/pipelines/*.yml` (schema de pipeline) | `gui/`, `cli/` |
102
+ | `qa` | `tests/` | todo o código de produção |
103
+ | `security` | `docs/security/` (criar se necessário) | todo o codebase |
104
+ | `reviewer` | — | todo o codebase |
105
+
106
+ > Note: neste projeto `dba` cobre **camada de dados/domínio + adapter MNE-NIRS**, não banco relacional. Ele detém o contrato `Pipeline`/`Block`/`DataType` (ADR-005) e o adapter `engine/mne_adapter.py`. Qualquer mudança em estrutura de domínio passa por contrato dele antes do dev tocar na GUI.
107
+
108
+ ---
109
+
110
+ ## Convenções
111
+
112
+ ### Commits
113
+
114
+ ```
115
+ tipo(escopo): mensagem imperativa curta
116
+
117
+ Agente: <Nome> (<role>)
118
+ Task: T-xxx
119
+ ```
120
+
121
+ Tipos válidos: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `perf`, `style`
122
+
123
+ Escopos sugeridos: `domain`, `engine`, `blocks`, `gui`, `io`, `cli`, `ci`, `docs`.
124
+
125
+ ### Estilo Python
126
+ - `ruff` configurado em `pyproject.toml` (E, F, I, B, UP, SIM)
127
+ - `mypy --strict` no pacote `nirspy`
128
+ - Linha máx 100 caracteres
129
+ - Type hints obrigatórios em código novo (camada `domain` em particular)
130
+
131
+ ### Regra de ouro arquitetural (ADR-005)
132
+ - `domain/` **não importa** Dash, Plotly, MNE, MNE-NIRS — apenas stdlib + tipagem
133
+ - `engine/` importa `domain` + MNE/MNE-NIRS — nunca Dash
134
+ - `gui/` pode importar tudo do projeto
135
+ - Antes de criar arquivo novo, identificar a camada e respeitar a direção dos imports
136
+
137
+ ### Pipelines como contrato
138
+ - Pipelines salvas em YAML são **API pública** do projeto
139
+ - Mudança breaking no schema de pipeline requer ADR e bump de minor (v0.x → v0.x+1)
140
+ - Round-trip YAML → Pipeline → YAML deve ser idêntico (golden tests em `tests/io/`)
141
+
142
+ ### Open source
143
+ Toda decisão técnica deve considerar:
144
+ - Reprodutibilidade (mesma pipeline + mesmo SNIRF = mesmo resultado em qualquer máquina)
145
+ - Compatibilidade com Best Practices fNIRS (Yücel et al., 2021)
146
+ - Acessibilidade para usuários que não programam
147
+ - Manutenibilidade por dev solo
148
+
149
+ ### Dependências
150
+ - Não adicionar dependência sem justificativa em PR
151
+ - Preferir biblioteca já presente no ecossistema MNE/scipy
152
+ - Nunca acoplar a algo GPL — projeto é BSD-3
153
+
154
+ ---
155
+
156
+ ## Stack-específico
157
+
158
+ ### Estrutura de pastas (src layout)
159
+ ```
160
+ src/nirspy/
161
+ ├── domain/ # camada 1 — pura
162
+ ├── engine/ # camada 2 — adapter MNE-NIRS
163
+ ├── blocks/ # blocos concretos (load, OD, mBLL, motion, QC, analysis, export)
164
+ ├── io/ # serializadores YAML/JSON de pipelines
165
+ ├── gui/ # Dash app (components/, pages/, callbacks/)
166
+ └── cli/ # entry point `nirspy`
167
+ ```
168
+
169
+ ### Testes
170
+ - `tests/domain/` — unit puro, <100ms
171
+ - `tests/engine/` — integração com fixtures MNE
172
+ - `tests/blocks/` — integração por bloco
173
+ - `tests/io/` — round-trip golden files
174
+ - `tests/gui/` — smoke tests via `pytest-dash`
175
+
176
+ Dataset de referência: MNE-NIRS sample dataset (BSD-3, redistribuível).
177
+
178
+ ### CI
179
+ GitHub Actions em `.github/workflows/ci.yml` — matrix Python 3.10/3.11/3.12, ruff + mypy + pytest.
@@ -0,0 +1,16 @@
1
+ # Code of Conduct
2
+
3
+ This project adopts the **[Contributor Covenant 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/)**
4
+ as its code of conduct.
5
+
6
+ Full text: https://www.contributor-covenant.org/version/2/1/code_of_conduct/
7
+
8
+ Official translations: https://www.contributor-covenant.org/translations/
9
+
10
+ ## Enforcement
11
+
12
+ Conduct that violates the code may be reported to the maintainer:
13
+
14
+ - Email: bruno.furlanetto@hotmail.com
15
+
16
+ Reports are handled confidentially. Expected response within 7 days.
@@ -0,0 +1,114 @@
1
+ # Contributing to NIRSPY
2
+
3
+ Thanks for your interest in contributing. This document describes the minimal
4
+ flow for running the project, opening issues, and submitting pull requests.
5
+
6
+ ## Local setup
7
+
8
+ Prerequisites: Python 3.10+. [`uv`](https://docs.astral.sh/uv/) is supported
9
+ but not required.
10
+
11
+ ```bash
12
+ git clone https://github.com/BrunoFurlanetto/nirspy.git
13
+ cd nirspy
14
+ python -m venv .venv
15
+ # Linux/macOS
16
+ source .venv/bin/activate
17
+ # Windows PowerShell
18
+ .venv\Scripts\Activate.ps1
19
+
20
+ pip install -e ".[dev]"
21
+ ```
22
+
23
+ ### Run tests, lint, types
24
+
25
+ ```bash
26
+ pytest
27
+ ruff check .
28
+ mypy src/nirspy
29
+ ```
30
+
31
+ ### Run the app
32
+
33
+ ```bash
34
+ nirspy serve
35
+ # open http://127.0.0.1:8050
36
+ ```
37
+
38
+ ## Issues
39
+
40
+ Before opening an issue:
41
+
42
+ 1. Check that a similar issue is not already open or closed.
43
+ 2. For bugs: describe reproduction steps, expected vs observed behaviour,
44
+ Python version, and `nirspy` version.
45
+ 3. For features: review the [roadmap](docs/roadmap.md) — it may already be
46
+ planned. Otherwise describe the problem before the solution.
47
+
48
+ Use the [issue templates](.github/ISSUE_TEMPLATE/) — blank issues are
49
+ disabled.
50
+
51
+ ## Branches
52
+
53
+ Always branched off `main`:
54
+
55
+ ```
56
+ feature/T-xxx-short-name
57
+ fix/T-xxx-description
58
+ chore/T-xxx-description
59
+ docs/T-xxx-description
60
+ ```
61
+
62
+ `main` is protected — no direct commits. All changes go through a PR.
63
+
64
+ ## Commits
65
+
66
+ Short Conventional Commits style:
67
+
68
+ ```
69
+ type(scope): short imperative subject
70
+
71
+ Optional body explaining the why.
72
+ ```
73
+
74
+ Types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `perf`, `style`.
75
+ Suggested scopes: `domain`, `engine`, `blocks`, `gui`, `io`, `cli`, `ci`, `docs`.
76
+
77
+ ## Pull requests
78
+
79
+ 1. Branch from `main`.
80
+ 2. Lint, types and tests pass locally.
81
+ 3. Open a PR against `main` with a clear description: what changes, why, and
82
+ how to test.
83
+ 4. CI must pass (ruff + mypy + pytest matrix on Python 3.10/3.11/3.12).
84
+ 5. Wait for review. Squash-merge is the default.
85
+
86
+ ## Architecture
87
+
88
+ Before creating new files, read [`docs/architecture.md`](docs/architecture.md).
89
+ The golden rule:
90
+
91
+ - `domain/` must not import Dash, Plotly, or MNE.
92
+ - `engine/` may import `domain` + MNE/MNE-NIRS, but not Dash.
93
+ - `gui/` may import everything from the project.
94
+
95
+ PRs that violate this rule will be rejected.
96
+
97
+ ## Tests
98
+
99
+ - `tests/domain/` — pure unit tests, <100 ms.
100
+ - `tests/engine/` and `tests/blocks/` — integration with fixtures.
101
+ - `tests/io/` — round-trip golden files.
102
+ - `tests/gui/` — smoke tests via Dash test client.
103
+
104
+ Minimum coverage target for `domain/`: 80%.
105
+
106
+ ## Code of conduct
107
+
108
+ By participating in this project you agree to follow the
109
+ [Code of Conduct](CODE_OF_CONDUCT.md).
110
+
111
+ ## License
112
+
113
+ Contributions are accepted under the project's
114
+ [BSD-3-Clause license](LICENSE).