myastro 0.3.0__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 (117) hide show
  1. myastro-0.3.0/.gitignore +27 -0
  2. myastro-0.3.0/CHANGELOG.md +80 -0
  3. myastro-0.3.0/LICENSE +21 -0
  4. myastro-0.3.0/PKG-INFO +211 -0
  5. myastro-0.3.0/README.md +154 -0
  6. myastro-0.3.0/constraints.txt +20 -0
  7. myastro-0.3.0/docs/capabilities.md +118 -0
  8. myastro-0.3.0/docs/design-io.md +215 -0
  9. myastro-0.3.0/docs/design-top.md +232 -0
  10. myastro-0.3.0/docs/dev-plan.md +92 -0
  11. myastro-0.3.0/docs/en/install.md +82 -0
  12. myastro-0.3.0/docs/en/quickstart.md +85 -0
  13. myastro-0.3.0/docs/processing.md +309 -0
  14. myastro-0.3.0/docs/release.md +166 -0
  15. myastro-0.3.0/docs/roadmap-e.md +141 -0
  16. myastro-0.3.0/docs/test-map.md +1396 -0
  17. myastro-0.3.0/docs/testing.md +146 -0
  18. myastro-0.3.0/docs/zh/install.md +80 -0
  19. myastro-0.3.0/docs/zh/quickstart.md +82 -0
  20. myastro-0.3.0/githooks/pre-push +69 -0
  21. myastro-0.3.0/manifests/legacy-test.yaml +4 -0
  22. myastro-0.3.0/manifests/unwise-test.yaml +5 -0
  23. myastro-0.3.0/pyproject.toml +97 -0
  24. myastro-0.3.0/src/myastro/__init__.py +102 -0
  25. myastro-0.3.0/src/myastro/__main__.py +6 -0
  26. myastro-0.3.0/src/myastro/cli.py +404 -0
  27. myastro-0.3.0/src/myastro/descriptors.py +245 -0
  28. myastro-0.3.0/src/myastro/errors.py +30 -0
  29. myastro-0.3.0/src/myastro/facade.py +265 -0
  30. myastro-0.3.0/src/myastro/imaging/__init__.py +0 -0
  31. myastro-0.3.0/src/myastro/io/__init__.py +1 -0
  32. myastro-0.3.0/src/myastro/io/aria2.py +84 -0
  33. myastro-0.3.0/src/myastro/io/backup.py +164 -0
  34. myastro-0.3.0/src/myastro/io/config.py +34 -0
  35. myastro-0.3.0/src/myastro/io/coords.py +133 -0
  36. myastro-0.3.0/src/myastro/io/core.py +132 -0
  37. myastro-0.3.0/src/myastro/io/db.py +126 -0
  38. myastro-0.3.0/src/myastro/io/docsync.py +58 -0
  39. myastro-0.3.0/src/myastro/io/doctor.py +280 -0
  40. myastro-0.3.0/src/myastro/io/health.py +95 -0
  41. myastro-0.3.0/src/myastro/io/index.py +191 -0
  42. myastro-0.3.0/src/myastro/io/integrity.py +83 -0
  43. myastro-0.3.0/src/myastro/io/jobs/__init__.py +71 -0
  44. myastro-0.3.0/src/myastro/io/jobs/aria2_exec.py +114 -0
  45. myastro-0.3.0/src/myastro/io/jobs/lifecycle.py +171 -0
  46. myastro-0.3.0/src/myastro/io/jobs/query.py +82 -0
  47. myastro-0.3.0/src/myastro/io/jobs/rebuild.py +50 -0
  48. myastro-0.3.0/src/myastro/io/jobs/runner.py +160 -0
  49. myastro-0.3.0/src/myastro/io/jobs/spec.py +89 -0
  50. myastro-0.3.0/src/myastro/io/jobs/store.py +95 -0
  51. myastro-0.3.0/src/myastro/io/manifest.py +47 -0
  52. myastro-0.3.0/src/myastro/io/schedule.py +101 -0
  53. myastro-0.3.0/src/myastro/io/search.py +139 -0
  54. myastro-0.3.0/src/myastro/io/sources/__init__.py +128 -0
  55. myastro-0.3.0/src/myastro/io/sources/asassn.py +64 -0
  56. myastro-0.3.0/src/myastro/io/sources/exoplanet.py +59 -0
  57. myastro-0.3.0/src/myastro/io/sources/gaia.py +46 -0
  58. myastro-0.3.0/src/myastro/io/sources/mpc.py +38 -0
  59. myastro-0.3.0/src/myastro/io/sources/simbad.py +44 -0
  60. myastro-0.3.0/src/myastro/io/sources/tess.py +76 -0
  61. myastro-0.3.0/src/myastro/io/sources/unwise.py +97 -0
  62. myastro-0.3.0/src/myastro/io/sources/vizier.py +49 -0
  63. myastro-0.3.0/src/myastro/io/sources/ztf.py +120 -0
  64. myastro-0.3.0/src/myastro/io/sources/ztf_lc.py +57 -0
  65. myastro-0.3.0/src/myastro/io/testmap.py +189 -0
  66. myastro-0.3.0/src/myastro/io/top/__init__.py +13 -0
  67. myastro-0.3.0/src/myastro/io/top/app.py +412 -0
  68. myastro-0.3.0/src/myastro/io/top/batchscreen.py +146 -0
  69. myastro-0.3.0/src/myastro/io/top/panes.py +388 -0
  70. myastro-0.3.0/src/myastro/io/top/screens.py +270 -0
  71. myastro-0.3.0/src/myastro/io/top/suggest.py +46 -0
  72. myastro-0.3.0/src/myastro/io/types.py +45 -0
  73. myastro-0.3.0/src/myastro/io/urls.py +47 -0
  74. myastro-0.3.0/src/myastro/lc/__init__.py +250 -0
  75. myastro-0.3.0/src/myastro/phot/__init__.py +0 -0
  76. myastro-0.3.0/src/myastro/tasks.py +64 -0
  77. myastro-0.3.0/tests/cli/test_cli.py +318 -0
  78. myastro-0.3.0/tests/conftest.py +89 -0
  79. myastro-0.3.0/tests/facade/test_facade.py +242 -0
  80. myastro-0.3.0/tests/guards/test_boundaries.py +21 -0
  81. myastro-0.3.0/tests/guards/test_capability_map.py +100 -0
  82. myastro-0.3.0/tests/guards/test_descriptor_contract.py +144 -0
  83. myastro-0.3.0/tests/guards/test_doc_sync.py +17 -0
  84. myastro-0.3.0/tests/guards/test_docs_paths.py +101 -0
  85. myastro-0.3.0/tests/guards/test_registry.py +40 -0
  86. myastro-0.3.0/tests/kernel/test_backup.py +189 -0
  87. myastro-0.3.0/tests/kernel/test_batch.py +92 -0
  88. myastro-0.3.0/tests/kernel/test_coords.py +113 -0
  89. myastro-0.3.0/tests/kernel/test_db.py +202 -0
  90. myastro-0.3.0/tests/kernel/test_doctor.py +88 -0
  91. myastro-0.3.0/tests/kernel/test_health.py +102 -0
  92. myastro-0.3.0/tests/kernel/test_index.py +168 -0
  93. myastro-0.3.0/tests/kernel/test_integrity.py +51 -0
  94. myastro-0.3.0/tests/kernel/test_jobs.py +622 -0
  95. myastro-0.3.0/tests/kernel/test_path_containment.py +66 -0
  96. myastro-0.3.0/tests/kernel/test_schedule.py +44 -0
  97. myastro-0.3.0/tests/kernel/test_search.py +189 -0
  98. myastro-0.3.0/tests/sources/test_asassn.py +33 -0
  99. myastro-0.3.0/tests/sources/test_exoplanet.py +108 -0
  100. myastro-0.3.0/tests/sources/test_gaia.py +64 -0
  101. myastro-0.3.0/tests/sources/test_manifest.py +35 -0
  102. myastro-0.3.0/tests/sources/test_mpc.py +23 -0
  103. myastro-0.3.0/tests/sources/test_simbad.py +19 -0
  104. myastro-0.3.0/tests/sources/test_tess.py +68 -0
  105. myastro-0.3.0/tests/sources/test_unwise.py +123 -0
  106. myastro-0.3.0/tests/sources/test_vizier.py +22 -0
  107. myastro-0.3.0/tests/sources/test_ztf.py +77 -0
  108. myastro-0.3.0/tests/ui/test_form_labels.py +150 -0
  109. myastro-0.3.0/tests/ui/test_index_hints.py +164 -0
  110. myastro-0.3.0/tests/ui/test_refresh.py +273 -0
  111. myastro-0.3.0/tests/ui/test_suggest.py +111 -0
  112. myastro-0.3.0/tests/ui/test_top.py +584 -0
  113. myastro-0.3.0/tests/unit/test_core.py +117 -0
  114. myastro-0.3.0/tests/unit/test_format.py +18 -0
  115. myastro-0.3.0/tests/unit/test_lc.py +202 -0
  116. myastro-0.3.0/tests/unit/test_path_safety.py +86 -0
  117. myastro-0.3.0/tests/unit/test_prefill.py +68 -0
@@ -0,0 +1,27 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .ipynb_checkpoints/
5
+ # 数据不进 git
6
+ data/
7
+ *.fits
8
+ *.fit
9
+ *.fz
10
+ *.csv
11
+ out/
12
+ *.png
13
+ !docs/**/*.png
14
+ .env
15
+ lightkurve-cache/
16
+
17
+ # 构建产物:可再生产物不进 git(发布时由 CI/本地构建生成)
18
+ dist/
19
+ build/
20
+ *.egg-info/
21
+ .pytest_cache/
22
+
23
+ # 本机环境路径(每台机器不同,不进版本控制)
24
+ .myastro-env
25
+
26
+ # 编辑器配置(个人设置不进版本库)
27
+ .vscode/
@@ -0,0 +1,80 @@
1
+ # Changelog
2
+
3
+ 本文件记录对使用者有影响的变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
+ 版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
5
+
6
+ ## [0.3.0] - 2026-10-10
7
+
8
+ **首个公开发布**(0.2.0 为私有基线,未发布)。PyPI 上的起点。
9
+
10
+ ### 新增
11
+
12
+ - **双语用户文档**:英文 `README.md` + 中文 `README.zh-CN.md`;`docs/en/` 与 `docs/zh/`
13
+ 下的安装与快速上手成对存在,并有守卫检查中英章节结构一致(防止只更新一边)。
14
+ - **CI(GitHub Actions)**:lint(ruff + pyflakes)、test(ubuntu + macos × Python
15
+ 3.11/3.12/3.13,全量离线测试)、build(构建 + `twine check` + 安装 wheel + `doctor` 冒烟);
16
+ 标签发布走 **PyPI Trusted Publishing(OIDC,无长期 token)**,另有 TestPyPI 演练工作流。
17
+ - **社区文件**:`CONTRIBUTING.md`(含分层测试规则与"回归测试必须能变红")、`SECURITY.md`
18
+ (凭据处理与漏洞报告)、`CITATION.cff`、issue/PR 模板。
19
+ - `[test]` extra(pytest/pytest-asyncio/ruff/pyflakes),CI 用它而不必装 jupyterlab。
20
+
21
+ ### 变更
22
+
23
+ - **默认数据根**改为 `~/myastro-data`(此前是本机个人布局)。`doctor` 在未显式设置
24
+ `MYASTRO_DATA` 时给出提示与 export 写法。数据可以放 NAS,账本必须在本地磁盘。
25
+ - `githooks/pre-push` 不再硬编码本机环境路径:候选链 `MYASTRO_ENV_BIN` → 仓库内
26
+ `.myastro-env`(gitignore)→ 当前 venv → `.venv` → PATH,每个候选先用
27
+ `pytest --collect-only` 预检;找不到时给出三种修复方式。
28
+ - notebook 输出已清空(体积 2.2MB → 28KB),公开仓库不含执行结果。
29
+
30
+ ### 修复
31
+
32
+ - 发布产物内容明确化:sdist 1.9MB → 179KB(排除 notebooks / `.vscode` / conda 环境记录)。
33
+ - 开发向命令(`test-map` / `doc-sync`)在已安装环境里不再抛栈或写入 site-packages,
34
+ 改为清晰报错 + 退出码 2。
35
+
36
+ ## [0.2.0] - 2026-10-10
37
+
38
+ 首个打标签的基线(此前为私有开发,未发布)。0.x 阶段允许破坏性变更,但都会写在本文件里。
39
+
40
+ ### 新增
41
+
42
+ - **数据获取**:10 个描述符源(tess / gaia / ztf / ztf-meta / ztf-lc / mpc / simbad /
43
+ vizier / legacy / unwise),另有 manifest 清单批量下载、exoplanet 目录查询;
44
+ asassn 为休眠源(后端失联)。
45
+ - **账本与去重**:SQLite 账本(数据存 UTC,显示转本地时区),缓存键规范化
46
+ (同参数二次调用零网络),`meta_json` 溯源持久化。
47
+ - **本地检索**:按源/目标/文件名/时间检索;**精确圆锥坐标检索**
48
+ (入库时解析坐标 → SQL 包围盒粗筛 → haversine 精判 → 按角距排序带 `sep_deg`)。
49
+ - **批量与调度**:批次下单与整批重试;launchd 定时任务(健康检查、索引更新)。
50
+ - **索引**:legacy-bricks(366k 行)、ztf-fields(1776 场)本地索引,
51
+ 前缀查询走缓存 + bisect(实测每次按键 0.5ms)。
52
+ - **TUI**(`myastro top`):三面板(数据源/作业/存储)、F1 新建、F2 预填充、F12 批量;
53
+ 索引字段带原生补全(→ 接受)与输入前可见的 `(索引)` 标记。
54
+ - **CLI**:20 个子命令;`fetch` 参数由描述符自动生成;`--version`;`init`(建数据根/账本)、`doctor`(环境自检)、`backup`/`restore`(账本备份与恢复)。
55
+ - **环境自检**:`ma.doctor()` 检查依赖、路径可写性、账本 schema、**账本文件系统(NFS 上 SQLite WAL 不可用)**、文件抽查、索引、平台能力;有 FAIL 时退出码 1。
56
+ - **账本备份/恢复**:`ma.backup()` / `ma.restore()`,SQLite 在线备份 API,恢复默认拒绝覆盖、覆盖前自动留 `.pre-restore-*.bak`、支持旧 schema 备份再迁移。
57
+ - **可验证的工程**:能力矩阵(capabilities)+ 生成的测试地图;设计守卫(注册表漂移、
58
+ 文档同步、层边界、门面覆盖、落盘路径不变量)。
59
+
60
+ ### 修复
61
+
62
+ - **路径安全**:名字型参数(`brick`/`ffd`/`target`)此前可经 `..` 把产物写到数据根之外;
63
+ 现在输入即拒(`FieldSpec.pattern`/`name_like`)+ 落库前运行时兜底。
64
+ - **检索参数**:越界输入(负半径、dec 越界、`limit<1`、日期格式错)此前静默返回空结果,
65
+ 其中 `limit=-1` 会按切片语义返回"除最后一条外的全部";现在一律 `ParamError`。
66
+ - **TUI 闪烁**:选中项在视口外时,每 2 秒刷新会先画一帧"列表顶部"再滚回(帧级实测 2 帧/次);
67
+ 现在内容签名短路(无变化不重绘)+ 重建后同步恢复滚动(1 帧)。
68
+ - **TUI 首屏列宽**:本地资产首屏"文件名"列被截断(自动列宽在"只有列还没有行"时定宽),
69
+ 排序后才正常;现在列宽按内容确定性计算。
70
+ - **CLI 错误处理**:`myastro retry 999999` 此前直接抛栈崩溃;现在错误消息 + 退出码
71
+ 契约(0/1/2/3/4/5/130)。
72
+ - **连接生命周期**:自建 SQLite 连接此前靠 GC 回收;现在用完即关,传入的连接不受影响。
73
+
74
+ ### 变更
75
+
76
+ - 依赖声明与实际使用对齐:补 `numpy`/`pyarrow`;重依赖移入 `[processing]` extras;
77
+ `pyasassn`/`ztfquery` 为可选后端。
78
+ - 采用 MIT 许可。
79
+
80
+ [0.2.0]: https://github.com/DanJiabi/myastro/releases/tag/v0.2.0
myastro-0.3.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DanJiabi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
myastro-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.5
2
+ Name: myastro
3
+ Version: 0.3.0
4
+ Summary: Personal astronomy data toolkit: fetch, ledger, dedup, coverage, TUI
5
+ Project-URL: Homepage, https://github.com/DanJiabi/myastro
6
+ Project-URL: Repository, https://github.com/DanJiabi/myastro
7
+ Project-URL: Issues, https://github.com/DanJiabi/myastro/issues
8
+ Project-URL: Changelog, https://github.com/DanJiabi/myastro/blob/main/CHANGELOG.md
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: astronomy,astroquery,data-management,legacy-survey,tess,tui,ztf
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: astropy
24
+ Requires-Dist: astroquery
25
+ Requires-Dist: lightkurve
26
+ Requires-Dist: numpy
27
+ Requires-Dist: pandas
28
+ Requires-Dist: pyarrow
29
+ Requires-Dist: pyyaml
30
+ Requires-Dist: requests
31
+ Requires-Dist: textual
32
+ Requires-Dist: transitleastsquares
33
+ Provides-Extra: asassn
34
+ Requires-Dist: pyasassn; extra == 'asassn'
35
+ Provides-Extra: dev
36
+ Requires-Dist: jupyterlab; extra == 'dev'
37
+ Requires-Dist: pyflakes; extra == 'dev'
38
+ Requires-Dist: pytest; extra == 'dev'
39
+ Requires-Dist: pytest-asyncio; extra == 'dev'
40
+ Requires-Dist: ruff; extra == 'dev'
41
+ Provides-Extra: processing
42
+ Requires-Dist: astroalign; extra == 'processing'
43
+ Requires-Dist: ccdproc; extra == 'processing'
44
+ Requires-Dist: matplotlib; extra == 'processing'
45
+ Requires-Dist: photutils; extra == 'processing'
46
+ Requires-Dist: scipy; extra == 'processing'
47
+ Requires-Dist: skyfield; extra == 'processing'
48
+ Provides-Extra: test
49
+ Requires-Dist: pyflakes; extra == 'test'
50
+ Requires-Dist: pytest; extra == 'test'
51
+ Requires-Dist: pytest-asyncio; extra == 'test'
52
+ Requires-Dist: ruff; extra == 'test'
53
+ Requires-Dist: ztfquery; extra == 'test'
54
+ Provides-Extra: ztfquery
55
+ Requires-Dist: ztfquery; extra == 'ztfquery'
56
+ Description-Content-Type: text/markdown
57
+
58
+ # myastro
59
+
60
+ [![CI](https://github.com/DanJiabi/myastro/actions/workflows/ci.yml/badge.svg)](https://github.com/DanJiabi/myastro/actions/workflows/ci.yml)
61
+ [![PyPI](https://img.shields.io/pypi/v/myastro.svg)](https://pypi.org/project/myastro/)
62
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
63
+
64
+ **A personal astronomy data toolkit with a memory.** Fetch from public surveys and
65
+ keep a local ledger of *what you already have* — so you stop re-downloading the same sky.
66
+
67
+ `myastro` answers questions plain query tools don't:
68
+
69
+ - "Have I already downloaded this patch of sky?" → precise cone search over your ledger
70
+ - "How much of the brick/field index is local?" → coverage against a full catalogue
71
+ - "Which files rotted on disk?" → sha256 baseline audit
72
+ - "Is it still fetchable?" → deduplicated fetches plus source probes
73
+
74
+ Three entry points, one contract:
75
+
76
+ | Entry point | Use |
77
+ |---|---|
78
+ | Library | `import myastro as ma` — the only public import (`ma.__all__`) |
79
+ | CLI | `myastro fetch / search / coverage / audit / doctor / backup …` |
80
+ | TUI | `myastro top` — jobs / storage / sources, no config file needed |
81
+
82
+ > Status: **0.3.0 — alpha**. The facade is the public API; `myastro.io.*` is internal
83
+ > and may change. Breaking changes are listed in [CHANGELOG.md](CHANGELOG.md).
84
+
85
+ ## Install
86
+
87
+ ```bash
88
+ pip install myastro # from PyPI
89
+ pip install -c constraints.txt myastro # with known-good dependency versions
90
+ pip install "myastro[processing]" # + photometry/imaging deps (planned P2/P3)
91
+ myastro doctor # self-check: deps, paths, ledger, filesystem
92
+ ```
93
+
94
+ Python ≥ 3.11. macOS and Linux are supported; Windows is untested (scheduling is
95
+ macOS/Linux only). Optional extras: `[processing]`, `[asassn]`, `[ztfquery]`.
96
+
97
+ ## Quick start
98
+
99
+ ```python
100
+ import myastro as ma
101
+
102
+ # 1) fetch — deduplicated: the same params never hit the network twice
103
+ r = ma.fetch("tess", target="WASP-12", sector=20)
104
+ print(r.paths[0])
105
+
106
+ # 2) what do I already have near this position?
107
+ for hit in ma.search(near=(97.6367, 29.6723), radius_deg=0.5):
108
+ print(f"{hit['source']:10s} sep={hit['sep_deg']:.4f}° {hit['path']}")
109
+
110
+ # 3) coverage against a full catalogue index
111
+ print(ma.coverage("legacy-bricks")) # {'local': 7, 'total': 366912, ...}
112
+
113
+ # 4) integrity: build a sha256 baseline, then detect silent corruption
114
+ print(ma.audit())
115
+ ```
116
+
117
+ Data root defaults to `~/myastro-data`; the ledger defaults to
118
+ `~/.local/state/myastro/astro.db`. Both are overridable:
119
+
120
+ ```bash
121
+ export MYASTRO_DATA=/path/to/your/data # may live on a NAS
122
+ export MYASTRO_DB=~/.local/state/myastro/astro.db # must be a LOCAL disk (SQLite WAL)
123
+ ```
124
+
125
+ Keeping the ledger local while data lives on a NAS is the intended layout —
126
+ `myastro doctor` fails when the ledger sits on NFS/CIFS.
127
+
128
+ ## CLI
129
+
130
+ ```bash
131
+ myastro init # create data root + ledger (idempotent)
132
+ myastro doctor # environment self-check (exit 1 if broken)
133
+ myastro backup --out ~/myastro-backup # online SQLite backup + manifest
134
+ myastro restore ~/myastro-backup/<stamp> --force # refuses to overwrite unless --force
135
+ myastro fetch tess --target "WASP-12" --sector 20 # args generated from descriptors
136
+ myastro jobs / wait / retry / delete / retry-batch
137
+ myastro search --near 196.18 33.35 --radius 0.2
138
+ myastro coverage legacy-bricks
139
+ myastro audit # sha256 baseline / corruption report
140
+ myastro index list | index update <name> # local indexes (Legacy bricks, ZTF fields)
141
+ myastro health | schedule install health # source probes, launchd (macOS)
142
+ myastro top # TUI
143
+ ```
144
+
145
+ Exit codes are a contract, so scripts can branch:
146
+ `0` ok · `1` partial failure / doctor found problems · `2` bad parameter ·
147
+ `3` not found · `4` network · `5` state not allowed · `130` interrupted.
148
+
149
+ ## What's inside
150
+
151
+ - **Ledger** — every fetch is a job; datasets, files, parameters, provenance and
152
+ coordinates are recorded. Data files are the truth, the ledger is the index.
153
+ - **Deduplication** — cache key is a normalized `(source, params)` hash: the same
154
+ request never hits the network twice; cache hits return the original metadata.
155
+ - **10 sources** — TESS light curves, Gaia DR3 cones, ZTF frames / metadata / light
156
+ curves, MPC ephemerides, SIMBAD, VizieR, Legacy Surveys tractor bricks, unWISE
157
+ cutouts, plus YAML manifests for bulk URL lists.
158
+ - **Precise cone search** — coordinates are resolved at ingest time (params → meta →
159
+ index lookup → filename fallback), stored in the ledger, then queried with a
160
+ bounding box plus haversine refinement and sorted by separation.
161
+ - **Local indexes** — 366k Legacy bricks and 1776 ZTF fields, cached in memory and
162
+ searched with binary search (sub-millisecond per keystroke in the TUI).
163
+ - **Verifiability** — a capability matrix (`docs/capabilities.md`), a generated test
164
+ map (`docs/test-map.md`) and design guards: tests fail when docs or registries drift.
165
+
166
+ ## Documentation
167
+
168
+ | Document | Language | Audience |
169
+ |---|---|---|
170
+ | [Install](docs/en/install.md) · [Quick start](docs/en/quickstart.md) | EN | users |
171
+ | [安装](docs/zh/install.md) · [快速上手](docs/zh/quickstart.md) | 中文 | 用户 |
172
+ | [capabilities.md](docs/capabilities.md) | 中文 | roadmap: what exists, at which maturity |
173
+ | [processing.md](docs/processing.md) | 中文 | pipeline behaviour and failure semantics |
174
+ | [design-io.md](docs/design-io.md) · [design-top.md](docs/design-top.md) | 中文 | layer design and decisions |
175
+ | [testing.md](docs/testing.md) · [test-map.md](docs/test-map.md) | 中文 | test layers, guards, generated map |
176
+ | [release.md](docs/release.md) | 中文 | release process and public-mirror model |
177
+
178
+ Developer docs are maintained in Chinese; user-facing docs are bilingual.
179
+
180
+ ## Development
181
+
182
+ ```bash
183
+ git clone https://github.com/DanJiabi/myastro && cd myastro
184
+ pip install -e ".[dev]" # or: pip install -e . pytest ruff pyflakes ztfquery
185
+ git config core.hooksPath githooks # versioned pre-push gate (full suite + pyflakes)
186
+ pytest -q # 372 tests, offline (network is stubbed)
187
+ pytest -m "unit or guards" -q # fast lane (~3 s)
188
+ myastro test-map && myastro doc-sync # regenerate docs (guards fail when stale)
189
+ ```
190
+
191
+ > `requirements-lock.txt` is the maintainer's conda environment record (it contains
192
+ > conda `file://` sources, so it is not a pip lock file). For reproducible pip installs
193
+ > use `constraints.txt`.
194
+
195
+ The pre-push hook resolves a usable interpreter itself (`MYASTRO_ENV_BIN` →
196
+ `.myastro-env` → active venv → `.venv` → PATH, each pre-flighted with
197
+ `pytest --collect-only`) and never pipes command output, so a red suite cannot slip through.
198
+
199
+ ## Data, privacy, credentials
200
+
201
+ - Everything stays on your machine: no telemetry, no account, no upload.
202
+ - Downloads use public survey endpoints (MAST, IRSA, VizieR, SIMBAD, NERSC, unwise.me).
203
+ ZTF metadata via IRSA may benefit from a free account configured in your own tooling —
204
+ **myastro never stores credentials**.
205
+ - Survey data belongs to the surveys; this tool only fetches it. Cite the surveys you use.
206
+
207
+ ## License
208
+
209
+ MIT — see [LICENSE](LICENSE).
210
+
211
+ <sub>中文说明见 [README.zh-CN.md](README.zh-CN.md)。</sub>
@@ -0,0 +1,154 @@
1
+ # myastro
2
+
3
+ [![CI](https://github.com/DanJiabi/myastro/actions/workflows/ci.yml/badge.svg)](https://github.com/DanJiabi/myastro/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/myastro.svg)](https://pypi.org/project/myastro/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+
7
+ **A personal astronomy data toolkit with a memory.** Fetch from public surveys and
8
+ keep a local ledger of *what you already have* — so you stop re-downloading the same sky.
9
+
10
+ `myastro` answers questions plain query tools don't:
11
+
12
+ - "Have I already downloaded this patch of sky?" → precise cone search over your ledger
13
+ - "How much of the brick/field index is local?" → coverage against a full catalogue
14
+ - "Which files rotted on disk?" → sha256 baseline audit
15
+ - "Is it still fetchable?" → deduplicated fetches plus source probes
16
+
17
+ Three entry points, one contract:
18
+
19
+ | Entry point | Use |
20
+ |---|---|
21
+ | Library | `import myastro as ma` — the only public import (`ma.__all__`) |
22
+ | CLI | `myastro fetch / search / coverage / audit / doctor / backup …` |
23
+ | TUI | `myastro top` — jobs / storage / sources, no config file needed |
24
+
25
+ > Status: **0.3.0 — alpha**. The facade is the public API; `myastro.io.*` is internal
26
+ > and may change. Breaking changes are listed in [CHANGELOG.md](CHANGELOG.md).
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install myastro # from PyPI
32
+ pip install -c constraints.txt myastro # with known-good dependency versions
33
+ pip install "myastro[processing]" # + photometry/imaging deps (planned P2/P3)
34
+ myastro doctor # self-check: deps, paths, ledger, filesystem
35
+ ```
36
+
37
+ Python ≥ 3.11. macOS and Linux are supported; Windows is untested (scheduling is
38
+ macOS/Linux only). Optional extras: `[processing]`, `[asassn]`, `[ztfquery]`.
39
+
40
+ ## Quick start
41
+
42
+ ```python
43
+ import myastro as ma
44
+
45
+ # 1) fetch — deduplicated: the same params never hit the network twice
46
+ r = ma.fetch("tess", target="WASP-12", sector=20)
47
+ print(r.paths[0])
48
+
49
+ # 2) what do I already have near this position?
50
+ for hit in ma.search(near=(97.6367, 29.6723), radius_deg=0.5):
51
+ print(f"{hit['source']:10s} sep={hit['sep_deg']:.4f}° {hit['path']}")
52
+
53
+ # 3) coverage against a full catalogue index
54
+ print(ma.coverage("legacy-bricks")) # {'local': 7, 'total': 366912, ...}
55
+
56
+ # 4) integrity: build a sha256 baseline, then detect silent corruption
57
+ print(ma.audit())
58
+ ```
59
+
60
+ Data root defaults to `~/myastro-data`; the ledger defaults to
61
+ `~/.local/state/myastro/astro.db`. Both are overridable:
62
+
63
+ ```bash
64
+ export MYASTRO_DATA=/path/to/your/data # may live on a NAS
65
+ export MYASTRO_DB=~/.local/state/myastro/astro.db # must be a LOCAL disk (SQLite WAL)
66
+ ```
67
+
68
+ Keeping the ledger local while data lives on a NAS is the intended layout —
69
+ `myastro doctor` fails when the ledger sits on NFS/CIFS.
70
+
71
+ ## CLI
72
+
73
+ ```bash
74
+ myastro init # create data root + ledger (idempotent)
75
+ myastro doctor # environment self-check (exit 1 if broken)
76
+ myastro backup --out ~/myastro-backup # online SQLite backup + manifest
77
+ myastro restore ~/myastro-backup/<stamp> --force # refuses to overwrite unless --force
78
+ myastro fetch tess --target "WASP-12" --sector 20 # args generated from descriptors
79
+ myastro jobs / wait / retry / delete / retry-batch
80
+ myastro search --near 196.18 33.35 --radius 0.2
81
+ myastro coverage legacy-bricks
82
+ myastro audit # sha256 baseline / corruption report
83
+ myastro index list | index update <name> # local indexes (Legacy bricks, ZTF fields)
84
+ myastro health | schedule install health # source probes, launchd (macOS)
85
+ myastro top # TUI
86
+ ```
87
+
88
+ Exit codes are a contract, so scripts can branch:
89
+ `0` ok · `1` partial failure / doctor found problems · `2` bad parameter ·
90
+ `3` not found · `4` network · `5` state not allowed · `130` interrupted.
91
+
92
+ ## What's inside
93
+
94
+ - **Ledger** — every fetch is a job; datasets, files, parameters, provenance and
95
+ coordinates are recorded. Data files are the truth, the ledger is the index.
96
+ - **Deduplication** — cache key is a normalized `(source, params)` hash: the same
97
+ request never hits the network twice; cache hits return the original metadata.
98
+ - **10 sources** — TESS light curves, Gaia DR3 cones, ZTF frames / metadata / light
99
+ curves, MPC ephemerides, SIMBAD, VizieR, Legacy Surveys tractor bricks, unWISE
100
+ cutouts, plus YAML manifests for bulk URL lists.
101
+ - **Precise cone search** — coordinates are resolved at ingest time (params → meta →
102
+ index lookup → filename fallback), stored in the ledger, then queried with a
103
+ bounding box plus haversine refinement and sorted by separation.
104
+ - **Local indexes** — 366k Legacy bricks and 1776 ZTF fields, cached in memory and
105
+ searched with binary search (sub-millisecond per keystroke in the TUI).
106
+ - **Verifiability** — a capability matrix (`docs/capabilities.md`), a generated test
107
+ map (`docs/test-map.md`) and design guards: tests fail when docs or registries drift.
108
+
109
+ ## Documentation
110
+
111
+ | Document | Language | Audience |
112
+ |---|---|---|
113
+ | [Install](docs/en/install.md) · [Quick start](docs/en/quickstart.md) | EN | users |
114
+ | [安装](docs/zh/install.md) · [快速上手](docs/zh/quickstart.md) | 中文 | 用户 |
115
+ | [capabilities.md](docs/capabilities.md) | 中文 | roadmap: what exists, at which maturity |
116
+ | [processing.md](docs/processing.md) | 中文 | pipeline behaviour and failure semantics |
117
+ | [design-io.md](docs/design-io.md) · [design-top.md](docs/design-top.md) | 中文 | layer design and decisions |
118
+ | [testing.md](docs/testing.md) · [test-map.md](docs/test-map.md) | 中文 | test layers, guards, generated map |
119
+ | [release.md](docs/release.md) | 中文 | release process and public-mirror model |
120
+
121
+ Developer docs are maintained in Chinese; user-facing docs are bilingual.
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ git clone https://github.com/DanJiabi/myastro && cd myastro
127
+ pip install -e ".[dev]" # or: pip install -e . pytest ruff pyflakes ztfquery
128
+ git config core.hooksPath githooks # versioned pre-push gate (full suite + pyflakes)
129
+ pytest -q # 372 tests, offline (network is stubbed)
130
+ pytest -m "unit or guards" -q # fast lane (~3 s)
131
+ myastro test-map && myastro doc-sync # regenerate docs (guards fail when stale)
132
+ ```
133
+
134
+ > `requirements-lock.txt` is the maintainer's conda environment record (it contains
135
+ > conda `file://` sources, so it is not a pip lock file). For reproducible pip installs
136
+ > use `constraints.txt`.
137
+
138
+ The pre-push hook resolves a usable interpreter itself (`MYASTRO_ENV_BIN` →
139
+ `.myastro-env` → active venv → `.venv` → PATH, each pre-flighted with
140
+ `pytest --collect-only`) and never pipes command output, so a red suite cannot slip through.
141
+
142
+ ## Data, privacy, credentials
143
+
144
+ - Everything stays on your machine: no telemetry, no account, no upload.
145
+ - Downloads use public survey endpoints (MAST, IRSA, VizieR, SIMBAD, NERSC, unwise.me).
146
+ ZTF metadata via IRSA may benefit from a free account configured in your own tooling —
147
+ **myastro never stores credentials**.
148
+ - Survey data belongs to the surveys; this tool only fetches it. Cite the surveys you use.
149
+
150
+ ## License
151
+
152
+ MIT — see [LICENSE](LICENSE).
153
+
154
+ <sub>中文说明见 [README.zh-CN.md](README.zh-CN.md)。</sub>
@@ -0,0 +1,20 @@
1
+ # 已知可用的依赖版本(用于可复现安装)
2
+ #
3
+ # pip install -c constraints.txt myastro
4
+ #
5
+ # 这些是 0.2.0 开发与测试时使用过的版本,不强制锁定——没有特别需要时
6
+ # 直接 `pip install myastro` 即可。注意 transitleastsquares 需 >=2.0:
7
+ # 2.0 起自带凌星模型(不再需要 batman)且算法有变化,1.x 的 API 不同。
8
+ astropy==8.0.1
9
+ astroquery==0.4.11
10
+ lightkurve==2.6.0
11
+ transitleastsquares==2.0
12
+ numpy==2.5.3
13
+ pandas==2.3.3
14
+ pyarrow==25.0.0
15
+ PyYAML==6.0.3
16
+ requests==2.34.2
17
+ textual==8.2.8
18
+ rich==15.0.0
19
+ numba==0.68.0
20
+ scipy==1.18.1
@@ -0,0 +1,118 @@
1
+ # myastro 领域能力清单(master 规划文档) <!-- cap:design.guards -->
2
+
3
+ 版本:0.1|地位:**最高规划文档**。roadmap 从"做哪个功能"改为"把哪项能力
4
+ 推进到哪级";TUI/CLI/文档都是呈现层客户端,不再牵引架构。
5
+
6
+ ## 0. 工作模式与成熟度
7
+
8
+ ```
9
+ 能力 → 契约(门面 API + 契约测试)→ 内核实现 → 呈现(TUI/CLI/文档)
10
+ ```
11
+
12
+ | 级 | 含义 |
13
+ |---|---|
14
+ | L0 | 缺失 |
15
+ | L1 | 内核有实现,无契约 |
16
+ | L2 | 契约就绪(门面导出 + 测试 + 文档生成) |
17
+ | L3 | 至少一个呈现客户端暴露 |
18
+ | L4 | 自动化就绪(无人值守/定时/自愈) |
19
+
20
+ 验收单位是**能力**而非屏幕行为;呈现层 bug(如焦点/布局)不进入本清单。
21
+
22
+ 能力的**证据**在测试层:每个测试挂 `cap` 标记,`myastro test-map` 生成能力→测试映射,四条守卫保证不漂移(见 [testing.md](testing.md))。
23
+
24
+ ## 1. 数据源管理(source)
25
+
26
+ | 能力 | 级 | 现状 |
27
+ |---|---|---|
28
+ | 源注册表(schema 化描述符) | L3 | 10 源;SOURCES/URL_SOURCES/TASKS/INDEXES 四表互指有守卫 | <!-- cap:source.registry -->
29
+ | 源健康监测 | L3 | `ma.health()` 端点探测 + 落库 + info 面板新鲜覆盖;实测发现 unwise 已恢复 |。**探测深度=所填 URL**:只探域名根会漏报(unwise 根 200 而 `/cutout_fits` 因参数错返 500)——凡能给出合法最小请求的源都应填该请求 <!-- cap:source.health -->
30
+ | 源接入指南 | L1 | 隐含在代码模式里;缺"接一个新源要动哪几处"的 checklist | <!-- cap:source.contract -->
31
+ | 休眠源处置 | 决策已定 | asassn(后端失联)保留实现+测试防腐烂,恢复日做真实验证;弃用则代码/测试/注册表一并删 | <!-- cap:source.dormant -->
32
+ | 凭据管理 | L1 | IRSA 账号手动配 ~/.ztfquery;无统一凭据层 |
33
+
34
+ ## 2. 下载管理(acquire)
35
+
36
+ | 能力 | 级 | 现状 |
37
+ |---|---|---|
38
+ | 单件获取 fetch(缓存幂等) | L3 | 门面 + TUI + CLI | <!-- cap:acquire.fetch -->
39
+ | 计划型查询 query(不落盘) | L3 | | <!-- cap:acquire.query -->
40
+ | 批量 batch(批次生命周期) | L3 | 提交/查看/`ma.retry_batch`(失败半批一键重跑)/CLI retry-batch | <!-- cap:acquire.batch --> <!-- cap:acquire.manifest -->
41
+ | 重试/强制重下/删除 | L3 | 含跨进程重建、僵尸判定 | <!-- cap:acquire.retry --> <!-- cap:acquire.cancel -->
42
+ | 断点续传 | L2 | aria2 原生,依赖 daemon 存活 |
43
+ | 定时获取 schedule | L3 | launchd 代理(health 每日/index 每周),`myastro schedule list/install/remove`;调度不自建 | <!-- cap:acquire.schedule -->
44
+ | 带宽礼仪 | L1 | IRSA 夜间建议靠文档;无速率配置 |
45
+
46
+ ## 3. 数据管理(ledger,本地/云端共管)
47
+
48
+ | 能力 | 级 | 现状 |
49
+ |---|---|---|
50
+ | 溯源账本(params 可反查) | L3 | datasets/files/jobs 三表 | <!-- cap:manage.ledger -->
51
+ | 文件在盘核对 | L2 | exists 三态标记(storage/assets/jobs 产出列) |
52
+ | 完整性校验 | L3 | `ma.audit()` sha 基线+核对(首次建基线,此后测损坏)+ `audit_detail`;CLI `myastro audit`;实测 25 文件基线建立 | <!-- cap:manage.integrity -->
53
+ | 环境自检 `doctor` | L3 | 依赖/路径可写/账本/文件系统/索引/平台;退出码 1 表示有 FAIL | <!-- cap:manage.doctor -->
54
+ | 账本备份与恢复 | L3 | `ma.backup()` / `ma.restore()`;SQLite 在线备份、默认拒绝覆盖、覆盖前留 `.pre-restore-*.bak` | <!-- cap:manage.backup -->
55
+ | 索引浏览 + ✓/☁ 共管视图 | L3 | 批量屏;索引两枚:legacy-bricks(36 万,url 型)/ ztf-fields(1776,builder 型本地构造);批量资格=索引字段可单独标识获取 | <!-- cap:manage.index -->
56
+ | 按需云端下载 | L3 | 同屏勾选 ☁ → Ctrl+S |
57
+ | 覆盖率统计 | L3 | `ma.coverage(index)`;实测 legacy-bricks 7/366912 | <!-- cap:manage.coverage -->
58
+ | 本地检索(按坐标/时间/目标查已有) | L3 | `ma.search(target/near/since/name)` + CLI `--near/--radius`;**坐标精确化**:入库时解析(params/meta/编号→索引/文件名兜底)存 `datasets.ra/dec`,查询走 SQL 包围盒 + haversine 精判、按角距排序带 sep_deg | <!-- cap:manage.search -->
59
+ | 保留策略 retention | L0 | 无"旧 job 归档、冷数据清理"策略 |
60
+
61
+ ## 4. 数据处理(process)——逐步拓展,先立边界
62
+
63
+ **边界**:处理逻辑住在 notebook/脚本层(用户域),myastro 的职责是
64
+ **保证原料稳定**(schema 契约)+ **供处理层调用的最小工具**。
65
+
66
+ 判据:**"换个目标还会一模一样地做"的进库**(纯变换、可测试、契约稳定),
67
+ **"取决于这次想干什么"的留 notebook**(选目标、挑参数、画图、叙述)。
68
+
69
+ | 能力 | 级 | 现状 |
70
+ |---|---|---|
71
+ | 产物 schema 稳定承诺 | L2 | SCHEMA_VERSION=1 声明;列名即契约 |
72
+ | 处理示例 | L3 | 三个阶梯 notebook(凌星/造父/ZTF 差分) |
73
+ | **lc 时序工具库** | **L3** | 9 函数(归一化/筛选/折叠/分箱/幅度/周期搜索/凌星搜索)+ 17 测试;01/02 两片 notebook 已重构使用,数字与重构前逐项对账一致 | <!-- cap:process.lc -->
74
+ | phot 测光工具库 | L0 | 下一步 P2(检测/孔径测光/Gaia G 定标打底、APASS 校验) |
75
+ | imaging 图像工具库 | L0 | P3(对齐/叠加/差分),智能望远镜到手后做 |
76
+ | 派生产物目录约定 | 决策已定 | `data/derived/<目标>/`,与原始数据物理分离;实现待 P4 |
77
+ | 派生数据集溯源(derived_from) | L0 | P4:产物入账本、可反查原料 dataset 与处理参数 |
78
+ | 管线编排(处理链描述/重跑) | L0 | 远期;防止过度设计先不做 |
79
+
80
+ > **教训载体**:库函数不只是去重,还承载 notebook 里以文字记录的坑——
81
+ > `transit_search` 内部强制归一化(否则 TLS 静默 nan)并返回真深度
82
+ > (TLS `depth` 是凌内/凌外比);`period_search` 默认 LS+PDM 两步
83
+ > (LS 对非正弦光变系统性偏峰)。测试里有对应的回归项。
84
+
85
+ ## 5. 格式转换(convert)——领域概念确认
86
+
87
+ 天文领域该概念**真实存在且分两层**,但须防"格式金字塔"。
88
+ 原则:**正典格式 + 边缘按需转换**(正典 = 表格 parquet / 图像 fits)。
89
+
90
+ | 能力 | 级 | 现状 |
91
+ |---|---|---|
92
+ | 文件格式(fits 表 → parquet) | L1 | 隐式散在源实现里(tess/meta 即转换) |
93
+ | 时间系统(JD/MJD/BJD ↔ 相位) | L1 | notebook 手写;无统一工具 |
94
+ | 星等 ↔ 流量(含归一化) | L1 | 项目 2 手写 f/median;ZTF mag 列原生 |
95
+ | 坐标系(ICRS ↔ Galactic) | L0 | astropy 一行的事,按需暴露 |
96
+ | 互操作导出(CSV/AstroImageJ/VStar) | L0 | 有真实场景(AAVSO 上报)再做 |
97
+
98
+ > 判断标准:转换能力只在**第二个真实消费者出现**时升 L2(老规矩)。
99
+
100
+ ## 6. 呈现层(presentation,非能力域)
101
+
102
+ | 客户端 | 现状 |
103
+ |---|---|
104
+ | TUI(top) | 三面板 + 新建/批量/**预填充**模态(F1 新建、F2 从选中作业预填);身份寻址契约 | <!-- cap:present.tui -->
105
+ | CLI | 16 子命令:fetch 参数由描述符自动生成;错误→退出码 2/3/4/5 | <!-- cap:present.cli -->
106
+ | 文档 | 矩阵生成(doc-sync);API 参考未生成 |
107
+ | 第三方 | 门面 + 错误契约(含作业失败类型映射)+ 扩展点 register_source + `ma.prefill`(spec→表单,客户端共用) | <!-- cap:facade.api -->
108
+
109
+ ## 7. 当前最高价值的缺口(按能力排序)
110
+
111
+ 3. **保留策略 retention**(L0):job 归档、冷数据清理
112
+ 4. **本地检索坐标精确化**:现为 params 粗匹配,量级上来后需空间索引
113
+
114
+ ## 8. 维护纪律
115
+
116
+ - 本文档随能力变动更新(提交含能力变化时必须同步)
117
+ - 新工作入队格式:"把 X 能力从 Ln 推到 Lm",呈现层工作单列
118
+ - 每次架构 review 对照本文档检查:是否有能力降级/无契约实现