Organize living documentation and directory guides
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 13m40s

This commit is contained in:
2026-10-18 20:58:42 +08:00
parent 6fa95b64b0
commit 8bbe78e01e
30 changed files with 674 additions and 396 deletions
+61
View File
@@ -0,0 +1,61 @@
# 运行与宿主存储
这里说明跨 CLI、Server 和 Storage 的运行流程。当前本机禁止构建、测试、冒烟与依赖下载;以下命令供用户指定的远端环境执行。环境变量见 [配置](configuration.md),容器和生产服务见 [部署](deployment.md),检查见 [验证](validation.md)。
## 构建与 CLI
工作区要求 Rust 1.91 或兼容更高版本;构建镜像固定 rust:1.91.1-bookworm,依赖由 Cargo.lock 锁定。
```sh
cargo build --workspace --locked
cargo run -p aster-cli -- bootstrap
```
bootstrap 创建两个 Record,输出 runtime=EndorObject、type_system=disabled、objects_distinct=true 和 heap_objects=2,显式释放后输出 released heap_objects=0。它不读取数据库配置,因此无效 DATABASE_URL 也不影响该命令。
```sh
cargo run -p aster-cli -- metadata put project 'Aster VM'
cargo run -p aster-cli -- metadata get project
```
每次 metadata 命令读取宿主存储配置、连接、操作并关闭连接池;缺失键显示 (missing)。命令和退出码的源码位置见 [cli/src](../../crates/cli/src/README.md)。
## HTTP 宿主
```sh
cargo run -p aster-server
curl --fail http://127.0.0.1:8080/health
curl --fail http://127.0.0.1:8080/bootstrap
```
Server 创建空 VM、连接存储、初始化元数据表并写入 host.version,随后绑定监听地址。连接、初始化或绑定失败会退出,不降级换库。默认地址为 127.0.0.1:8080。
| 端点 | 行为 |
| --- | --- |
| GET /health | 实际 ping 数据库;成功返回 200,失联返回 503,含 status 和 storage 后端名 |
| GET /bootstrap | 返回 object_model=EndorObject、type_system=false、heap_objects=0;只读,不分配对象 |
当前未提供语言执行、对象写入或认证 API。Unix 上 Ctrl-C/SIGTERM 触发 Axum 优雅退出,等待服务结束后关闭共享 Storage;最后的 Arc 释放时销毁 Vm。没有执行中脚本的取消协议。
## 存储契约
Storage 不依赖 Core,只保存宿主元数据。连接时执行 schema.sql:aster_metadata 的 key 为非空文本主键,value 为非空文本。put 使用参数绑定并更新重复键,get 对不存在的键返回 None。当前只有幂等建表,没有版本化迁移;CREATE IF NOT EXISTS 不能升级已有列结构。
| 后端 | 当前行为 |
| --- | --- |
| SQLite 文件 | 默认 data/aster.db,相对当前工作目录;创建父目录和文件,开启 WAL,最多 5 个连接,busy timeout 5 秒 |
| SQLite 内存 | SQLITE_PATH=:memory:;单连接、不做空闲回收和最大存活轮换;不同 Storage 实例隔离 |
| PostgreSQL | DATABASE_URL 显式选择;最多 5 个连接,连接池获取超时 5 秒,启动即真实连接;失败不回退 SQLite |
Storage 克隆共享连接池,close 会关闭所有克隆使用的池。元数据可跨进程保存;VM 堆、句柄、全局对象和执行帧不持久化。重启服务创建新的空 VM。
## 出错时先查哪里
| 现象 | 定位 |
| --- | --- |
| bootstrap 正常,metadata/服务启动失败 | [存储配置](configuration.md)、[storage/src](../../crates/storage/src/README.md) |
| /health 返回 503 | 当前数据库连接;该端点不检测语言执行能力 |
| 容器替换后元数据丢失 | [卷与生产数据路径](deployment.md),先确认是否使用内存库 |
| 重启后找不到原 VM 对象 | 当前未实现 VM 快照,见 [生命周期](../runtime/lifecycle.md) |
返回 [文档索引](../README.md)。
+67
View File
@@ -0,0 +1,67 @@
# 配置、UTF-8 与进程边界
## 当前选择
当前先明确少量稳定边界,不引入 PyPreConfig/PyConfig 式两阶段初始化,也不新增 VM 配置文件、环境变量前缀或配置框架。Vm::new 从空堆启动;需要环境、数据库或网络的是宿主。
| 配置层 | 当前入口 | 责任 |
| --- | --- | --- |
| 内核 | Vm::new、显式创建对象/函数;call_with_limits/execute_with_limits | 可预测的运行时语义,不读取环境变量、修改 locale、注册信号或加载 .env |
| 宿主 | StorageConfig::from_env、Server 启动代码 | 将环境变量转成存储配置和监听地址,再启动服务 |
| 部署 | Compose 与 ces-control 脚本 | 端口映射、数据库密码、持久卷和镜像版本 |
| 构建/CI | Cargo.toml、Cargo.lock、Dockerfile、工作流 | 工具链、依赖锁定与验证环境;不作为语言运行语义配置 |
内核不直接依赖 HTTP、SQLx 或操作系统 locale 接口。这个隔离来自现有代码与分层,不是已经实现的独立安全沙箱。
## 为什么不照搬 CPython 的 locale 初始化
CPython 的 PyPreConfig 支持选择分配器、UTF-8 模式以及是否配置 LC_CTYPE,以处理它自己的启动和兼容性需求。Python 官方也提供忽略环境、保留 LC_CTYPE、不注册信号处理的隔离初始化。当前 Endor 通过 Rust 宿主接收已构造的值,没有需要复刻这套预初始化的依赖环。[CPython 初始化文档](https://docs.python.org/3.14/c-api/init_config.html)。
LC_CTYPE 处理字符分类、大小写和多字节字符相关约定;小数点和数字分组属于 LC_NUMERIC。只调整 LC_CTYPE 不能直接等同于修改数字小数点,这两类配置应区分。[locale 类别说明](https://docs.python.org/3.14/library/locale.html#locale.LC_CTYPE)。
云原生环境仍会遇到进程变量、终端、文件路径与外部工具的问题;较少跨语言互操作不代表可以省略输入边界。当前解决方式是让核心语义独立于进程区域设置,把必要的解码留在宿主入口。
## 当前文本和数字行为
- Value::Text 与 EndorStringObject 使用 Rust String,内容始终是有效 UTF-8。字符访问按 Unicode 标量值,不按字节或字形簇;不支持孤立代理码点。[Rust String](https://doc.rust-lang.org/std/string/struct.String.html#utf-8)。
- Number 的整数与十进制构造器明确检查 ASCII 数字和语法;十进制点为句点,不根据 LANG/LC_NUMERIC 切换为逗号。当前数值比较、哈希和算术尚未实现。
- 内核没有 setlocale 调用;不会为了启动 VM 修改 LANG、LC_ALL 或 LC_CTYPE。外部库、终端、字体或下游工具自身的行为不在这项保证之内。
- 尚无源码加载器、标识符语法、通用字节串对象或文件系统 API,因此不能宣称已完成源码编码、路径编码和全部 I/O 策略。
## 已有宿主环境变量
| 名称 | 使用位置与默认值 | 错误和优先级 |
| --- | --- | --- |
| DATABASE_URL | StorageConfig;未设置时才选择 SQLite | 仅 postgres:// 或 postgresql://;显式空值、错误协议和非 Unicode 值报错;连接失败不降级 |
| SQLITE_PATH | 无 DATABASE_URL 时使用;默认 data/aster.db | 空值和非 Unicode 值报错;:memory: 为临时库;设置 DATABASE_URL 后忽略此项 |
| ASTER_LISTEN | Server;默认 127.0.0.1:8080 | 当前 var(...).unwrap_or_else:缺失或非 Unicode 都用默认值;有效 Unicode 的错误地址在绑定时失败 |
| ASTER_PORT | Compose 宿主端口映射 | 独立方案默认 8080,ces-control 默认 18081;不是 Vm 配置 |
| POSTGRES_PASSWORD | PostgreSQL Compose/生产环境文件 | Compose 必填;示例使用随机十六进制以避免 URL 转义歧义;不写入仓库 |
| ASTER_IMAGE | ces-control Compose | 必填已构建的版本镜像,通常由 release.env 提供 |
| ASTER_RELEASE_SHA | CI 与部署脚本 | 必须为 40 位小写十六进制提交 SHA;用于镜像和版本目录 |
| ASTER_TEST_POSTGRES_URL | 指定环境显式运行 PostgreSQL 集成测试 | 专用测试库 URL;不是生产数据库配置 |
程序本身不自动加载 .env,Cargo 运行时须显式导出变量。Compose 会按其规则读取 .env;显式 --env-file 的生产文件由部署脚本管理。模板见 [.env.example](../../.env.example),执行链见 [部署](deployment.md)。
数据库 URL 可能包含密码;当前 StorageConfig 的 Debug 脱敏,公开数据库错误不回显 URL。底层错误 source 仍保留给宿主,不应不加处理地作为公开日志输出。
## 已有执行限额
ExecutionLimits 是每次调用显式传入的普通 Rust 值,不是进程全局开关;字段定义见 [frame.rs](../../crates/core/src/frame.rs)。
| 字段 | 默认值 | 作用 |
| --- | --- | --- |
| max_frames | 1000 | 本次执行允许的活动语言帧数量 |
| max_instructions | usize::MAX | 本次执行共享的逻辑指令预算;默认不设实用的有限预算 |
call_with_limits/execute_with_limits 使用自定义值;嵌套语言调用共用计数。预算不能抢占正在执行的 Native 回调,也没有超时、内存上限或异步取消能力;不能据此视为安全执行不可信代码的完整方案。
## 保留的入口缺口与以后再做的内容
CLI 当前使用 std::env::args,遇到非 Unicode 命令行参数可能 panic,并没有统一转换成友好的配置错误。[Rust args 文档](https://doc.rust-lang.org/std/env/fn.args.html#panics)。Server 的非 Unicode ASTER_LISTEN 也尚未像存储变量一样严格报错;宿主输入错误接口尚未统一。
以后增加宿主输入时,应明确使用 OsString/PathBuf 保留系统路径,或显式拒绝不符合文本协议的输入;不要通过修改整个进程 locale 让隐式解码暂时成功。未来源码文本默认 UTF-8、协议数字固定格式是设计方向,只有加载器实现后才能写成已实现行为。
现在不新增通用 VmConfig。出现构造期策略时再集中为实例级不可变配置;进程参数由宿主解析后传入,不让 Vm::new 自动读取一组隐含开关。时区、模块路径、凭据注入、内存配额和网络能力也按实际实现分别设计,不预设已存在。
返回 [运行指南](README.md) 或 [文档索引](../README.md)。
+69
View File
@@ -0,0 +1,69 @@
# Docker 与 ces-control 部署
这里描述仓库当前工作流和脚本行为,不代表正在运行的服务器状态。正式持久部署选择 PostgreSQL,SQLite Compose 保留为独立运行选项。配置字段见 [配置](configuration.md),CI 检查细节见 [验证](validation.md)。
## 镜像与独立运行
Dockerfile 的 source 阶段复制 Cargo 工作区及脚本;ci 阶段安装远端检查工具,build 阶段构建 aster-server 和 aster,runtime 阶段使用 Debian slim、UID 10001、/data 工作目录及 HTTP 健康检查。
指定环境的 SQLite 方案:
```sh
cp .env.example .env
docker compose up --build -d
curl --fail http://127.0.0.1:8080/health
docker compose exec aster aster metadata put project 'Aster VM'
```
默认 docker-compose.yml 只向应用提供 SQLITE_PATH,使用 aster-sqlite 命名卷;不透传 DATABASE_URL。down 保留数据,down -v 会删除卷。
指定环境的 PostgreSQL 独立替代方案:先在 .env 中将 POSTGRES_PASSWORD 改为随机十六进制字符串,例如 openssl rand -hex 24,再运行:
```sh
docker compose -f docker-compose.postgres.yml up --build -d
docker compose -f docker-compose.postgres.yml exec aster aster metadata get project
```
仅使用该 Compose 文件,不与默认 SQLite 文件叠加。此方案使用 aster-postgres 命名卷、PostgreSQL 17;数据库不发布宿主端口。两个独立方案不要同时占用相同应用端口。内部示例连接禁用 TLS,跨不可信网络使用 PostgreSQL TLS 验证。
## CI 到正式发布
[工作流](../../.gitea/workflows/README.md) 响应 main push 和 workflow_dispatch,在 ces-control 上串行运行:
1. 检出代码,调用 ci-ces-control.sh;在 Docker 中检查 workspace、SQLite/HTTP 冒烟及专用真实 PostgreSQL。
2. 检查成功后构建 endorphin-aster-vm:<sha> 生产镜像。
3. main 上调用 deploy-ces-control.sh 更新 PostgreSQL 宿主。
临时检查容器与网络退出时清理,Cargo 下载与构建缓存保留在专属远端卷。生产镜像、已有发布目录与数据库数据保留;没有自动 image prune 或数据库卷清理。工作流不改动其他项目或共享 Runner 配置。
## 生产目录与数据
| 路径 | 用途 |
| --- | --- |
| /opt/endorphin-aster-vm/releases/<sha>/ | 固定版本的 compose.yml 与 release.env |
| /opt/endorphin-aster-vm/current | 最近通过部署检查的版本符号链接 |
| /etc/endorphin-aster-vm/production.env | 首次生成的数据库密码和默认端口,权限 0600 |
| /var/lib/endorphin-aster-vm/postgres | 独立的 PostgreSQL 持久数据目录 |
| /var/lock/endorphin-aster-vm-deploy.lock | 避免并行切换生产版本的文件锁 |
生产 Compose 固定项目名 endorphin-aster-vm,默认应用入口仅绑定 127.0.0.1:18081;数据库不发布端口,两个服务使用 unless-stopped 自动重启和日志轮换。端口绑定回环地址不等于已实现应用认证。
部署脚本只接受已构建镜像。启动容器、健康检查、真实元数据 put/get 及 PostgreSQL 后端确认都成功后才切换 current。失败时保留数据并尝试恢复上一个健康版本;首次部署没有旧版本可恢复。脚本内容导航见 [scripts](../../scripts/README.md)。
## 查看、停止与恢复
以下命令在服务器上使用已有生产配置,不重新生成密码:
```sh
docker compose -p endorphin-aster-vm --env-file /etc/endorphin-aster-vm/production.env --env-file /opt/endorphin-aster-vm/current/release.env -f /opt/endorphin-aster-vm/current/compose.yml ps
curl --fail http://127.0.0.1:18081/health
curl --fail http://127.0.0.1:18081/bootstrap
```
同样的 Compose 参数接 stop 停服保留数据,接 up -d --wait 恢复。不要删除数据目录或使用删除卷的操作代替停服。
更改环境文件密码不会自动修改已有 PostgreSQL 数据库用户密码;需另行同步数据库凭据。数据库 major 升级、schema 变更需要迁移设计,恢复旧应用镜像不等于回退数据库。
Compose 配置依据 [Docker 环境变量说明](https://docs.docker.com/compose/how-tos/environment-variables/variable-interpolation/),触发方式依据 [Gitea Actions](https://docs.gitea.com/usage/actions/)。按用户约定不主动追踪运行状态;需要排障时针对具体提交核实,不能用旧成功记录推断新版本结果。
返回 [运行指南](README.md) 或 [文档索引](../README.md)。
+44
View File
@@ -0,0 +1,44 @@
# 验证范围与结果边界
本页维护当前检查入口和覆盖范围,不累计已失效的测试数量、机器资源快照或旧对象模型的通过记录。历史行为查 Git 历史;某个版本是否通过,只能依据该提交对应的实际结果。
## 执行约定
本地不运行 Cargo 构建、测试、Clippy、冒烟、Docker 或依赖下载;允许阅读、格式化和静态文件/文档检查。指定运行验证环境为 ces-control。按用户要求不主动追踪 CI/部署结果,有问题由用户反馈后再查。
## 检查入口
以下命令只在指定的验证环境执行,不表示已经运行:
```sh
sh scripts/check.sh
cargo test -p aster-storage --test postgres --locked -- --ignored
python3 scripts/smoke.py
```
check.sh 执行 cargo fmt --all --check、cargo test --workspace --locked 和 cargo clippy --workspace --all-targets --locked -- -D warnings。workspace 测试也包含 rustdoc 示例;显式忽略的 PostgreSQL 测试需要单独执行。
ci-ces-control.sh 负责准备专用临时 PostgreSQL 和测试 URL;成功路径使用真实数据库,不用模拟 socket 代替。测试库与生产数据不共享挂载。没有 ASTER_TEST_POSTGRES_URL 时,显式执行 PostgreSQL 测试会失败,不标记为通过。
## 覆盖范围与文件位置
| 范围 | 当前检查内容 | 入口 |
| --- | --- | --- |
| 堆内部边界 | 非法索引、槽位代数、代数耗尽、计数溢出原子性 | [core/src](../../crates/core/src/README.md) 的 heap.rs 私有单元测试 |
| 对象运行时 | 地址稳定、引用/借用、属性、长链、循环、原生操作、VM 销毁 | [core/tests](../../crates/core/tests/README.md) 的 runtime.rs |
| 基本对象 | Number 表示、字符串、Dict/Cell 引用与更新、函数环境、异常数据 | 同目录 builtins.rs |
| 字节码 | 编解码、非法指令/控制流、跳转、调用、闭包、结果存活、失败清理与限额 | 同目录 execution.rs |
| 公开示例 | 对象操作、手写指令执行与释放 | [core/src](../../crates/core/src/README.md) 的 lib.rs rustdoc |
| 存储 | 配置优先级、内存隔离/共享、文件重连、失败不降级、真实 PostgreSQL | [storage/tests](../../crates/storage/tests/README.md) |
| HTTP 状态 | 数据库关闭后 health 返回 unavailable | [server/src](../../crates/server/src/README.md) 的单元测试 |
| 端到端宿主 | CLI 跨进程元数据、独立 bootstrap、错误配置、HTTP 与 SIGTERM | [scripts](../../scripts/README.md) 的 smoke.py |
测试源码说明验证意图,不能证明已通过;现有测试也不代表完整 Python 兼容、panic 恢复、云沙箱或 VM 快照已经实现。
## 文档修改的静态检查
修改后核对所有受版本管理目录存在 README、父目录有入口、相对链接指向现存文件;运行 git diff --check 检查差异空白。静态文本检索可以查出旧路径和过时 API;维护规则见 [开发与文档维护](../contributing/README.md)。这些检查不执行 VM 或数据库。
仅修改文档时也不据此宣称运行检查通过。推送触发现有 CI 时,仍由原流程检查和部署;报告应分别说明静态检查、运行测试与推送结果。
返回 [运行指南](README.md) 或 [文档索引](../README.md)。