# sshconfig-resolve 总体架构

## 1. 架构目标与约束

目标是把不可信配置文本转换为确定、可解释的有效配置，同时把纯语义与 native IO
隔离。核心包必须 all-target；真实文件、环境与 CLI 必须 native-only；任何包都不
执行配置中的命令或读取 IdentityFile 内容。公开类型由实际公共 package 持有，根
facade 只重导出。

依赖方向：`syntax` ← `loader`、`syntax/pattern` ← `resolve`、`loader/resolve` ← `native`、
`syntax/pattern/loader/resolve` ← root facade、`native/loader/resolve/syntax` ← `cmd/sshcfg`。
禁止 `syntax/pattern/loader/resolve → native/CLI` 和 `loader → resolve`，避免环依赖
与 IO/语义混杂。

## 2. Package 职责


| Package                           | 职责                                                            | 依赖                                     |
| --------------------------------- | --------------------------------------------------------------- | ---------------------------------------- |
| `syntax`                          | lexer、ordered AST、strict/recovering diagnostics、span         | core                                     |
| `pattern`                         | glob、pattern-list、Match predicates、limits                    | core                                     |
| `loader`                          | FileSystem contract、path、Include expansion、limits/provenance | `syntax`                                 |
| `resolve`                         | directive spec/validation/merge、context、token、trace/query    | `syntax`、`pattern`                      |
| `native`                          | native filesystem/environment adapter、path convenience         | `loader`、`resolve`、`moonbitlang/x`     |
| root package                      | portable facade 与公开 API 汇总                                 | `syntax`、`pattern`、`loader`、`resolve` |
| `cmd/sshcfg`                      | argv、resolve/explain/lint/version、输出/脱敏/退出码            | `syntax`、`loader`、`resolve`、`native`  |
| `integration` + package tests     | API contract、跨包 E2E、property/边界测试                       | 被测公共包                               |
| fixtures/scripts/examples/CI/docs | conformance、interop、演示、发布和申报证据                      | facade/CLI                               |

## 3. 目录结构

```
sshconfig-resolve/
├── moon.mod
├── moon.pkg + sshconfig.mbt
├── syntax/           lexer、AST、diagnostics
├── pattern/          glob、pattern-list、Match
├── loader/           FileSystem、Include、limits
├── resolve/          directive spec、merge、token、trace
├── native/           native filesystem adapter
├── cmd/sshcfg/       native CLI
├── integration/      cross-package MoonBit tests
├── test/conformance + test/interop
├── scripts/          reproducible harness
├── examples/basic + bench/resolve
├── .github/workflows/ci.yml
└── docs/ + LICENSE
```

## 4. 核心类型与公开接口

- `syntax` 拥有 `SourceLocation/SourceSpan/Argument/Directive/ConfigItem/Config`、
  `ParseError/Diagnostic/ParseResult`，公开 `parse` 与 `parse_recovering`。
- `pattern` 拥有 `PatternList/PatternDecision/MatchPredicate/MatchContext/PatternError`。
- `loader` 拥有 `FileSystem/LoadOptions/LoadedConfig/LoadError/MemoryFileSystem`。
- `resolve` 拥有 `ResolveContext/ResolvedValue/ResolvedConfig/ResolveOutcome/TraceEvent`
  与 `ResolveError`，公开 `resolve/resolve_explained/resolve_strict`。
- `native` 拥有 `NativeFileSystem` 和 native convenience API；第三方 fs 类型不外泄。
- root package 使用 `pub using` 重导出上述 portable API，不复制类型定义。
- `cmd/sshcfg` 的 command/options/exit model 保持 package-private。

公开 Array/Map getter 必须返回不破坏内部状态的值；调用者可构造/匹配的 concrete
类型不放入 `internal/*`。

## 5. 数据流与关键算法

text/path → lexer → ordered Config with spans → Include DFS → Host glob / Match →
directive table → first-set/append/special merge → effective context update →
token expansion → ResolvedConfig + TraceEvent[] → facade / text / JSON / lint。

glob 使用非递归匹配并由 rolling-DP reference 测试对照；Include 只用 active stack
检测环，允许非递归位置重复 include；resolver 按源顺序单次运行并同时生成结果/trace，
避免 explain 二次求值漂移。

## 6. 错误模型


| 边界          | 所有者       | 典型错误                                       | 传播                                                |
| ------------- | ------------ | ---------------------------------------------- | --------------------------------------------------- |
| 文本/语法     | `syntax`     | NUL、quote/escape、line/argument/block         | strict 抛`ParseError`；recovering 生成 `Diagnostic` |
| pattern/Match | `pattern`    | 空/过长/过多、缺参、unsupported condition      | `PatternError`，resolver 映射为 trace/strict error  |
| 文件/Include  | `loader`     | read、cycle、limit、missing、parse chain       | `LoadError`/`LoadDiagnostic`                        |
| 求值          | `resolve`    | invalid value、unsupported/missing token/Match | trace 或`ResolveError`                              |
| native        | `native`     | not-found/permission/not-file/path             | 映射到 portable loader error                        |
| CLI           | `cmd/sshcfg` | usage/load/resolve/lint/internal               | 安全文本 + 稳定退出码                               |

不以字符串抹掉 owning error 的分类；诊断默认截断/脱敏敏感内容。

## 7. 并发与一致性模型

不适用并发共享状态：当前 API 为同步、单次调用、调用者拥有输入和结果。可变 Map/
Array 只存在于单次 parse/load/resolve 内部。确定性由源顺序、显式 context、稳定
glob 排序和固定输出顺序保证。未来若并行读取 Include，必须保持 DFS 插入顺序并禁止
共享 adapter 回调在锁内执行。

## 8. Target 与互操作边界

- portable：root、syntax、pattern、loader、resolve、integration tests；
- native-only：native、cmd/sshcfg、bench；
- Linux/OpenSSH：当前真实 `ssh -G` 互操作承诺；
- wasm-gc/wasm/js/native：核心 check/test 矩阵；
- 不声明 symlink-aware native identity 或 Windows/macOS 完整路径兼容。
