task-state-guard README

The project's README from github.com/MaxHu-xuan/task-state-guard. As one markdown file: README.md.

TaskStateGuard(任务状态守护)

CI

中文 · English · 运行合成演示 · Technical reference

中文

服务重启后,running 任务和 pending 投递很容易继续留在界面里,却没人能确认它们 是否真的还在工作。TaskStateGuard 是面向 AI 智能体、后台 worker 和本地工作流的 嵌入式 SQLite 状态对账护栏。它把任务终态与投递终态分开,按明确的截止时间和 宽限期收敛遗留状态;你可以先看只含汇总数字的预览,再决定是否应用,doctor 健康检查同样不会列出任务明细。

它解决的是任务状态对账(task state reconciliation)和重启后卡住任务的状态收敛 (stuck task recovery)。它不是队列、执行器或计算续跑工具,也不承诺恰好一次;系统没有 观测到成功或投递回执时,TaskStateGuard 不会把未知结果猜成成功或已送达。

三个工具怎么选

你需要解决的问题 选择
重启后核对卡住任务、超时与待投递状态,不把未知结果猜成成功 TaskStateGuard(任务状态守护),当前项目
分享或迁移聊天导出前,本地检查疑似秘密、个人信息形态、格式、SQLite 与扫描盲区 ChatArchiveGuard(聊天归档守护)
确认最终 PPTX 及随附验收证据仍匹配结构检查后生成的 HMAC 签名收据 ArtifactProof(PPTX 交付物验真)

三个项目都可以独立使用;它们分别守护状态、聊天归档和 PPTX 交付物,不会互相读取数据。

它能带来什么

你遇到的问题 TaskStateGuard 给出的结果
服务重启后,一批任务一直显示 running 超过截止时间或活跃宽限期的任务转为 timed_out;仍然新鲜的任务保持不变
任务已经结束,但用户是否收到结果并不确定 投递状态继续保持 pending,直到真实回执或投递宽限期到期
内部子任务完成后不应单独向用户投递 终态内部任务在宽限期后转为 not_applicable,不会伪装成已送达
收敛遗留状态前需要知道会改动多少记录 reconcile --dry-run 返回同一时刻将发生的聚合计数,不修改任务、事件或数据库
运维需要判断工作流账本是否可信 doctor 检查数据库、schema、状态、时间戳和事件链,只返回聚合计数
Linux、macOS 和 Windows 需要共用一套状态语义 状态机一致;文件保护按 POSIX 权限或外部管理的 Windows DACL 分别处理

适合以下场景:

状态模型

任务状态:

queued ──> running
  │           │
  └───────────┴──> succeeded | failed | timed_out | cancelled

任务可以从 queued 或 running 进入终态。终态不可改写;重复写入相同终态是幂等的, 写入冲突终态会被拒绝。

投递状态:

pending ──> delivered | failed | not_applicable

投递状态只能在任务进入终态后关闭。外部投递任务只有收到真实传输回执后才能标记为 delivered;无需直接投递的内部任务只能标记为 not_applicable。

这两套状态机回答不同问题:

快速开始

1. 安装 TaskStateGuard

对于已经发布到 PyPI 的版本,普通用户建议在虚拟环境中安装 TaskStateGuard。

Linux 或 macOS:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install task-state-guard

Windows PowerShell:

py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install task-state-guard

如需审阅尚未发布的修改或参与开发,请先确认源码来源和目标提交,再在已核对的源码仓库 根目录创建独立虚拟环境,并将最后一条安装命令改为 python -m pip install . (Windows 使用 .\.venv\Scripts\python.exe -m pip install .)。

支持 CPython 3.11 至 3.14。运行时代码只使用 Python 标准库,不包含网络请求或遥测。

2. 运行完全合成的演示

演示脚本随源码仓库提供,不包含在 wheel 中。请从仓库根目录运行;它只使用固定的公开 样例状态,在系统临时目录创建 SQLite,调用真实 CLI 完成 preview、apply、幂等复查和 doctor,结束后自动删除临时数据库。它不读取本机任务数据, 也不包含提示词、消息、任务正文或真实标识。

Linux 或 macOS:

PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 examples/restart_reconciliation_demo.py

Windows PowerShell:

$env:PYTHONDONTWRITEBYTECODE = "1"
$env:PYTHONPATH = "src"
py -3 .\examples\restart_reconciliation_demo.py --allow-external-acl

真实演示中的前三个聚合结果如下;<temporary-demo> 是刻意使用的、不包含本机信息的 路径占位符:

[preview] output: {"ok":true,"reconcile":{"active_examined":2,"applied":false,"deliveries_failed":1,"deliveries_not_applicable":1,"dry_run":true,"fresh_active_retained":1,"pending_delivery_examined":3,"pending_delivery_retained":1,"tasks_timed_out":1}}
[apply] output: {"ok":true,"reconcile":{"active_examined":2,"applied":true,"deliveries_failed":1,"deliveries_not_applicable":1,"dry_run":false,"fresh_active_retained":1,"pending_delivery_examined":3,"pending_delivery_retained":1,"tasks_timed_out":1}}
[idempotent-recheck] output: {"ok":true,"reconcile":{"active_examined":1,"applied":true,"deliveries_failed":0,"deliveries_not_applicable":0,"dry_run":false,"fresh_active_retained":1,"pending_delivery_examined":1,"pending_delivery_retained":1,"tasks_timed_out":0}}

第三次没有再次改写已经闭合的记录;仍保留的 queued 和刚刚进入 timed_out 的投递解释了 两个 retained 计数。完整命令与只含汇总数字的 doctor 输出由脚本直接打印,并在测试中 连续运行两次验证一致性。

3. 只记录真实发生的状态变化

from task_state_guard import Ledger

ledger = Ledger("./private-state/tasks.sqlite")
task = ledger.create_task(timeout_seconds=900)
ledger.start_task(task.id)

# 外部 worker 确认工作成功后再写入任务终态。
ledger.close_task(task.id, "succeeded", code="worker_completed")

# 传输层收到真实回执后再写入投递终态。
ledger.set_delivery(
    task.id,
    "delivered",
    code="transport_acknowledged",
)

在 Windows 上,数据库父目录必须提前存在,并由管理员或部署系统设置为仅服务账户可访问的 私有 DACL。只有确认该边界已经建立后,才传入 allow_external_acl=True。

4. 先预览,再执行重启收敛

task-state-guard --db ./private-state/tasks.sqlite reconcile \
  --active-grace-seconds 600 \
  --delivery-grace-seconds 600 \
  --dry-run
task-state-guard --db ./private-state/tasks.sqlite reconcile \
  --active-grace-seconds 600 \
  --delivery-grace-seconds 600
task-state-guard --db ./private-state/tasks.sqlite doctor

--dry-run 使用与实际执行相同的判断规则,但不会修改任务、事件或数据库。时间会继续前进, 并发 worker 也可能更新状态,因此预览只代表预览时刻;执行前应核对返回的 dry_run 和 applied 字段。

CLI 的 dry-run 会以只读模式打开一个已经存在、已经采用 WAL 且权限边界合格的账本;它 不会创建数据库、收紧文件权限或迁移 schema。安全的 schema v1 可以直接预览并保持为 v1;普通执行仍按原有默认行为迁移到 v2。嵌入 Python 时,如果连构造阶段也必须只读,请 使用 Ledger(path, read_only=True),并只调用读取操作或 dry_run=True 的收敛。

数据库已干净关闭且没有 WAL/SHM 时,TaskStateGuard 会对不超过 64 MiB 的主库做两次 身份、时间和 SHA-256 一致性读取,再把私有副本载入内存;不会用 SQLite 的 immutable 模式直接读取可能并发变化的源文件,也不会创建临时副本。读取期间出现 writer 或 checkpoint、内存反序列化不可用、或超过上限时都会安全失败。已有完整 WAL/SHM 时仍使用 SQLite 的正常只读锁语义。

Windows CLI 需要把 DACL 确认参数放在子命令之前:

.\.venv\Scripts\task-state-guard.exe `
  --db .\private-state\tasks.sqlite `
  --allow-external-acl `
  reconcile --active-grace-seconds 600 --delivery-grace-seconds 600 --dry-run

--allow-external-acl 只确认调用方已配置私有 DACL,不会创建、检查或认证 DACL。

Linux、macOS 与 Windows 命令差异

平台 源码与虚拟环境命令 文件保护与 CLI 注意事项
Linux 通常使用 python3、. .venv/bin/activate、PYTHONPATH=src 和 / 路径 项目检查并收紧 POSIX 文件模式;数据库必须在本地文件系统
macOS 与 Linux 使用相同的 shell 写法和 / 路径 同样执行 POSIX 模式与链接检查;数据库必须在本地文件系统
Windows PowerShell 使用 py -3、$env:PYTHONPATH = "src" 和 \ 路径 先由外部配置私有 DACL,并把 --allow-external-acl 放在子命令之前

三个平台的任务与投递状态语义相同;差异只在命令写法和本地文件保护边界。在 Windows 上,合成演示只有收到显式参数后才会加入 DACL 确认,但仍不会替你配置或验证 DACL。 运行前请先确认临时目录的 DACL 边界,并确认上述 python3 或 py -3 实际选择的是 受支持的 CPython 3.11 至 3.14。

工作流可观测性

reconcile 返回本次将收敛或已收敛的聚合计数,不返回任务 ID。输出中的 dry_run=true, applied=false 表示只读预览;默认执行返回 dry_run=false, applied=true。doctor 检查:

doctor 健康时退出码为 0。只要当前数据库中真实存在结构、状态、时间戳或事件链 不一致,它就返回 1;已闭合且一致的历史终态不会仅因仍被保留而失败。它也不会因为 报告能正常生成就把不健康账本当作成功。普通状态命令会返回操作所需的 UUID、状态和 时间戳,因此这些输出仍应像数据库一样受到保护。

数据库没有提示词、消息正文、任务正文、路径或自由文本异常字段。可选的 SHA-256 payload fingerprint 是可关联的假名化元数据,不是匿名数据;低熵内容可能被离线猜测时, 应省略它或在 TaskStateGuard 之外使用带密钥的指纹方案。

真实边界

常见问题

TaskStateGuard 能续跑中断的智能体任务吗?

不能。它保存并收敛任务生命周期元数据,不保存计算检查点,也不恢复计算。超过截止时间 或活跃宽限期的 running 任务会转为 timed_out;是否新建重试任务由外部运行时决定。

它能保证恰好一次执行或恰好一次投递吗?

不能。相同终态的重复写入是幂等的,冲突终态会被拒绝,但 TaskStateGuard 无法观察外部 副作用。只有传输系统记录了真实回执后,调用方才能把投递状态更新为 delivered。

它是 Python 任务队列、调度器或工作流引擎吗?

不是。它只保存本地 SQLite 状态账本,不负责入队、调度、执行、取消、重试或发送任务。 它可以放在 agent runtime、worker pool 或工作流系统旁边,但当前仓库不提供框架专用 适配器。

为什么任务状态和投递状态要分开?

任务可能已经成功,但结果仍在等待投递;内部子任务也可能不需要直接面向用户投递。 拆分状态机可以避免把任务完成误判为结果已经送达。

预览结果是否保证与稍后执行完全相同?

只有在使用同一时刻且期间没有并发状态变化时才相同。--dry-run 不写数据库,也不锁定 未来执行;它用于审阅当前判断,不是对后续执行的预约。

它会保存提示词、消息或模型输出吗?

不会,这些值没有受支持的数据库字段或 CLI 参数。可选的 SHA-256 fingerprint 仍可能被 关联或猜测,因此只应在理解其隐私边界时使用。

Windows、macOS 和 Linux 分别有什么要求?

所有平台都必须使用支持 SQLite 锁的本地文件系统。Linux 和 macOS 使用所有者/模式检查 并把数据库及 sidecar 收紧为 0600。Windows 要求预先创建带私有 DACL 的服务账户目录, 再显式传入 allow_external_acl=True;项目不能替你验证 DACL。

English

After a service restarts, running tasks and pending deliveries can remain visible even when no one can confirm that they are still active. TaskStateGuard is an embedded SQLite reconciliation guardrail for AI agents, background workers, and local workflow runtimes. It keeps task terminal state separate from delivery terminal state and reconciles stale state using explicit deadlines and grace periods. You can preview aggregate changes before applying them, then use a counts-only doctor to check the ledger.

It provides task-state reconciliation and stuck-task recovery for metadata. It is not a queue, executor, or computation-resumption tool and makes no exactly-once guarantee. When the surrounding system has not observed success or a delivery acknowledgement, TaskStateGuard does not guess that the work succeeded or was delivered.

What it gives you

Problem Result
A service restarts while tasks remain running Tasks past their deadline or active grace become timed_out; fresh tasks remain unchanged
Work is terminal but user-facing delivery is uncertain The delivery state stays pending until a real acknowledgement or the delivery grace expires
An internal child task should not create its own delivery obligation The terminal internal task becomes not_applicable after grace instead of pretending it was delivered
You need to see the impact before applying reconciliation reconcile --dry-run returns the aggregate changes for that moment without updating tasks, events, or the database
Operations needs to decide whether the ledger is trustworthy doctor checks the database, schema, state, timestamps, and event chains and emits aggregate counts
Linux, macOS, and Windows need one state contract The state model is portable; storage protection uses POSIX modes or a caller-managed Windows DACL

TaskStateGuard fits runtimes that need:

Choose among the three tools

Problem to solve Choose
After a restart, reconcile stuck tasks, timeouts, and pending delivery without guessing success TaskStateGuard, this project
Before sharing or migrating a chat export, locally audit potential secrets, personal-data patterns, format or SQLite issues, and scan gaps ChatArchiveGuard
Verify that a final PPTX and its supplied QA evidence still match the HMAC-signed receipt created after structural checks ArtifactProof

Each project works independently. They protect state, chat archives, and PPTX artifacts respectively, without reading one another's data.

State model

Task states:

queued ──> running
  │           │
  └───────────┴──> succeeded | failed | timed_out | cancelled

A task can close from queued or running. Terminal states are immutable. Repeating the same close is idempotent; a conflicting close is rejected.

Delivery states:

pending ──> delivered | failed | not_applicable

Delivery can close only after the task is terminal. A delivery-required task becomes delivered only after a real transport acknowledgement. An internal task that has no direct delivery obligation can become only not_applicable.

The two state machines answer different questions:

Quick start

1. Install TaskStateGuard

After a release is published to PyPI, most users should install TaskStateGuard in a virtual environment.

Linux or macOS:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install task-state-guard

Windows PowerShell:

py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install task-state-guard

To review unreleased changes or contribute, first verify the source and target commit. Then create an isolated environment from that checkout's repository root and replace the final command with python -m pip install . (on Windows, use .\.venv\Scripts\python.exe -m pip install .).

TaskStateGuard supports CPython 3.11 through 3.14. Runtime code uses only the Python standard library and has no network or telemetry path.

2. Run the fully synthetic demonstration

The demo script is provided in the source repository and is not included in the wheel. Run it from the repository root. It creates a SQLite database under the system temporary directory from fixed public sample states, invokes the real CLI for preview, apply, an idempotent recheck, and doctor, then removes the database. It does not read local task data or contain prompts, messages, task bodies, or real identifiers.

Linux or macOS:

PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 examples/restart_reconciliation_demo.py

Windows PowerShell:

$env:PYTHONDONTWRITEBYTECODE = "1"
$env:PYTHONPATH = "src"
py -3 .\examples\restart_reconciliation_demo.py --allow-external-acl

The first three aggregate resul

task-state-guard (MaxHu-xuan/task-state-guard)

Searching Database…

这是什么?TaskStateGuard 是一个内嵌 SQLite 的对账防护工具,在 AI 智能体、worker 或本地工作流重启后修复卡住的任务和交付状态,让你再也不用猜测工作是否真的成功、是否已交付。
这是任务队列,还是只是一个状态对账层?它既不是队列也不是执行器;它是一个对账库/CLI,只在本地 SQLite 账本中跟踪并关闭任务和交付状态,不会运行、重试或恢复你的实际工作。
怎么安装和运行它?在虚拟环境中从 PyPI 安装它(Linux/macOS 上用 pip,Windows 上用对应的 PowerShell 命令),然后针对你的 SQLite 账本调用 CLI 的 reconcile 和 doctor 命令。
除了 Python 之外,运行它还需要别的东西吗?不需要额外的服务或账号:它只需要 CPython 3.11 到 3.14,运行时代码仅使用标准库,没有任何网络或遥测调用。
--dry-run 能保证实际运行和预览结果一致吗?只有在这期间没有其他东西改动数据库时才能保证;dry-run 只是读取某一时刻的账本,不会锁定或保留该结果,因此在真正应用之前,并发的 worker 或时间的流逝都可能改变结果。
在 Windows 上运行它,与在 Linux 或 macOS 上有什么不同?任务/交付状态机在各平台上完全一致;区别在于文件保护。Linux 和 macOS 会自动进行 POSIX 权限检查,而在 Windows 上你必须自行预先创建一个带有私有 DACL 的目录,并通过 allowexternalacl=True 明确确认。
账本会存储我的提示词或任务内容吗?不会。数据库只保存 UUID、状态、时间戳等生命周期元数据,绝不保存提示词文本、消息正文或自由文本字段;一个可选的 SHA-256 指纹是与任务内容最接近的东西,而且是假名化的,并非匿名。
为什么任务状态和交付状态要分开跟踪?一个任务可能已成功完成,但其结果仍在等待交付;或者内部子任务可能根本不需要直接交付。把两个状态机分开,可以避免把「任务完成」误当成「结果已送达用户」。
doctor 命令具体检查什么?它检查 SQLite 完整性、外键和模式(schema)、任务状态与交付状态之间的一致性、父子顺序、UUID 和时间戳,以及每个任务事件链的完整性,只返回汇总的通过/失败计数,绝不返回任务 ID。
它能恢复崩溃的 AI 智能体任务吗?不能,它只保存和对账生命周期元数据,不保存计算检查点。超时的运行中任务只会被标记为 timedout;是否重试实际工作完全由你的运行时决定。
与它一起提到的配套项目有哪些?ChatArchiveGuard 在分享聊天导出文件之前,在本地审计其中是否含有机密和个人身份信息(PII);ArtifactProof 验证最终 PPTX 是否仍与其经 HMAC 签名的 QA 回执相符;这三个工具相互独立,从不共享数据。
Creator
MaxHu-xuan
Size
0.2 MB
Stars
895
Age
1mo
Commits · 90 Days