@ai-slot/operations 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -1,41 +1,47 @@
1
1
  # @ai-slot/operations
2
2
 
3
- 实验性服务端公开包(0.x API 和持久格式尚不承诺跨版本兼容),提供版本状态校验与本地单写者文件库。需要 Node.js 22 或更新版本。`openFileStore(directory)` 在目录中维护 `state.json` 和独占的 `writer.lock`,事务把草稿、审批、发布记录、指针及幂等回执作为一个快照提交。当前边界为 64 MiB 和 1000 条发布记录;只支持本地具备原子 rename 语义的文件系统,不支持 NFS、云同步目录或多个服务实例。
3
+ **English** | [简体中文](https://github.com/iannil/ai-slot-component/blob/master/packages/operations/README.zh-CN.md)
4
4
 
5
- 事务按调用顺序执行,读取也进入同一队列。提交先校验完整引用关系,再写同目录临时文件、同步文件、rename 到 `state.json`,最后同步目录。`beforeRename` 失败不会改变旧快照;rename 后失败返回 `commit_unknown`,该句柄停止后续写入。调用方应通过幂等回执核对提交结果,不能把该错误视为明确失败并盲目重试。
5
+ An experimental public server-side package that provides version-state validation and a local single-writer file store. The 0.x API and persisted format do not yet guarantee compatibility across versions. Requires Node.js 22 or later. `openFileStore(directory)` maintains `state.json` and an exclusive `writer.lock` in the directory. Transactions commit drafts, approvals, publication records, pointers, and idempotency receipts as a single snapshot. The current limits are 64 MiB and 1,000 publication records. Only local filesystems with atomic rename semantics are supported; NFS, cloud-synced directories, and multiple service instances are not supported.
6
6
 
7
- ## 人工恢复
7
+ ## Installation
8
8
 
9
- 1. 停止唯一服务,备份整个存储目录(包括 `state.json`、临时文件及 `writer.lock`)。
10
- 2. 核对 `writer.lock` 中的 PID 与随机 nonce,并确认原服务进程确已退出;不要按锁文件年龄自动抢占。
11
- 3. 管理员人工移走残留的 `writer.lock`,重新调用 `openFileStore`。启动会在解析前检查快照大小,并用 `assertState` 校验结构、hash 和所有引用;损坏快照会拒绝启动,不会重置为空库。
12
- 4. 用幂等键查询对应回执确认发布是否已经落盘,再决定后续业务动作。
9
+ ```bash
10
+ npm install @ai-slot/operations
11
+ ```
13
12
 
14
- `fault` 注入选项只供故障测试使用,不是业务配置。
13
+ Import `openFileStore` and `createOperations`; the workflow is described below. A complete runnable reference service is available at [`examples/managed-slot`](https://github.com/iannil/ai-slot-component/tree/master/examples/managed-slot).
15
14
 
16
- ## 草稿、发布与公开投递
15
+ ## Transactions and manual recovery
17
16
 
18
- `createOperations(store, env)` 是治理和交付的统一入口。`listSlots(actor)` 只列出有 `read` 授权且存在策略的槽位;`readSlot(actor, slotId)` 只返回该槽位的发布指针与草稿。`previewDraft` 和 `getStatus` 同样需要本槽位的 `read` 授权。草稿建立时校验树、来源与线上基线,将内容写成以 SHA-256 寻址的不可变 artifact;预览的 `previous` 固定到草稿创建时的版本。批准再次核对哈希、基线、来源及组件契约,且有效期最多 15 分钟并不得超过来源期限。
17
+ Transactions execute in call order, and reads enter the same queue. A commit first validates all references, then writes a temporary file in the same directory, syncs the file, renames it to `state.json`, and finally syncs the directory. A failure at `beforeRename` leaves the previous snapshot unchanged. A failure after rename returns `commit_unknown`, and the handle stops accepting further writes. Callers should check the idempotency receipt to determine the commit outcome, rather than treating this error as a definitive failure and retrying blindly.
19
18
 
20
- 一次完整的操作顺序如下,其中发布和回滚都需要批准人重新审核内容哈希与有效期:
19
+ 1. Stop the sole service and back up the entire storage directory, including `state.json`, temporary files, and `writer.lock`.
20
+ 2. Check the PID and random nonce in `writer.lock` and confirm that the original service process has exited. Do not automatically take over a lock based on its age.
21
+ 3. Have an administrator manually move the leftover `writer.lock` out of the directory, then call `openFileStore` again. Startup checks the snapshot size before parsing and uses `assertState` to validate the structure, hashes, and all references. A corrupt snapshot prevents startup; it is never reset to an empty store.
22
+ 4. Look up the corresponding receipt using the idempotency key to confirm whether the publication was persisted before deciding on the next business action.
21
23
 
22
- 1. `createDraft(actor, { slotId, tree, baseRevision, sourceVersion })` 建立草稿。
23
- 2. `previewDraft(actor, draft.id)` 查看草稿、artifact 哈希和基线差异。
24
- 3. `approveDraft(actor, { draftId, artifactHash, expiresAt })` 批准该草稿。
25
- 4. `publishDraft(actor, { draftId, artifactHash, expectedRevision, idempotencyKey })` 原子发布,并取得新 revision 回执。
26
- 5. `deliver(slotId)` 公开交付当前版本;它不接受管理员身份,也不会返回草稿、批准人或来源凭据。
27
- 6. 需要回滚时,`prepareRollback(actor, { slotId, targetRevision, expectedRevision })` 将历史 artifact 建成新的回滚草稿。
28
- 7. 再次 `previewDraft` 和 `approveDraft`,审核这份回滚草稿。
29
- 8. `rollbackSlot(actor, { draftId, artifactHash, expectedRevision, idempotencyKey })` 发布新的 revision,而非移动指针回旧编号。
24
+ The `fault` injection option is for fault testing only, not application configuration.
30
25
 
31
- `deliver` 返回版本 1 的 JSON:`{ version, slot, tree, meta: { revision, artifactHash, sourceVersion, expiresAt } }`。`expiresAt` 是 artifact 中的 Unix 毫秒时间。所有响应均使用 `Cache-Control: no-store`。已知槽位没有可读发布内容,或当前来源、组件契约、有效期校验失败时,返回 `503 { "error": "ai_unavailable" }`,由页面保留原始内容;未知槽位返回 404。来源读取抛出的异常会统一转成 `source_unavailable`,来源数据本身不合法仍是 `source_invalid`,公开响应不会暴露这些内部细节。
26
+ ## Drafts, publication, and public delivery
32
27
 
33
- `getStatus(actor, slotId)` 返回 `{ desiredRevision, readableRevision, browserObservation }`。`desiredRevision` 来自发布指针,即使当前来源失效也保留;`readableRevision` 只有通过同一实时可读性检查才有值;`browserObservation` 固定为 `null`,因为服务端没有浏览器渲染观测。每次交付都会重读外部来源,外部来源与文件事务不能跨系统原子锁定,因此不承诺来源在校验后永不变化。此包是单站点参考实现,不负责任意事实语义验证或金融促销自动审批。
28
+ `createOperations(store, env)` is the unified entry point for governance and delivery. `listSlots(actor)` lists only slots with a policy for which the actor has `read` permission. `readSlot(actor, slotId)` returns only that slot's publication pointer and drafts. `previewDraft` and `getStatus` also require `read` permission for the slot. Draft creation validates the tree, source, and live baseline, then stores the content as an immutable artifact addressed by SHA-256. The preview's `previous` is pinned to the version at draft creation. Approval rechecks the hash, baseline, source, and component contract. Approval validity is limited to 15 minutes and must not extend beyond the source's expiry.
34
29
 
35
- ## 安装与验收边界
30
+ A complete workflow follows. Both publication and rollback require the approver to review the content hash and expiry again:
36
31
 
37
- ```bash
38
- npm install @ai-slot/operations
39
- ```
32
+ 1. `createDraft(actor, { slotId, tree, baseRevision, sourceVersion })` creates a draft.
33
+ 2. `previewDraft(actor, draft.id)` shows the draft, artifact hash, and differences from the baseline.
34
+ 3. `approveDraft(actor, { draftId, artifactHash, expiresAt })` approves the draft.
35
+ 4. `publishDraft(actor, { draftId, artifactHash, expectedRevision, idempotencyKey })` publishes atomically and returns a receipt for the new revision.
36
+ 5. `deliver(slotId)` publicly delivers the current version. It accepts no administrator identity and returns no drafts, approver information, or source credentials.
37
+ 6. To roll back, `prepareRollback(actor, { slotId, targetRevision, expectedRevision })` creates a new rollback draft from a historical artifact.
38
+ 7. Run `previewDraft` and `approveDraft` again to review the rollback draft.
39
+ 8. `rollbackSlot(actor, { draftId, artifactHash, expectedRevision, idempotencyKey })` publishes a new revision rather than moving the pointer back to an old revision number.
40
+
41
+ `deliver` returns version 1 JSON: `{ version, slot, tree, meta: { revision, artifactHash, sourceVersion, expiresAt } }`. `expiresAt` is the Unix timestamp in milliseconds stored in the artifact. All responses use `Cache-Control: no-store`. A known slot with no readable published content, or whose current source, component contract, or expiry fails validation, returns `503 { "error": "ai_unavailable" }`, allowing the page to retain its original content. Unknown slots return 404. Exceptions thrown while reading the source are normalized to `source_unavailable`; invalid source data still produces `source_invalid`. Public responses do not expose these internal details.
42
+
43
+ `getStatus(actor, slotId)` returns `{ desiredRevision, readableRevision, browserObservation }`. `desiredRevision` comes from the publication pointer and is retained even when the current source becomes invalid. `readableRevision` is populated only if the same live readability checks pass. `browserObservation` is always `null` because the server has no observation of browser rendering. Every delivery rereads the external source. An external source and a file transaction cannot be locked atomically across systems, so this package does not guarantee that the source remains unchanged after validation. This is a single-site reference implementation; it does not provide arbitrary factual or semantic verification, or automatic approval of financial promotions.
44
+
45
+ ## Validation status and scope
40
46
 
41
- 可导入 `openFileStore`、`createOperations`,调用流程见上文。完整可运行参考服务位于仓库 `examples/managed-slot`;此包不自动启动 HTTP 服务,也不提供多实例或租户隔离。协议和脚本验收已通过,真实运营人员及客户试点尚未完成。升级前备份状态;不承诺自动迁移历史试验快照。
47
+ This package does not start an HTTP service automatically or provide support for multiple instances or tenant isolation. Protocol and scripted validation have passed; validation with real operators and customer pilots has not yet been completed. Back up state before upgrading. Automatic migration of historical experimental snapshots is not guaranteed.
@@ -0,0 +1,43 @@
1
+ # @ai-slot/operations
2
+
3
+ [English](https://github.com/iannil/ai-slot-component/blob/master/packages/operations/README.md) | **简体中文**
4
+
5
+ 实验性服务端公开包(0.x API 和持久格式尚不承诺跨版本兼容),提供版本状态校验与本地单写者文件库。需要 Node.js 22 或更新版本。`openFileStore(directory)` 在目录中维护 `state.json` 和独占的 `writer.lock`,事务把草稿、审批、发布记录、指针及幂等回执作为一个快照提交。当前边界为 64 MiB 和 1000 条发布记录;只支持本地具备原子 rename 语义的文件系统,不支持 NFS、云同步目录或多个服务实例。
6
+
7
+ 事务按调用顺序执行,读取也进入同一队列。提交先校验完整引用关系,再写同目录临时文件、同步文件、rename 到 `state.json`,最后同步目录。`beforeRename` 失败不会改变旧快照;rename 后失败返回 `commit_unknown`,该句柄停止后续写入。调用方应通过幂等回执核对提交结果,不能把该错误视为明确失败并盲目重试。
8
+
9
+ ## 人工恢复
10
+
11
+ 1. 停止唯一服务,备份整个存储目录(包括 `state.json`、临时文件及 `writer.lock`)。
12
+ 2. 核对 `writer.lock` 中的 PID 与随机 nonce,并确认原服务进程确已退出;不要按锁文件年龄自动抢占。
13
+ 3. 管理员人工移走残留的 `writer.lock`,重新调用 `openFileStore`。启动会在解析前检查快照大小,并用 `assertState` 校验结构、hash 和所有引用;损坏快照会拒绝启动,不会重置为空库。
14
+ 4. 用幂等键查询对应回执确认发布是否已经落盘,再决定后续业务动作。
15
+
16
+ `fault` 注入选项只供故障测试使用,不是业务配置。
17
+
18
+ ## 草稿、发布与公开投递
19
+
20
+ `createOperations(store, env)` 是治理和交付的统一入口。`listSlots(actor)` 只列出有 `read` 授权且存在策略的槽位;`readSlot(actor, slotId)` 只返回该槽位的发布指针与草稿。`previewDraft` 和 `getStatus` 同样需要本槽位的 `read` 授权。草稿建立时校验树、来源与线上基线,将内容写成以 SHA-256 寻址的不可变 artifact;预览的 `previous` 固定到草稿创建时的版本。批准再次核对哈希、基线、来源及组件契约,且有效期最多 15 分钟并不得超过来源期限。
21
+
22
+ 一次完整的操作顺序如下,其中发布和回滚都需要批准人重新审核内容哈希与有效期:
23
+
24
+ 1. `createDraft(actor, { slotId, tree, baseRevision, sourceVersion })` 建立草稿。
25
+ 2. `previewDraft(actor, draft.id)` 查看草稿、artifact 哈希和基线差异。
26
+ 3. `approveDraft(actor, { draftId, artifactHash, expiresAt })` 批准该草稿。
27
+ 4. `publishDraft(actor, { draftId, artifactHash, expectedRevision, idempotencyKey })` 原子发布,并取得新 revision 回执。
28
+ 5. `deliver(slotId)` 公开交付当前版本;它不接受管理员身份,也不会返回草稿、批准人或来源凭据。
29
+ 6. 需要回滚时,`prepareRollback(actor, { slotId, targetRevision, expectedRevision })` 将历史 artifact 建成新的回滚草稿。
30
+ 7. 再次 `previewDraft` 和 `approveDraft`,审核这份回滚草稿。
31
+ 8. `rollbackSlot(actor, { draftId, artifactHash, expectedRevision, idempotencyKey })` 发布新的 revision,而非移动指针回旧编号。
32
+
33
+ `deliver` 返回版本 1 的 JSON:`{ version, slot, tree, meta: { revision, artifactHash, sourceVersion, expiresAt } }`。`expiresAt` 是 artifact 中的 Unix 毫秒时间。所有响应均使用 `Cache-Control: no-store`。已知槽位没有可读发布内容,或当前来源、组件契约、有效期校验失败时,返回 `503 { "error": "ai_unavailable" }`,由页面保留原始内容;未知槽位返回 404。来源读取抛出的异常会统一转成 `source_unavailable`,来源数据本身不合法仍是 `source_invalid`,公开响应不会暴露这些内部细节。
34
+
35
+ `getStatus(actor, slotId)` 返回 `{ desiredRevision, readableRevision, browserObservation }`。`desiredRevision` 来自发布指针,即使当前来源失效也保留;`readableRevision` 只有通过同一实时可读性检查才有值;`browserObservation` 固定为 `null`,因为服务端没有浏览器渲染观测。每次交付都会重读外部来源,外部来源与文件事务不能跨系统原子锁定,因此不承诺来源在校验后永不变化。此包是单站点参考实现,不负责任意事实语义验证或金融促销自动审批。
36
+
37
+ ## 安装与验收边界
38
+
39
+ ```bash
40
+ npm install @ai-slot/operations
41
+ ```
42
+
43
+ 可导入 `openFileStore`、`createOperations`,调用流程见上文。完整可运行参考服务位于仓库 `examples/managed-slot`;此包不自动启动 HTTP 服务,也不提供多实例或租户隔离。协议和脚本验收已通过,真实运营人员及客户试点尚未完成。升级前备份状态;不承诺自动迁移历史试验快照。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-slot/operations",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -12,7 +12,7 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@ai-slot/registry": "0.1.1"
15
+ "@ai-slot/registry": "0.1.2"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "^22.0.0",