ctx_runner 0.2.1 → 0.2.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +4 -1
- data/docs/module-boundaries.md +94 -0
- data/docs/verification-2026-10-25.md +44 -0
- data/lib/ctx_runner/collection.rb +11 -13
- data/lib/ctx_runner/execution.rb +16 -15
- data/lib/ctx_runner/session_scope.rb +50 -0
- data/lib/ctx_runner/version.rb +1 -1
- data/lib/ctx_runner.rb +1 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 481f161a0681e4a60c15d9642a854e408ff4f1cef0a8ec110915b845e4a42032
|
|
4
|
+
data.tar.gz: 9d736f25c0a90fa70760131ee5f0cb3d95a757e27fcc86621c7a75c9a34535dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 147a0ebe6de5d9ec73a6b5affa610bd69cc5b1213f406ef0d7d9cac5927041c74afcca3fad1f8069972b071092e191197b4338b62f47d7227fe9fefe02a7eb8e
|
|
7
|
+
data.tar.gz: 74120e2e22b4324d5f946c155ef4aab97664ed056e4b28f8f1327773420ca3895a3a6c926a61f97f1bc3898f6a5ffa84366d7037c1bf29b6f3ed9d0ab714a00e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.2.2 (2026-10-25)
|
|
6
|
+
|
|
7
|
+
- Share a single session delivery scope between collection and controlled execution; reject swallowed delivery violations, unfinished operations and cross-thread callbacks without replaying device actions.
|
|
8
|
+
- Preserve the first collection delivery failure when connection cleanup also fails; document module ownership and business operation boundaries.
|
|
9
|
+
|
|
5
10
|
## 0.2.1 (2026-10-24)
|
|
6
11
|
|
|
7
12
|
- Leave ctx_parser and ctx_driver dependencies unconstrained in the gemspec; retain the current collection, immutable report and execution contracts.
|
data/README.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
| 对象 | 负责的业务 |
|
|
8
8
|
| --- | --- |
|
|
9
|
+
| `SessionScope` | 当前线程内一次会话交付、未完成事实和回调撤销 |
|
|
9
10
|
| `Collection` | 一次连接器交付、阶段诊断、禁止重复执行 |
|
|
10
11
|
| `Query` | 单命令读取解析、共享视图、失败与来源绑定 |
|
|
11
12
|
| `Observation` | 事实外壳、可用性、时间类型、深度快照及安全展示 |
|
|
@@ -37,7 +38,9 @@ end
|
|
|
37
38
|
|
|
38
39
|
领域 Profile 实现 `parse_many(names, body, complete:, command:)`;不可用投影接收 `(name, capture, failure)`。一次 Query 对应一条命令,多个视图共享同一份 Capture。
|
|
39
40
|
|
|
40
|
-
`Collection.new(strict: true)` 对连接器零次/重复回调抛出 ArgumentError,兼容严格宿主契约;默认记录 session_not_opened/session_reentered
|
|
41
|
+
`Collection.new(strict: true)` 对连接器零次/重复回调抛出 ArgumentError,兼容严格宿主契约;默认记录 session_not_opened/session_reentered。交付块未正常完成但异常被连接器吞掉时记录 session_incomplete;跨线程交付记录 session_out_of_scope,并拒绝执行领域块。连接关闭错误不会覆盖已完成的领域事实或先前交付故障。借用会话直接使用 Reader/Query,无需再进入 Collection。
|
|
42
|
+
|
|
43
|
+
Collection 与 Execution 共用 `SessionScope`。会话必须由创建流程的线程同步交付;并行调度应在每个设备任务内部创建流程。重复交付的异常即使被提供方吞掉,流程仍不能报告完成;所有者退出后保留的回调立即失效。作用域不持有或关闭会话,连接清理仍由连接器负责。跨模块职责、业务原子边界与领域拆分见 [模块设计](docs/module-boundaries.md)。
|
|
41
44
|
|
|
42
45
|
`Batch.new(report:, progress:, requested:)` 接收报告和进度协作者。`collect(device) { snapshot }` 返回不含原始配置的设备摘要;`run(present:) { ... }` 包住调度和领域后处理;块必须在返回或抛错前回收全部任务。Runner 统一取消、执行失败、报告及输出失败,返回不可变 Completion(status、summary、安全 failure、finalization_error、recovery_failed)。取消优先于收尾失败,展示失败只补写报告、不重采或重复展示。进入收尾即关闭结果登记,run 不可重放。CLI 将 complete/incomplete/failed/interrupted 映射到 0/1/2/130。`finish` 是内部交付步骤;调度和网络资源仍由宿主拥有。
|
|
43
46
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# 网络模块的业务边界与原子操作
|
|
2
|
+
|
|
3
|
+
本设计覆盖 ctx_parser、ctx_driver、ctx_runner、ctx_cli、ctx_checker、net-connector、expect-pty、VXLAN 和 Wireless。目录中的 `expect-ruby` 对应 expect-pty,连接器当前工作目录为 `net-connector-trunk`。相邻 worktree 可能包含不同工作,不能当作同一版本。
|
|
4
|
+
|
|
5
|
+
## 业务链路与依赖
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart TD
|
|
9
|
+
CLI[领域 CLI / 宿主] --> CtxCli[ctx_cli:输入、预检、交互与退出码]
|
|
10
|
+
CLI --> Domain[VXLAN / Wireless / ctx_checker:领域计划和判定]
|
|
11
|
+
Domain --> Runner[ctx_runner:采集交付、报告、受控执行]
|
|
12
|
+
Domain --> Parser[ctx_parser:声明、解析与不可变事实]
|
|
13
|
+
Runner --> Driver[ctx_driver:单命令执行与来源回执]
|
|
14
|
+
Driver --> Parser
|
|
15
|
+
CLI --> Connector[net-connector:连接、认证、操作租约和设备对话]
|
|
16
|
+
Driver -. 借用已打开会话 .-> Connector
|
|
17
|
+
Connector --> PTY[expect-pty:IO、PID、匹配和资源回收]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
实线表示业务组合或依赖方向;Driver 的原生适配只操作已加载连接器提供的会话,不自动 require、打开或重连。ctx_cli 不依赖 Runner 或具体领域,通过显式 adapter 和 batch 协作者完成终端编排。net-connector 的 CLI 使用 ctx_cli;底层 PTY 不反向依赖业务库。
|
|
21
|
+
|
|
22
|
+
| 模块 | 独立职责 | 交付物或接口 | 资源所有权 |
|
|
23
|
+
| --- | --- | --- | --- |
|
|
24
|
+
| expect-pty | 进程创建、字节匹配、超时、脱敏、关闭回收 | Session、Result、ResourceOwner | 拥有创建的 IO/PID;借用日志目标 |
|
|
25
|
+
| net-connector | 认证、提示符、厂商对话、操作互斥、命令步骤 | 原生 Session、Result、Command | 拥有连接及操作租约;关闭底层资源 |
|
|
26
|
+
| ctx_driver | 校验单条查询、执行回执、正文和原始摘要分离 | Reader、Capture、可选 Session 适配 | 借用会话;首次失同步后停止后续命令 |
|
|
27
|
+
| ctx_parser | 文本来源、命令声明、共享视图、事实快照 | Commands、Profile、Result、Immutable | 不持有连接或宿主状态 |
|
|
28
|
+
| ctx_runner | 唯一会话交付、单查询、批量结果、证据发布和已确认变更 | SessionScope、Collection、Query、Batch、Report、Execution | 借用会话;报告对象拥有自己的文件 |
|
|
29
|
+
| ctx_cli | 来源配置、输入预算、静态预览、预检顺序、交互和退出码 | Configuration、Collection、Review、Output | 借用标准流;调度任务须由宿主回收 |
|
|
30
|
+
| ctx_checker | 配置适用性、有限发现、观测关联、健康和计数策略 | Collector、Applicability、Snapshot、Evaluator | 借用连接器;规则独立于传输 |
|
|
31
|
+
| VXLAN | 配置依赖、Fabric 范围、服务身份、ACL 和类型化增量 | CollectionPlan、Collector、Fabric::Review、ChangePlan | 领域连接适配器取得操作租约 |
|
|
32
|
+
| Wireless | 控制器查询、AP 身份和选择、邻居覆盖、模板增量 | Collector、ApCollection、ApSession、Projection、ChangePlan | ApCollection 借用控制器;ApSession 管理转接租约 |
|
|
33
|
+
|
|
34
|
+
## 原子操作的含义
|
|
35
|
+
|
|
36
|
+
原子边界由可独立核验的业务事实决定,不能把一次跨设备网络操作当成本地事务。
|
|
37
|
+
|
|
38
|
+
1. **请求预检**:完整校验设备身份、维度、凭据与资源限制后再打开连接。身份和选择范围在任何时钟、连接器、凭据回调前复制。
|
|
39
|
+
2. **会话交付**:每次 Collection 或 Execution 只能在创建它的线程内接受一次同步交付。零交付、重复、跨线程或未正常完成都不能成为成功。
|
|
40
|
+
3. **单命令 Capture**:一条查询对应一个回执;原始字节摘要与解码正文分别保存。失败不重放;失同步后的查询标记 skipped。
|
|
41
|
+
4. **单来源多视图**:共享命令读取、解析一次,各视图独立投影。单个视图失败不抹除其他视图或其他来源。
|
|
42
|
+
5. **单 AP 邻居采集**:AP 清单决定选择范围;无匹配不读取凭据。每个 AP 独立保留尝试状态、摘要、邻居数和失败阶段,部分覆盖不能刷新未采集 AP 的覆盖时间。
|
|
43
|
+
6. **单设备报告交付**:先登记设备事实,再持久化报告。保存失败不能删除设备已经完成的结果;文件原子替换与目录同步分别记账。
|
|
44
|
+
7. **单项确认变更**:先保存意图,回读配置并比对指纹,逐条记录 pending/acknowledged,最后回读验证。发送后失败为 uncertain,不自动回滚或重试。
|
|
45
|
+
8. **批次完成**:调度器回收全部工作后,再计算交付状态并发布摘要。终端展示失败只补写状态,不能再次连接设备。
|
|
46
|
+
|
|
47
|
+
## 统一会话作用域
|
|
48
|
+
|
|
49
|
+
`SessionScope` 只维护一次交付资格、完成事实和撤销状态,不持有会话对象、连接器、业务回调或凭据。短临界区保护资格变更,领域操作在锁外执行。`close` 只撤销回调资格,不关闭设备连接。
|
|
50
|
+
|
|
51
|
+
```mermaid
|
|
52
|
+
stateDiagram-v2
|
|
53
|
+
[*] --> Waiting
|
|
54
|
+
Waiting --> Running: 当前线程首次交付
|
|
55
|
+
Running --> Completed: 领域块正常返回
|
|
56
|
+
Waiting --> Invalid: 跨线程交付
|
|
57
|
+
Running --> Invalid: 重复或重入交付
|
|
58
|
+
Completed --> Invalid: 再次交付
|
|
59
|
+
Waiting --> Closed: 所有者退出
|
|
60
|
+
Running --> Closed: 异常或取消退出
|
|
61
|
+
Completed --> Closed: 所有者退出
|
|
62
|
+
Invalid --> Closed: 所有者退出
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
交付失败状态保留到流程结束,即使连接器 rescue 了回调异常,也不能恢复为完成。作用域结束后的回调直接抛出 IOError,且不修改已经发布的结果。
|
|
66
|
+
|
|
67
|
+
| 事实 | Collection 默认模式 | Collection strict 模式 | Execution |
|
|
68
|
+
| --- | --- | --- | --- |
|
|
69
|
+
| 没有交付 | session_not_opened | ArgumentError | failed;不发命令 |
|
|
70
|
+
| 重复交付 | session_reentered;保留首次事实 | ArgumentError,外部吞掉后仍拒绝完成 | 已发送则 uncertain;不重放 |
|
|
71
|
+
| 交付块未完成但异常被提供方吞掉 | session_incomplete | ArgumentError | failed/uncertain,取决于是否开始发送 |
|
|
72
|
+
| 跨线程交付 | session_out_of_scope;不调用领域块 | ArgumentError | failed;不发命令 |
|
|
73
|
+
| 关闭连接失败 | session_close_failed;保留已完成事实和先前交付故障 | 同左 | 不发布 configuration_verified |
|
|
74
|
+
|
|
75
|
+
线程池应在每个设备任务内部创建 Collection/Execution 并同步打开、使用、关闭该设备的会话。并行发生在设备任务之间,不能将已借出的会话回调移交给后台线程。
|
|
76
|
+
|
|
77
|
+
## Wireless 的领域拆分
|
|
78
|
+
|
|
79
|
+
`Collector` 保留控制器请求预检、依赖维度展开、终端准备、共享查询和最终 Snapshot。`ApCollection` 接收不可变 access_points 观测、借用控制器会话、选择名称、延迟凭据源与 AP 会话工厂,输出一个 LLDP Observation。
|
|
80
|
+
|
|
81
|
+
ApCollection 负责 AP 选择、缺失名称、覆盖范围、回执归属及逐 AP 失败隔离;`ApSession` 继续负责登录/返回控制器和嵌套操作租约。厂商 Profile 和 NeighborParser 继续维护命令及语法。公共 Runner 不承担 AP、型号、Fabric 或健康策略。
|
|
82
|
+
|
|
83
|
+
已有 `Wireless::Collector#collect` 参数和返回结构保持兼容。新的领域对象可以单独使用,但必须显式提供 `Wireless::Observation(name: :access_points)`;选择范围在回调前快照,非法输入在访问凭据前拒绝。
|
|
84
|
+
|
|
85
|
+
## 本次落地与验证边界
|
|
86
|
+
|
|
87
|
+
- Collection 和 Execution 共用 SessionScope,移除两份交付状态逻辑;补全吞异常、跨线程、重复交付及非局部退出的行为测试。
|
|
88
|
+
- Wireless 的 AP 邻居业务从 Collector 提取到 ApCollection,保留原有来源和诊断语义,并增加独立入口的输入边界测试。
|
|
89
|
+
- VXLAN、ctx_checker 经现有 Collection 自动使用统一约束;ctx_parser、ctx_driver、ctx_cli、net-connector、expect-pty 保持其当前职责,不增加反向依赖。
|
|
90
|
+
- 包括原生适配和 PTY 的链路需要用本地合成会话验证;网络设备兼容性仍需对应型号实机验证。源码联调与隔离 gem 安装是不同验收项。
|
|
91
|
+
|
|
92
|
+
后续改动仍应以具体业务不变量为依据:发现策略留在 ctx_checker,配置依赖留在 VXLAN,AP 选择和租约留在 Wireless;不要因类名相似而合并这些策略,也不要新增统一工作流 DSL。对底层资源所有权的修改必须覆盖取消、关闭失败和已完成设备效果的保留。
|
|
93
|
+
|
|
94
|
+
本次验证结果、环境限制与复现证据见 [2026-10-25 验证记录](verification-2026-10-25.md)。
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 2026-10-25 模块边界重构验证
|
|
2
|
+
|
|
3
|
+
本次代码改动集中于 ctx_runner 的 SessionScope/Collection/Execution 和 Wireless 的 ApCollection/Collector。模块设计见 [module-boundaries.md](module-boundaries.md)。工作区已有大量未提交改动,本记录只评价本次重构及相关链路,不替代各仓库完整发布验证。
|
|
4
|
+
|
|
5
|
+
## 已通过
|
|
6
|
+
|
|
7
|
+
| 检查 | 结果 | 范围 |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| 关键回归前后对照 | 原实现 3 项失败;修改后 3 项通过 | 提供方吞掉未完成异常、严格模式重复交付、变更执行重复交付 |
|
|
10
|
+
| 跨模块业务契约 | 18/18 通过 | 会话作用域、执行记账、VXLAN、Wireless、AP 选择/覆盖和 ctx_checker 共享查询 |
|
|
11
|
+
| net-connector 定向测试 | 69 tests / 664 assertions,通过 | execution_receipts、engine_boundary、transport |
|
|
12
|
+
| expect-pty 定向测试 | 35 tests / 225 assertions,通过 | cleanup、cleanup_priority、resource_acquisition |
|
|
13
|
+
| 现有离线与本地 PTY 示例 | 9 个通过 | ctx_parser 1、ctx_driver 2、ctx_runner 2、ctx_checker 2、VXLAN 1、Wireless 1 |
|
|
14
|
+
| 修改文件语法 | 10 个 Ruby 文件通过 | 生产代码及新增/修改的 RSpec 文件 |
|
|
15
|
+
| 按能力独立加载 | 通过 | `require "wireless/ap_collection"` 未加载 net-connector |
|
|
16
|
+
| 差异格式 | 通过 | ctx_runner、Wireless 的 `git diff --check` |
|
|
17
|
+
|
|
18
|
+
Driver 与 Checker 的 connector 示例使用真实 expect-pty、net-connector、Driver 和解析器驱动本地合成 PTY。没有连接真实设备,不声明所有厂商型号兼容性。
|
|
19
|
+
|
|
20
|
+
## 环境与限制
|
|
21
|
+
|
|
22
|
+
环境初始没有 Ruby;从工作区已有 Ruby 4.0.7 源码构建了 Linux x86_64 验证运行时。安装遗漏的 `digest/sha2/loader.rb` 从同一源码补入测试运行时,未修改项目业务实现。由于缺少 libyaml,Psych 未构建。
|
|
23
|
+
|
|
24
|
+
底层定向测试使用工作区缓存的 Minitest 源码,源码 `VERSION=5.26.2`,缓存目录和 gem specification 标为 5.27.0。明确激活该缓存并设置 `MT_NO_PLUGINS=1`,避免内置 Minitest 6 的插件再次加载并清空测试注册。最终记录均核对了非零 test/assertion 数;总计 104 tests、889 assertions,0 failures、0 errors、0 skips。这属于本地兼容性验证,不是锁定依赖矩阵通过。
|
|
25
|
+
|
|
26
|
+
下列检查尚未完成:
|
|
27
|
+
|
|
28
|
+
- ctx_runner 和 Wireless 的 `bundle exec rake`:以 frozen 模式运行时,分别被现有锁文件 ctx_parser/ctx_cli 的空 CHECKSUMS 项阻止;未修改锁文件。环境还缺少 RSpec 和项目完整依赖。
|
|
29
|
+
- 新增 RSpec 回归已写入对应仓库,并完成语法校验;上述独立契约检查覆盖了关键行为,但不等于 RSpec 全量运行。
|
|
30
|
+
- ctx_cli 的两个示例、VXLAN 的 collect/parse CLI 示例:因缺少 Psych/YAML 不能完成。
|
|
31
|
+
- 两个改动包的 `gem build`:因缺少 Psych 失败,因此尚未执行隔离 gem 安装验证。
|
|
32
|
+
- 完整 RuboCop、Ruby 版本/操作系统矩阵及实机验收尚未运行。RubyGems 域名在当前环境无法解析,不能补齐缺失依赖。
|
|
33
|
+
|
|
34
|
+
## 证据与复现
|
|
35
|
+
|
|
36
|
+
本地脚本与日志保存在工作区 `.module-validation-20261025/`:
|
|
37
|
+
|
|
38
|
+
- `verify.rb` / `logs/contracts.json`:18 项源码联调。
|
|
39
|
+
- `regressions.rb` / `logs/regressions-before.json` / `logs/regressions-after.json`:3 项缺陷前后对照。
|
|
40
|
+
- `check-native.py` / `logs/native-tests.json`:底层定向测试及计数。
|
|
41
|
+
- `check-examples.py` / `logs/examples.json`:示例逐项退出码。
|
|
42
|
+
- `logs/syntax.json`:语法校验;其余 log 保存构建、Bundler 和示例诊断。
|
|
43
|
+
|
|
44
|
+
为避免重新堆积大型临时文件,完成验证后删除本次创建的编译目录和测试运行时;保留脚本及日志。需要重建时可在工作区根目录执行 `sh .module-validation-20261025/build-runtime.sh`,并补齐 libyaml/Psych、RSpec 和锁定依赖,再运行各仓库完整 gate、构建和隔离安装验证。源码联调脚本使用显式 RUBYLIB,不修改 gemspec 的安装边界。
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "ctx_driver/failure"
|
|
4
|
+
require_relative "session_scope"
|
|
4
5
|
|
|
5
6
|
module CtxRunner
|
|
6
7
|
# 约束一次连接器交付,不接管连接或操作租约;已取得的事实由领域块保留。
|
|
@@ -32,26 +33,23 @@ module CtxRunner
|
|
|
32
33
|
private
|
|
33
34
|
|
|
34
35
|
def acquire(connector)
|
|
35
|
-
|
|
36
|
-
active = true
|
|
36
|
+
scope = SessionScope.new
|
|
37
37
|
connector.open do |session|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
delivered = scope.deliver do
|
|
39
|
+
@stage = :collect
|
|
40
|
+
yield session
|
|
41
|
+
@stage = :close
|
|
42
42
|
end
|
|
43
|
-
|
|
44
|
-
@stage = :collect
|
|
45
|
-
yield session
|
|
46
|
-
@stage = :close
|
|
43
|
+
contract_failure(scope.failure) unless delivered
|
|
47
44
|
end
|
|
48
|
-
|
|
45
|
+
scope.close
|
|
46
|
+
contract_failure(scope.failure) if scope.failure
|
|
49
47
|
rescue StandardError => error
|
|
50
48
|
raise unless CtxDriver::Failure.connection_error?(error, connector)
|
|
51
49
|
details = CtxDriver::Failure.details(error, fallback: :connection_failed, stage: stage)
|
|
52
|
-
@failure
|
|
50
|
+
@failure ||= (stage == :close ? details.merge(code: :session_close_failed) : details).freeze
|
|
53
51
|
ensure
|
|
54
|
-
|
|
52
|
+
scope&.close
|
|
55
53
|
end
|
|
56
54
|
|
|
57
55
|
def contract_failure(code)
|
data/lib/ctx_runner/execution.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "ctx_parser/immutable"
|
|
4
4
|
require "ctx_driver/failure"
|
|
5
5
|
require_relative "fingerprint"
|
|
6
|
+
require_relative "session_scope"
|
|
6
7
|
|
|
7
8
|
module CtxRunner
|
|
8
9
|
# 只执行已确认的单项领域变更;日志、设备效果与配置验收分别记账。
|
|
@@ -45,24 +46,24 @@ module CtxRunner
|
|
|
45
46
|
|
|
46
47
|
# 保存意图先于连接;回调次数和完成状态不依赖连接器返回值。
|
|
47
48
|
def perform
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
finished = recorded = false
|
|
50
|
+
scope = SessionScope.new
|
|
50
51
|
save
|
|
51
52
|
yield lambda { |session|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
delivered = scope.deliver do
|
|
54
|
+
before = CtxParser::Immutable.copy(session.read_configuration)
|
|
55
|
+
unless Fingerprint.call(before) == @plan["expected_config_sha256"] && @change.eligible?(before)
|
|
56
|
+
raise ArgumentError, "Configuration changed or preconditions failed"
|
|
57
|
+
end
|
|
58
|
+
@commands.each_with_index { |command, index| execute(session, command, index) }
|
|
59
|
+
after = CtxParser::Immutable.copy(session.read_configuration)
|
|
60
|
+
raise IOError, "Configuration verification failed" unless @change.satisfied?(after, before: before)
|
|
61
|
+
@state["observed_config_sha256"] = Fingerprint.call(after)
|
|
58
62
|
end
|
|
59
|
-
|
|
60
|
-
after = CtxParser::Immutable.copy(session.read_configuration)
|
|
61
|
-
raise IOError, "Configuration verification failed" unless @change.satisfied?(after, before: before)
|
|
62
|
-
@state["observed_config_sha256"] = Fingerprint.call(after)
|
|
63
|
-
verified = true
|
|
63
|
+
raise IOError, "Invalid session delivery" unless delivered
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
scope.close
|
|
66
|
+
raise IOError, "Session did not verify the configuration" if scope.failure
|
|
66
67
|
@state["status"] = "configuration_verified"
|
|
67
68
|
save
|
|
68
69
|
finished = true
|
|
@@ -73,7 +74,7 @@ module CtxRunner
|
|
|
73
74
|
record_failure(type)
|
|
74
75
|
raise
|
|
75
76
|
ensure
|
|
76
|
-
|
|
77
|
+
scope&.close
|
|
77
78
|
# 非局部退出与线程取消也不能留下可重放的成功意图。
|
|
78
79
|
record_failure("aborted") unless finished || recorded
|
|
79
80
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CtxRunner
|
|
4
|
+
# 连接所有者只在当前线程、当前作用域内交付一次借用会话;不持有或关闭会话。
|
|
5
|
+
class SessionScope
|
|
6
|
+
def initialize
|
|
7
|
+
@owner, @lock = Thread.current, Mutex.new
|
|
8
|
+
@active, @delivered, @completed = true, false, false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# 先占用交付资格再调用领域代码;失败或重复交付不能因外部 rescue 变为成功。
|
|
12
|
+
def deliver
|
|
13
|
+
raise ArgumentError, "Session delivery requires an operation" unless block_given?
|
|
14
|
+
accepted = @lock.synchronize do
|
|
15
|
+
raise IOError, "Session provider scope has ended" unless @active
|
|
16
|
+
if @violation
|
|
17
|
+
false
|
|
18
|
+
elsif Thread.current != @owner
|
|
19
|
+
@violation ||= :session_out_of_scope
|
|
20
|
+
false
|
|
21
|
+
elsif @delivered
|
|
22
|
+
@violation ||= :session_reentered
|
|
23
|
+
false
|
|
24
|
+
else
|
|
25
|
+
@delivered = true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
return false unless accepted
|
|
29
|
+
|
|
30
|
+
yield
|
|
31
|
+
@lock.synchronize { @completed = true }
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def failure
|
|
36
|
+
@lock.synchronize do
|
|
37
|
+
@violation || (!@delivered ? :session_not_opened : !@completed ? :session_incomplete : nil)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def close
|
|
42
|
+
@lock.synchronize { @active = false }
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def inspect = "#<#{self.class.name}>"
|
|
47
|
+
alias to_s inspect
|
|
48
|
+
def pretty_print(printer) = printer.text(inspect)
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/ctx_runner/version.rb
CHANGED
data/lib/ctx_runner.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ctx_runner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gatework contributors
|
|
@@ -130,10 +130,12 @@ files:
|
|
|
130
130
|
- CHANGELOG.md
|
|
131
131
|
- LICENSE
|
|
132
132
|
- README.md
|
|
133
|
+
- docs/module-boundaries.md
|
|
133
134
|
- docs/superpowers/plans/2026-10-21-runner.md
|
|
134
135
|
- docs/superpowers/plans/2026-10-23-report-documents.md
|
|
135
136
|
- docs/superpowers/specs/2026-10-23-report-documents.md
|
|
136
137
|
- docs/verification-2026-10-22.md
|
|
138
|
+
- docs/verification-2026-10-25.md
|
|
137
139
|
- examples/execution.rb
|
|
138
140
|
- examples/report.rb
|
|
139
141
|
- lib/ctx_runner.rb
|
|
@@ -146,6 +148,7 @@ files:
|
|
|
146
148
|
- lib/ctx_runner/observation.rb
|
|
147
149
|
- lib/ctx_runner/query.rb
|
|
148
150
|
- lib/ctx_runner/report.rb
|
|
151
|
+
- lib/ctx_runner/session_scope.rb
|
|
149
152
|
- lib/ctx_runner/version.rb
|
|
150
153
|
licenses:
|
|
151
154
|
- MIT
|