inkcheck
inkcheck
面向 ink 故事的机械式 QA。 包括编译检查、有界系统化分支探索、运行时错误复现路径和死内容检测——作为供作者和团队使用的独立 CLI,并可选集成 CI 与 MCP。
代理请从这里开始 → SKILL.md —— 何时调用此工具、实操示例、MUST/MUST NOT 规定。家族契约:FAMILY.md。
inkcheck 是一个 QA 工具,不是写作工具。它不会生成、重写或把散文的任何一个字发送出去。它的存在是为了让 你 写的故事可以被机械地检查:用 ink 的官方编译器编译它,在明确限制内探索选择路径,并在玩家发现故障之前复现它们。
它使用 AI 吗?
不使用。inkcheck 本身不使用 AI、机器学习、LLM 或生成式模型来测试故事。它不会基于你的源代码进行训练、推断散文修改、重写故事文本,也不会将故事内容发送给 AI 服务。
它的设计目标是让人类、CI 系统和可选的 AI 编码代理都能驱动同样的机械式 QA 检查。实际检查由确定性代码完成:官方 ink 编译器、ink 运行时、有界分支探索和结构化报告。
Related MCP server: RenForge MCP
两分钟上手
需要 Node.js 18 或更高版本:
npx -y inkcheck path/to/main.ink想先看看失败路径报告再测试自己的故事?运行 两分钟合成演示。
产品承诺
Inkcheck 是对 ink 故事进行有界机械式 QA 的工具。它不能证明大型故事中的每条路径都可用。它会在明确限制内确定性地探索可达的故事状态,报告所发现问题的精确复现路径,并说明覆盖在哪些方面——以及为什么——是不完整的,从而让作者将其用作廉价、可重复的回归保险。
Inkcheck 不会证明大型互动故事没有 bug。组合爆炸是真实存在的:循环、变量、随机性和宿主游戏代码可能创造出比任何工具都能穷尽访问的更多可能状态。
承诺更窄、也更有用:让机械式故事 QA 廉价、可重复且可操作。Inkcheck 会在明确限制内遍历真实可达的选择状态,告诉你运行何时是部分的,并把失败转化为修复后可以再次运行的复现路径。如果它今天发现了一个损坏的路径,明天同一个配置好的检查应该还能再查找那条路径。
这是一个开源 QA 项目,因为这条边界很重要。如果某份报告夸大了结论、遗漏了明显的模式、需要更好的遍历策略,或者在你能够安全分享的故事形态上失败,请带上 fixture 或 issue。路线图的目标是让部分覆盖更透明、更有价值,而不是装作部分覆盖就是证明。
产品方向与自评
Inkcheck 的未来价值计划来自一种可复现的混合方法:广泛的种子化探测、系统的局部检查、有界多样性搜索,以及针对门(gates)、循环、断言和 storylet 资格的 Ink 感知专家。专家必须保持有界,并通过组合新增证据来争取更多工作,因为它们也可能成为预算陷阱。
同样的约定也适用于硬件。本地 CLI 和一次性 MCP 组合检查默认采用确定性的 1,024 状态实时试点,该试点让小型、深度受限、作者前沿饱和的任务保持串行,并且仅对开放且持续的前沿激活有界工作进程。每个试点状态都计入原始全局上限;不会为做出决定而重新启动搜索。配对评估保留了精确证据,并将一次 5M 状态、深度 100 的 The Intercept 运行提升了 25.6%,而受约束和托管任务仍保留显式的串行上限。参见并发评估。
维度 | 当前 | 10/10 方向 |
可操作、可重复的 QA | 8/10 | 在编辑/CI/代理活动中保持稳定发现和精确重放 |
诚实的有界证据 | 8/10 | 事实、估计、限制、不确定性和证明始终分离 |
对未知形态的稳健探索 | 6/10 | 在不进行遍历或 fixture 过拟合的情况下提供广泛的跨家族价值 |
结构化专家优势 | 4/10 | 由有界专家探针测试门、循环、边界和枢纽 |
每挂钟时间的随时价值 | 7/10 | 存在早期结果窗口和截止时间;首窗口大小调整仍是固定的 |
作者与代理意图 | 8/10 | 安全不变量、目标、资源姿态和紧凑解释 |
已验证的泛化能力 | 4/10 | 预声明的多项目语料库,包括真正的中/大型作品 |
这些是独立分数,不是平均值。高信任分数无法弥补丢失的运行时错误。详细的产品与工程真相计分卡定义了每个 10/10 目标、当前证据、工程约束,以及每个史诗或发布时使用的重新评估协议。首份完整的策略 v2 晋升评估将动态分配保持为实验性,而不是把混合证据变成发布声明。
Inkcheck 0.6 范围
Inkcheck 0.6 交付随时可用(anytime)的 QA 基础,而不声称拥有普遍更优的动态搜索策略。已确立的有界组合仍然是搜索默认。当实时试点显示出足够的持续工作时,感知工作负载的并发可能会将结果提前;持久活动可以返回、恢复并检查源绑定(source-bound)的结果窗口;人类和代理可以选择命名的时间/资源姿态;并且每个自动决策都是可归因的。长尾扩展、轮换和停止仍只是影子功能,因为三家族晋升门未能在作者面向的价值上足够广泛地建立使其上线。
这是一个已完成的发布契约,而不是声称更大的研究问题已解决。动态首窗口大小调整、紧凑的大型检查点、供应商归属成本、更广泛的代理评估和有界专家探索器仍然是单独跟踪的路线图工作。未来的发布只有在经过检查的证据通过同样关键保留、重放、资源和诚实门之后,才可能替换固定组合。
Inkcheck 0.7: Rules That Matter
Inkcheck 0.7 使作者声明的不变量在托管检查器以及本地配置、CI 和 MCP 中成为一流公民。作者可以在 Web 流程中添加一条可选数值规则,例如 gold >= 0;该规则会在运行前以通俗语言和生成的类型化配置显示,在普通有界 QA 期间检查,并在违反时以精确重放见证报告。Web 流程会检测声明的 Ink 变量以辅助选择,但服务器仍具有权威性:未知变量、无效类型和不支持的语法会在探索前失败;临时规则配置会随上传一起删除。代理可以起草类型化规则提案,但不能静默授权它们。版本 0.7.2 还添加了私有 QA 证据固定:经批准的运行时、断言或目标见证可以在编辑后无需再次搜索即可重新检查,而新的有界运行对于广泛验证仍是必要的。
一个独立的断言导向专家仍然是可选和实验性的。在通过其预先注册的证据门之前,它不会获得默认预算、改变计分卡或声称更好的覆盖率。Rules That Matter 契约定义了两条边界。
代理活动策略
MCP 代理可以使用高级 quick、balanced、deep、overnight 或 campaign 模式启动持久活动,而不用自行发明探索器权重。balanced 是新代理的默认值;fixed 保留显式的旧式控制。有界覆盖可以更改状态/窗口/时间/内存/磁盘/截止时间姿态、稀缺/均衡/丰富资源、首选价值(broad_qa、runtime_assertions、outcomes 或 approved_goals)、受保护的长尾工作,以及 ceilings 与 knee 停止。精确的基础窗口保持无断言/无目标且可恢复。受保护的长尾分配现在会启动确定性的根启动组合子任务,使用替代搜索种子和更深的边界,同时保留精确的基础检查点。runtime_assertions 活动可以使用 add_assertions 添加验证过的断言窗口;approved_goals 活动可以使用 add_goal 添加验证过的目标。每个子任务都使用显式授权,保存单独的证据报告,并且仅获得活动新增的关键、意图、作者结(authored-knot)或终局(terminal)证据的信用。
首份作者故事活动子任务评估在 The Intercept 上发现了一个可信的过期变量审查线索和一个被拒绝的断言假设。其分阶段目标未达成,两个高预算子任务都在达到 5M 之前因内存停止,而一个 500K 共享基础超过了持久检查点上限。这既是令人鼓舞的断言价值,也是一个明确的警告:代理编写的规则需要人工验证,专家需要从探针到扩展的经济学,大型活动成为常规之前需要紧凑的检查点。
随后的配对独立长尾评估比较了增长的共享前沿与受保护的根启动组合分区。在一次 5M Intercept 活动中,共享分支在总共 786,559 个状态时因内存停止;九个独立子任务完成了全部 5M,峰值堆更低,并计入了 3,558 个活动新增终局变体,而共享分支为 407。它们没有发现新的关键问题、作者结或可见结局。这是资源高效多样性和可测量的收益递减的证据,而不是普遍的 QA 价值声明。
随后的三家族 0.6 晋升门没有提升动态停止或扩展。Dog Ink Adventure 和 Heresy II 都在其 500K 基础产生可恢复检查点之前达到资源上限,因此没有长尾策略可以行动。在 The Intercept 上,独立分区达到 4.66M 个状态,峰值堆 1.40 GiB,而增长的前沿在 787K 个状态和 3.70 GiB 时停止;终局重新发现率从 34% 上升到 94%,没有新的关键问题、作者结或可见结果。Inkcheck 将这些建议保持为影子模式,并将动态首窗口大小调整视为更强大的下一个产品需求。
每个结果窗口都会返回稳定的策略 ID、分配原因、实测首选产出、吞吐量/资源证据、针对另一个窗口的带不确定性标签的经验范围、任何约束条件,以及用于检查完整曲线或发现的报告 ID。紧凑检查还会命名最新窗口的用途、分区和边际产出。一个 knee(拐点)需要连续三个无首选产出的窗口,并且不能消耗受保护的探针。它仍然是对实际运行轨迹的有界观察,而不是声称故事已被覆盖或之后不存在新发现。参见活动策略契约和 MCP 结果窗口指南。
在独立子级运行之后,紧凑决策还包含一个版本化的仅影子长尾推荐:扩展同一族、轮换到另一个分区,或在受保护下限之后停止。它在所选偏好下使用活动新增价值,报告按状态和秒计的近期收益,对于稀缺/均衡/充裕姿态要求逐步增多的干探针,并暴露紧凑的选择值重新发现以及事实性的报告局部发现差距。旧账本将那些信号标记为不可用。重新发现是与早期活动报告的身份重叠,而不是原始的重复状态工作;扩大的差距是观察结果,而不是平台期证明。liveEffect: false 意味着该证据尚不能改变分配。
人类无需学习其控制方式即可使用相同的持久策略:inkcheck campaign story.ink 运行均衡意图,而 --mode quick、deep 或 overnight 选择一种结果与时间的姿态。它随着工作推进返回不可变的源绑定结果窗口,在窗口之间的截止或取消时保留最新的部分报告,并将技术上的状态/时间/内存/磁盘上限保留为专家覆盖项。结果窗口区分已花费的工作、可操作的收益、预测的不确定性以及搜索是否还能继续。安静的发现间隔或观察到的拐点永远不会被描述为完整覆盖。
快速开始
需要 Node.js 18 或更高版本:
npx -y inkcheck path/to/main.ink无需全局安装。首次运行会下载固定版本的官方 ink 编译器,校验其 SHA-256 哈希,并在本地处理故事。
项目配置
当项目需要为每个人类或代理会话使用相同的入口点和有界 CI 设置时,请提交 inkcheck.yml:
schemaVersion: 1
entrypoint: story.ink
ci:
maxDepth: 100
maxStates: 1000000
goalMaxStates: 250000
seed: 1
storySeed: 1
search: portfolio
concurrency: auto
strict: true
assertions:
- id: gold_nonnegative
description: Gold never goes negative
when: always
condition:
left: { variable: gold }
operator: ">="
right: { literal: 0 }
goals:
- id: depleted_gold
description: Seek paths where the player runs out of gold
condition:
left: { variable: gold }
operator: "<="
right: { literal: 0 }运行 inkcheck validate-config 进行检查。在该目录中,inkcheck 使用配置的入口点和默认值;显式 CLI 标志仍然优先。未知键会导致验证失败,因此不受支持的外部行为和编辑策略字段不会看起来已被实现。已发布的契约是 配置模式 v1。
断言是类型化数据,绝不是 JavaScript 或任意 Ink 表达式。操作数是变量或标量字面量;比较使用 ==、!=、<、<=、> 或 >=,条件可以用 all、any 和 not 组合。规则可以在任何时刻、在终止状态、或在进入命名 knot 时运行。未知变量/knot 以及无效的跨类型比较会在探索消耗其状态预算之前失败。违规总是导致 CI 失败,并包含观察到的值以及精确的索引化重放见证。有界的干净运行仅表示“未观察到违规”;只有穷尽式运行才会将规则报告为已穷尽验证。
目标使用相同的不可执行条件语法,但引导探索,而不是使 CI 失败。通用探索始终获得完整的 maxStates 预算。在配置中设置 goalMaxStates,或在 CLI 上设置 --goal-states,以添加一个显式的确定性目标邻近切片;它默认为零,合并预算不得超过 100,000,000 个状态。如果没有请求额外切片,目标在普通探索期间仍会被观察。达到的目标包含精确的选择索引;未达到时报告 not_reached_within_limits,除非穷尽式探索确实证明其不可达。报告分别展示基线、目标和总预算,因此导向不会悄悄取代常规 QA 发现。参见 搜索实验 中的对比证据。
对于较晚的复合依赖,用两个或更多有序的 stages 替换 condition。每个阶段使用相同的类型化语法。Inkcheck 寻找第一个未满足的累计里程碑,因此只有在某个路径的状态同时满足所有早期阶段时,才会到达较后的阶段。未满足的先决条件会使后续阶段保持 blocked_by_stage;它不会将它们称为不可达。这一首个分阶段契约使用一个共享的额外目标预算,并从故事根节点确定性地重新开始,而不是序列化运行时检查点。
对于包含单个 .ink 文件的新项目,inkcheck init 会创建此配置。多文件项目必须使用 --entrypoint 指定根文件。inkcheck agent-kit --format codex 会在需要时添加配置、固定的 GitHub Actions 示例、.inkcheck/ 工件忽略规则,以及紧凑的版本匹配代理说明。这两个命令都是幂等的,并对每个目标进行预检;它们会拒绝整个操作,而不是覆盖或部分修改已有的作者文件。npm 工件还包含规范的 skills/inkcheck/SKILL.md、渐进式 Ink/工作流参考,以及十个可执行的金牌练习。inkcheck capabilities --json 将其声明为 features.bundledAgentSkill,并且仍然是已安装模式契约的权威来源。
--save-report 原子地将版本化报告存储在 .inkcheck/reports/ 下,并返回其稳定的、由内容和入口点派生的 ID。后续会话可以使用 inkcheck artifacts list --json 和 inkcheck artifacts show <report-id> --json;重新打开会报告保存的证据相对于当前入口点是 current、stale 还是 path_changed。报告可能包含故事文本、变量和精确见证,因此代理工具包默认忽略它们。关于信任、隐私和兼容性契约,请参阅 本地报告工件。
长时间的基础共享运行也可以在本地持久化其精确的实时前沿。先使用 --search=shared --no-min-repro --save-checkpoint 启动,之后用 inkcheck resume <checkpoint-id> --max-states N 继续;N 是更大的总授予量,而不是额外隐藏的工作。inkcheck checkpoints list/show 报告有界元数据、持久压缩大小、存储编码和源新鲜度。新的检查点文件是流式 gzip 工件;旧的纯 schema-v1 JSON 仍然可读。检查点是私有的、原子的、与源/配置绑定的、默认被忽略的,并且有保留上限;它们可能包含作者文本和运行时状态。参见 本地可恢复检查点。MCP 代理可以通过持久的 start_search / inspect_search / continue_search / cancel_search 结果窗口 使用完全相同的基础。它们还可以使用 add_goal 进行显式的附加定向探测,该探测从故事根节点开始,并保持该精确的基础前沿不变。组合、共享变量、断言、定向前沿恢复和托管作业尚不使用此检查点契约。
托管检查器
该仓库现在包含一个自托管的 Web 界面,供不想使用终端的作者使用。托管模式会临时上传授权的 .ink 源码,提供 Quick(更早的 250K 状态结果)和 Balanced(更深的 1M 状态结果)意图,创建短时私有作业,流式传输真实工作、收益和不确定性信号,并在完成、取消或失败后删除临时作业目录。完成的托管检查返回源绑定的结果窗口标识和稳定的发现 ID。它不会公开报告,也不会在应用程序日志中保留故事文本。可选的第一方使用指标保留每日汇总计数,以及保护隐私的近似每日独立浏览器估算:不保留 IP、用户代理、浏览器令牌或访客画像。
本地 CLI 仍然是隐私优先选项,因为不会发生故事上传。关于威胁模型、Docker 部署、操作限制以及当前低于 50 美元/月的预算,请参阅 托管检查器部署。
它能发现什么
编译错误和警告 — 损坏的 divert、未解析的变量、松散的结尾,带有文件和行号(通过 inklecate,官方编译器)
带复现路径的运行时错误 — 触发除零、坏外部调用或内容越界的确切选择序列,例如
repro: [Enter in darkness → Descend to the cellar]可能的非终止强制选择循环 — 当唯一可用的选择返回到具有相同作者可见变量的相同控制状态时,给出保守的审查警告;可选出口、随机行为、回合计数、访问计数和 EXTERNAL 调用被有意排除
未访问内容(已分诊) — 在配置限制内没有任何已探索路径访问过的 knot,每个都通过入站 divert 扫描分类:“此处没有作者编写的 divert 点 — 可能是孤立内容”与“有入站 divert — 可能超出本次运行的限制”
不同的终止状态 — 附带到达每个终止状态的选择轨迹;不同的最终变量被保留为不同的结果
与替代方案对比
捕获语法错误 | 探索选择分支 | 发现未访问内容 | 崩溃复现路径 | 在 CI 中运行 | |
| ✓ | — | — | — | ✓ |
手动试玩 | — | 仅你点击的内容 | 靠运气 | 如果你记得自己的点击 | — |
Ink-Tester | ✓ | 随机重复运行 | 行覆盖率 | 有限 | 手动/CLI |
inkcheck | ✓ | 系统性 + 种子随机,有界 | knot 覆盖率 | ✓ | ✓ |
编译器告诉你故事是有效的。点击浏览告诉你的是你碰巧点击的路径能工作。Ink-Tester 反复采样随机通关并报告行级频率;inkcheck 则系统地遍历选择状态并返回简短的失败路径。关键区别在于可重复性:修复报告中的路径后,相同的配置运行可以再次检查该路径。这些方法是互补的,尤其是对于包含随机性或引擎集成的故事。
示例
$ inkcheck examples/manor.ink
✓ compiled — 92 words, 7 knots, 6 choices
✓ explored 18050 states within limits (depth 100, 10000000 states, seed 1) — exhaustive (every reachable state visited) — 5 distinct terminal state(s)
terminal via [Enter in darkness → Search the study → Leave with your loot]: "You slip out the servant door, heavier by half a purse."
...
✗ 1 runtime error(s):
obj is null or undefined (at cellar.3)
repro: [Enter in darkness → Descend to the cellar] (found by dfs:last)
⚠ 1 knot(s) never visited on any explored path — unreached is not necessarily unreachable:
treasure_vault (manor.ink line 35) — no authored divert points here — possible orphan当运行被截断时,报告会指出实际限制它的界限——例如 ⚠ coverage is partial, not a proof — paths were cut at 30 choices deep; raise --max-depth to follow longer trails。深度和状态预算是两个独立的轴:在本地运行 The Intercept 时,使用 1,000,000 状态预算将 --max-depth 从 30 提高到 100,比在深度 30 时使用 10 倍预算能到达更多的后段故事内容。
编译或运行时错误时退出码为非零。添加 --strict 还会在警告、未访问的 knot、截断或外部桩上失败,因此部分覆盖无法悄悄通过 CI。
故事不一定要长才会超过默认预算。Inkle 发布的 The Intercept 被社区认为是一个相对较小的源文件,但 Inkcheck 在 5,000,000 个状态下仍报告其为部分覆盖:分支加上持久变量会产生远比可见选择数所暗示的更大的可达状态图。耗尽是一个观察到的证明,而不是从源文件大小推断出的预期。有限值的故事原则上可能是可穷尽的,但逐一枚举不切实际;回合、随机或无限变量状态会使语义图变得无界。有界运行会在先到者(状态、深度、时间或内存)处停止,并说明是哪一项。托管检查器将共享作业限制为 1,000,000 个状态;更大的作业(最高可达 CLI 的 100M 上限)应在本地运行。有关规模调整指南,请参阅 性能与内存。
在单次运行中,inkcheck 将状态预算分散到互补的搜索遍上,而不是把一切押在一种遍历顺序上。当前的 CLI 组合会探索“后选先走”“先选先走”和“由内向外”的 DFS 切片,再加入一个带种子的随机采样切片,用来变化确定性遍历容易重复的早期选择前缀;还会加入一个受前沿上限约束的多样性波束,像 BFS 一样逐层推进,同时为每个变量签名谱系保留一个状态;最后预留一小块广度优先切片,用于缩短复现路径。随机切片使用固定默认种子,而波束完全不需要种子,因此运行在 CI 中保持可复现;每个报告的结局和运行时错误都会注明发现它的遍(以及种子)。在相同的 --max-states 限制下,这通常能发现更多结局和可达的 knot,但它仍然是有界 QA:截断报告是有用的证据,而不是穷尽式证明。
--search=shared 选择了一个实验性替代方案:深度、新颖性优先和带种子的视图都从一个去重前沿中取数,每个可达状态最多被扩展一次。当多种策略本来会重新发现同一状态时,这可以在紧张的预算下更高效地使用资源。JSON 遥测将待处理与活动中的检查点 JSON/变量、保留的见证祖先、去重与语义索引、前沿引用和发现结果区分开;它还会报告已释放的祖先和过期视图压缩。这些是确定性的、可核算的负载/结构估计,而非精确的 V8 堆使用量。它还不是默认方案:某些早期选择结构可能仍更青睐组合中独立的随机和波束遍。
评估长时间运行的共享作业的库使用者可以使用 exploreSharedResumable(...)。当预算仍有剩余时,它返回一个绑定来源、带版本号的 JSON 检查点,其中包含精确的活动基础共享前沿;后续调用会提高总预算(例如从 100k 提高到 1m),并在不重放前 100k 的情况下继续。分段运行的等价性会与不间断运行进行回归测试。这是引擎基础能力,尚不是 CLI 持久化功能:检查点可能包含作者文本、变量、运行时状态和见证路径,而 schema v1 刻意排除了断言、目标,以及感知变量/目标的共享模式。参见 shared checkpoint schema v1。
--search=shared-variable 是一个范围更小的实验,将 12.5% 的共享前沿选择分配给通过不常见变量快照或转移到达的状态。这种提升是有限的,深度、新颖性和带种子的视图仍然保持活跃。它可能有助于机制驱动的 storylet 图,但并非在所有情况下都更好;已检入的对照表同时包含收益和退化。
自适应组合仍然是通用默认方案。实验模式不会改变它的权重或行为。Inkcheck 的 search strategy policy 定义了未来任何默认方案变更所需的基准广度和回归门槛。
受限搜索与随机采样
Inkcheck 并不是承诺访问非平凡故事中的每一个可能状态。分支、循环、变量、随机行为和宿主游戏集成可能使穷尽覆盖在物理上不切实际。与随机采样相比,它的实际优势是可复现性:在相同的故事和限制下,inkcheck 会系统地遍历选择图,为失败返回精确的选择路径,报告未访问 knot 的线索,并明确说明运行是部分的。
随机采样仍然有用,尤其是对于带有随机性或状态空间巨大的故事。应将这两种方法视为互补:随机游玩可能偶然发现令人惊讶的路径,而 inkcheck 在声明的预算内提供确定性的、CI 友好的证据。
在对 The Intercept 的一次本地测试中,深度限制为 30,更高的预算发现了更多终止状态,但仍未证明覆盖的完整性。计时结果来自一台本地开发机器,应视为规模证据,而非通用基准:
状态预算 | 时间 | 不同终止状态数 | 运行时错误 | 未访问 knot 数 | 结果 |
50,000 | 9.4s | 7 | 0 | 9 | 已截断 |
100,000 | 19.9s | 10 | 0 | 9 | 已截断 |
500,000 | 100.2s | 17 | 0 | 8 | 已截断 |
1,000,000 | 205.5s | 25 | 0 | 8 | 已截断 |
这就是预期的解读:每次运行都会测试真实可达的状态,并可能暴露真正损坏的路径,但截断报告只是关于访问过什么的证据,而不是所有内容都可达或正确的证明。
性能与内存
默认预算为 10,000,000 个状态,上限为 100,000,000 个状态,因此有必要了解一次大型运行的成本。限制一次运行的是两种资源:时间和内存。小型或可穷尽的故事两者都不会触及——组合会在某个系统性遍历证明可达空间完整的那一刻提前退出,因此无论默认值如何,inkcheck small.ink 都会在它已有的少量状态内完成。下面这些数字只对大型、不可穷尽的故事有意义。
时间大致随探索的状态数线性扩展。在一台开发机器上,The Intercept 大约每百万个状态运行 200 秒(见上表),因此 1000 万状态的运行需要几十分钟,1 亿状态的运行需要数小时。本地 CLI 没有墙钟时间限制,因此在 CI 或交互式使用中,请将 --max-states 固定为你实际需要的覆盖范围,而不是依赖默认值——或者使用 --progress 运行默认值(在交互式终端中默认开启),以便观察和中断。
内存是各项不同增长速度之和,这也是上限很高而非危险的原因:
增长对象 | 扩展方式 | 备注 |
去重哈希集( | ~线性,每个不同状态约 200 字节 | 主导项。inkcheck 为每个状态存储一个哈希,而非状态本身,这正是数百万个状态也能负担得起的原因。 |
DFS / 波束前沿 | 平坦 | DFS 受深度限制;波束有硬性前沿上限。两者都不会随预算增长。 |
随机采样 | 平坦(O(发现数)) | 不保留去重结构。 |
BFS 缩短复现前沿 | 唯一的超线性风险 | 在深层、少循环、多分支的故事中可能急剧膨胀(一次研究运行排入了约 631K 个完整状态)。 |
实验性共享前沿 | 形状相关,可能线性 | 保留序列化的待处理检查点及见证祖先。报告会暴露组件高水位标记;可选的 |
由此得到两条实用的经验法则:
预算要考虑堆,而不只是状态数。 作为最坏情况估算(不做状态去重),请按每 1000 万不同状态约 2 GB 堆来规划。含循环的故事会大量去重,远低于此;低去重故事则接近最坏情况。因此,1000 万状态运行的最坏情况(约 2 GB)接近 Node 的默认堆限制:循环密集的故事会远低于该限制,但大型低去重故事即使在默认预算下也可能在完成前触及内存守卫。1 亿状态的运行会超出普通默认堆,除非提高
--max-old-space-size,否则会在守卫处停止。无论哪种方式,它都会以部分报告干净地停止——正是守卫让高上限变得可以安全设置,而不是承诺运行一定会完成。真正的限制者是内存守卫,而不是上限。 一次运行会在 V8 堆的 85%(或你的
--max-memory)处干净地停止,并返回带有truncatedBy.memory的部分报告,而不是崩溃。因此设置--max-states 100000000并不鲁莽——在普通机器上,决定停止位置的是守卫,而不是上限。要更进一步,就给 Node 更多堆:NODE_OPTIONS=--max-old-space-size=8192 inkcheck big.ink --max-states 100000000。安全限制不是效率决策。 状态、时间和内存上限回答的是“这个任务可以走多远?”它们并不声称用满整台机器是有价值的,也不声称一个看似平稳的平台期就是完整的。0.6 研究路径会随时间衡量组合新增发现、吞吐量、恢复间隙、峰值 RSS 和保留的前沿字节,以便未来的快速/均衡/深度策略能选择有用的结果窗口,同时仍保留长尾探测。固定限制仍然可用于 CI 和审计。
当故事太大而无法完成时,按影响程度排列的调节手段:提高 --max-old-space-size(更多余量)、传入 --no-min-repro(去掉超线性 BFS 前沿)、降低 --max-states(同时限制时间和内存),或者拆分故事并分别检查各部分。在实验性共享模式下,当待处理检查点队列本身需要更紧的边界时,设置 --max-frontier-memory 或 --max-frontier-states,并且只有当其报告显示有用的证据仍在持续出现时,才提高该边界。每次运行后,nextRun 的判定会指出起约束作用的限制,这样你就知道该使用哪种调节手段。
实测的 resource-safe deep-run evaluation 记录了守卫在作者编写的 5M 上限任务上的表现,包括共享前沿待处理状态和序列化字节的高水位证据。
MCP 服务器
为处理 ink 故事的 AI 智能体提供的工具:
工具或逻辑操作 | 作用 |
| 版本化模式、限制、搜索模式及显式特性可用性 |
| 仅源码项目映射:目录、结构、语义、外部项、节点、变量和静态条件门 |
| 结构化编译问题(严重级别、文件、行号) |
| 启动一个有界精确共享搜索结果窗口,并返回一个承载能力 |
| 通过一个有界操作路由搜索后、行动、测试、回归、断言、目标、取消和试玩测试的后续操作 |
添加到 Claude Code:
claude mcp add inkcheck -- npx -y inkcheck mcp或添加到任一 MCP 客户端配置:
{
"mcpServers": {
"inkcheck": { "command": "npx", "args": ["-y", "inkcheck", "mcp"] }
}
}默认的 MCP 配置会暴露五个工具:inkcheck_capabilities、inspect_story、compile_story、start_search 和 inkcheck_workflow。这能让新代理的引导上下文保持精简;能力列表会列出路由器的逻辑操作和请求字段。只有在客户端需要每个操作都作为独立的命名工具时,才设置 INKCHECK_MCP_PROFILE=full。
紧凑的代理循环是 inkcheck_capabilities -> inspect_story -> compile_story -> start_search -> 通过 inkcheck_workflow 进行路径查找/回放/回归操作 -> 修复 -> 编译并验证。结果窗口会话是默认的代理路径,因为它们有界、持久、分页且与源绑定。逻辑上的 start_campaign / continue_campaign 操作会围绕同一个精确的共享前沿增加一个聚合策略和实测/来源信息;普通的 start_search / continue_search 则保留显式的累计授权控制。调用是同步的,因此取消操作发生在可靠的返回边界处,而不是窗口中间。inspect_search 保持最小隐私;add_goal 在完全不影响精确基础搜索的前提下,可花费一个单独报告的方向性预算。replay_witness 是显式边界,返回当前剧本、变量轨迹及可选状态。
对于路由失败、断言失败和已批准目标,pin_regression 会在编辑前执行一次,而 check_assert 在编辑后再执行一次,只顺着一个精确的可变轨迹重新运行,无需另一次额外遍历。pin 不是广泛的重新验证;而是在有意义的修改后运行一次新的有界搜索。请参见 QA 证据 pins、内置技能 和 MCP 结果窗口会话。
当作者或代理提出故事规则时,inkcheck_workflow 可以首先运行 review_contract。该审查会验证编译后的故事中的类型化断言和目标,列出已有契约,要求作者批准,并默认推荐使用零定向预算的广泛 QA。它是只读的:不能编辑配置、不能支出搜索预算、也不能静默提升目标探针。请参见 代理定向 QA 合约。
CLI
inkcheck capabilities [--json]
inkcheck inspect <story.ink> [--json]
inkcheck <story.ink> [--max-depth N] [--max-states N] [--seed N] [--story-seed N] [--search=portfolio|shared|shared-variable] [--concurrency auto|N] [--max-frontier-states N] [--max-frontier-memory MB] [--auto] [--profile] [--next] [--no-min-repro] [--strict] [--save-report] [--save-checkpoint] [--progress=auto|human|ndjson|off] [--human|--json|--json-stream|--markdown]
inkcheck artifacts list [--json]
inkcheck artifacts show <report-id> [--json]
inkcheck artifacts findings <report-id> [--limit N] [--cursor C] [--json]
inkcheck artifacts finding <report-id> <finding-id> [--json]
inkcheck artifacts replay <report-id> <finding-id> [--json]
inkcheck artifacts delete <report-id> [--apply] [--json]
inkcheck artifacts prune --keep N [--apply] [--json]
inkcheck checkpoints list [--json]
inkcheck checkpoints show <checkpoint-id> [--json]
inkcheck resume <checkpoint-id> --max-states N [--json]
inkcheck mcp # start the MCP server on stdioinkcheck capabilities --json 允许代理在依赖它们之前先检查模式版本、限制、搜索模式,以及显式支持的或不可用的功能。inkcheck inspect story.ink --json 执行仅源码的确定性检查,不编译、不探索:它会跟踪项目内部的 include,并返回一个有界的映射,包含故事结构、语义、外部项、节点/函数、变量读/写声明、以及带实际赋值位置的静态条件门(static condition gates),并返回精确的搜索前沿。一个持久化的 MCP 会话可以把一个明确选择的受支持门放入一个单独的有界 probe_gate 目标运行中;该目标从根开始运行,并保持精确的基线,报告证据、有界漏失。门和目标赋值是前置提示,不是可达性证据或默认搜索分配的依据。请参见 复合门检查契约 和 代理发现契约。
门探针评估协议 会在普通共享搜索与相同预算的显式探针之间,对早期组合锁和一个选择性加入的 5M 互砥 单元进行对比。它用于判断额外的前置条件是否值得处理,而不是覆盖率或推广声明。
版本检查使用版本化的 报告结构。发现结果具有稳定 ID 和规范化的种类;终止和运行时错误证据中同时包含基于人选的文本和基于零的索引,因此重复标签可以通过 playtest_story 精确复现。版本记录包含 Inkcheck 版本、编译后故事指纹、生效配置、环境约束,以及仅观察不修改的 shadowDecision,同时保留已有的 compile、stats、explore 和 nextRun 小节。
--concurrency auto 是本地的默认配置。它设置四车道上限,而非四个无序 worker:一次自内向外 DFS 遍历最多运行 1,024 个状态,然后当故事用完、状态被绑定、作者定稿的节点已满、硬件只有单核、或内存无法安全支撑 worker 时,版本化分类器会按顺序执行。如果父进程中已有未利用的活路径存活,则向里 DFS 会保持该路径活跃,而未触碰的路径则会在持久化 worker 中开始。--concurrency 1 是硬顺序;显式取值 2–16 则在不进行负载分类的情况下保持固定的 worker 数。共享搜索和累加目标运行会保持顺序,除非显式请求了不兼容的固定值。
报告会显示 concurrencyMode、已解析的上限/触发策略/决策原因、运行 worker 列表、堆上计划的聚合体,以及重复评估(生产策略下为零)。worker 失败时,会保留最新的已完成证据并报告 truncatedByWorker;它永远不会伪装成状态预算的结果。托管部署会为每个作业设置显式的上限,默认值为生产容器上的一个,真正的子取消会清理临时的 RSS/上传内容。峰值 RSS 可能更高,因为 V8/runtime 开销不属于堆;分类器会估算工作负载类型,而不是覆盖完整性。
MCP 默认使用 压缩的计算机输出:检查上限为 16 KiB,编译、统计、一次性搜索和结果窗口响应为 32 KiB。输出省略与完整搜索截断分开报告。完整故事报告仅可通过显式深度调用或钻取调用获得。
保存的报告支持有界的查找钻取,而无需加载整个报告。artifacts findings 默认最多返回 20 条最小隐私摘要(最多可调至 100)和一个报告游标;摘要中不包含故事性叙事、变量、选项文本或证人路径。artifacts artifact 获取一条完整且稳定的证据。artifacts replay 重新编译已保存的入口点,并按照已保存的故事种子跟踪该查找的索引选择;但仅在证据新鲜度为 current 时允许重放;过期或移动过的源将直接关闭并失败。
报告存储是私有且有界的:每个报告最多使用 256 MiB,一个项目中的全部报告最多使用 1 GiB。超过任一上限的保存会失败,且不会删除旧的证据。artifacts delete 和 artifacts prune --keep N 默认是预览模式,只有 --apply 才会发生变化;prune 会为每个入口点保留最新 N 个报告,每次最多删除 100 个。这一显式生命周期可防止稳定的报告 ID 仅仅因为另一个运行完成而消失。
维护者可以用 manifest 驱动的 影子策略评估器 在独立的预算运行之间对比影子建议。单独的 搜索推广基准 在固化的、包含 20 个家族(含固定内容且作者安全的工程)语料库之上,对候选/基线矩阵进行分层对比,报告资源占用和项目的最坏情况/损失,不会宣布胜者。作者工程推广评估 在单元完成且工作负载有意义的项目约束(而非策略 v2 优势)时发现验证。两个工具都不会将有界运行称为预言机,也不会修改默认定额。
--max-depth 接受 1–1,000,--max-states 接受 1–100,000,000,默认预算为 10,000,000。这些硬性上限可防止格式异常的自动化输入意外禁用探索边界。该默认值刻意设定得较为宽松,因为三件事能让大预算变得安全而非鲁莽:一个可充分探索的故事会在系统化遍历证明其穷尽之后立刻提前退出(因此小故事仍能在少量状态内完成)、内存守护进程会在内存耗尽或崩溃前干净地停止、并且进度报告能让你观察并中断很长时间。因此,一个大型非穷尽故事会用掉那笔预算——参见 性能和内存 再在 CI 中运行。如果运行时间上限比覆盖率更重要,可以在那里固定一个更小的 --max-states。
--max-states 是整个运行的总预算,而不是某一单次 DFS 遍历会花完所有状态的承诺。默认情况下,CLI 会将该预算的大部分分配为三个互补的 DFS 视角用于选择树,外加一个随机种子化的采样片段,并保留一部分广度优先片段用于错误和失败的更短复现路径。当广度优先的缩短不如更广泛的搜索重要时,请使用 --no-min-repro 将该再现片段花费在 DFS 总计上。
--seed(默认为 1)仅控制 Inkcheck 的随机采样搜索片段。--story-seed(默认为 1)独立设置 Ink 初始运行时用于 RANDOM() 和 SHUFFLE() 的 RNG 状态。若要保证可重复的 CI 与精确的证据回放,请保持两者均固定;请更换 --seed 以采样不同的选择路径,或有意更改 --story-seed 以演练其他故事随机序列。作者编写的 SEEDED_RANDOM(...) 命令仍然有效,并可能覆盖初始故事种子。Inkcheck 会记录运行日志中的两个种子以及 storySeed,但一次运行并不能枚举每个可能的故事种子。每个查找结果在 --json 输出中的 foundBy 字段标识了发现该结果的遍历方式,例如 dfs:last 或 random:seed=1。
--search=shared 选择共享状态多前沿实验引擎;--search=portfolio 是原有默认且不变。共享模式在固定种子下时确定性依然保持,且依然遵守深度、状态、内存、时间、进度和重放缩减控件。
--save-checkpoint 有意识地比普通共享检查点更窄:它要求 --search=shared --no-min-repro,并且在同一命令中不能有断言、目标、--auto、--next 或其它报告关键点。当活动(live)仍存在时,JSON 输出会包含一个绑定源头的检查点 ID。inkcheck resume <id> --max-states N 会要求源和搜索绑定匹配,并要求 N 超过该检查点之前的已发放循环保活授权;它会自动保存下一代。已完成和资源受限的搜索会返回其报告,而不会再生成一个可恢复的检查点。
--search=shared-variable 会在共享前沿增加一个小型变量稀有度遍历。它优先遍历观察到的稀有变量以及机械地更改;它不使用 AI、不推断故事含义、也不推断哪些变量值得期望。
--max-frontier-states 和 --max-frontier-memory 是用于保留检查点的可选共享安全边界。两者均无默认值:Inkcheck 不设低默认上限。如果显式边界被限定,运行会保留其发现,并报告 truncatedBy.frontier,不会将停止误标为状态预算耗尽。同样的控制可作为 ci.maxFrontierStates / ci.maxFrontierMb 和 MCP explore_story 输入。
--max-memory <mb> 限制整个运行在干净停止前可以使用的内存总量。V8 堆内存耗尽中止无法事后捕获,因此 inkcheck 在探索期间监视内存,并恰好在崩溃之前停止,保留目前找到的所有内容,并报告 truncatedBy.memory 的部分报告,而不是丢失运行记录。显式上限保留最多 25%(至多 1 GiB)用于最终结果构建和刷新;受约束的流会同时报告完整上限和低勘探水位。默认上限为 V8 堆限制的 85%(遵循你设置的 NODE_OPTIONS=--max-old-space-size),因此大型运行在普通硬件上也只会优雅降级而不会直接崩溃;传一个显式的值可以调紧或放松。在内存停止时,nextRun 的判定是 investigate(提高 --max-old-space-size、降低 --max-states,或拆分故事)——绝不是 broaden,因为更多预算只会更快撞墙。
--max-time <s> 是总墙钟对应物:最后期限在编译和源码扫描之前开始,运行会保留 10% 的额度(250 毫秒下限、60 秒上限)用于合并已保留的发现并清空其结果。探索以 truncatedBy.time 停止,而不是运行到故事预算。本地 CLI 没有默认时间限制。它适用于持续集成或任何需要有限运行时间但仍希望获得目前结果的环境——与内存守卫相同的优雅部分理念,只是应用到时间上。托管 Web 检查器会将其自动设置在硬超时稍前,因此慢速的 feedback 会返回部分报告而不会被 kill。
--profile 会生成故事的简易静态摘要——变量及其赋值位置、选择密度、最长转移路径,以及深度限制,如果检查器为该摘要选择算出的权重。--auto 会应用这些建议:当静态摘要超过默认值时提高 --max-depth(永不降低,你的显式标志优先级更高),并将摘要报告器的权重传给作品集权重。对于主路径深度为 40 的故事,默认设置会找不到任何内容,而 --auto 会到达终点并证明该故事在约 111 个状态内是穷尽的。
交互式终端默认显示简短实时的进展:已探索的状态、对比了已配置的预算、以及已用时间。--progress=human 会生成适合 CI 日志的可读快照;--progress=ndjson 会为代理和解析器写入版本化事件;--progress=off 则静默进度信息。这些百分比都不代表故事覆盖率。最终的标准输出报告仍然保留权威性,进度信息也不包含故事正文、选项、变量、或代码片段。
每份报告还携带一个 nextRun 判定结果——一个很小的封闭词汇表(stop、deepen、broaden、reseed、investigate),它是根据报告本身环路计算的,包含具体的标识、引用报告使用字段的说明,以及有证据支持的预期收益。--next 会对它操作:检查完成后,inkcheck 会执行推荐的升级并重新运行,最多三次;在 stop/investigate 判定或者达到标识上限时停止,或者当升级后的运行没有发现新内容时(固定点)停止。每次运行的痕迹会以 runs 的形式写入 --json 输出;远的遍历会输出到 stderr,确保机器输出保持干净。建议永远不会超过文档化的硬上限——当没有标识提升有证据支撑时,判定会降级为 investigate,并指出需要修改的地方。
GitHub Actions:
- uses: actions/setup-node@v4
with: { node-version: 22 }
- name: Check the story and publish a readable summary
shell: bash
run: |
set -o pipefail
npx -y inkcheck story/main.ink --strict --markdown --max-states 500000 | tee -a "$GITHUB_STEP_SUMMARY"该示例固定了 --max-states 500000,以获得可预测的作运行时间;默认预算为 10,000,000,这是一个大型且非穷尽的故事实际会耗尽的预算(请参阅性能与内存)。在 CI 中,只要有界执行时间比最大覆盖率更重要,就固定预算。
--strict 不仅在未访问提示项和未访问的结上失败,还会在探索被截断时失败,或某个 EXTERNAL 方程需要被打桩失败。这是为了防止部分检查结果被打上绿色“完成”标记。
参阅 InkJam QA 指南,获取面向 o步作者的设置和解释报告的帮助。
发现翻译结果有误?请使用公共问题表单 报告错误或缺失结果,提交经授权的 minimal fixture,或 [请求加入 QA 诊所检查](issue new?template=qa-clinic.yml)。请勿将私有、保密或限量发布的故事材料附在公共 issue 中。
面向人类、CI 和智能体
inkcheck 可以由终端前的人类、CI 任务或可选的 AI 智能体驱动。工具本身仍然不使用 AI;智能体只是 CLI 或 MCP 服务器的另一个调用方。
机器可读工具:
tool.json位于仓库根目录,描述 CLI 标签、MCP 工具、退出代码和--json/--json-stream输出形状,集中在一个文件中。--json将整个报告输出为一个 JSON 对象({"compile": ...}或{"stats": ...}或{"explore": ...}),请解析它,而不是抓取漂亮的输出。explore.passes保留一个“探索器找到的内容”(discoveryByExplorer) 的有界传递dailyPassKeys(“此探索器新增了哪些内容”)加上portfolio专用passKey(“此探索器首先新增了什么”),区分开精确的终点、可见标记、运行时错误、断言、目标/阶段以及可比较的扣。摘要保留第一次/最后一次的发现状态,以及在没有压缩的情况下仍能保留缝隙事实。投资组合报告还包括实际交错执行顺序的整个运行曲线;挂钟时间仍然只是进度事件中的观测。explore.schedule显示自适应轮次如何分配预算。有版本的futureAlternatives显示未来任意时间策略会建议的内容以及原因,包括受保护的逐次通过下限和不作保证。它是只读的(applied: false):它永远不会改变当前所写的细节,也不声称boundedCoverage是证明。--json-stream当可重放的数字见证被保留时会输出 NDJSON,然后输出一个有限的结果摘要,而不是完整展示完整的多维报告或报告大小的 JSON 字符串。目前需要--concurrency 1,支持一次探索运行(不支持--next或--profile),并且不能与--save-report组合。保留数字标记模式支持 Inkcheck 的 oracle 无关证词,但不会将 oracle 的细节暴露给每次搜索或每个普通结尾。用于长期外部进程评估,其中部分证据必须跨越硬边界存活。请参阅 有界证据流契约。--progress=ndjson会向 stderr 发出版本化的生命周期和工作流事件,供智能体或 CI 日志解析器使用。stateBudget是预算使用情况,而不是故事覆盖范围;最终的 stdout 报告仍具有权威性。请参阅 进度契约。--human-readable会发出一个优先修复列表,按错误、警告和说明分组,尽量提供可用的文件/行位置、运行时失败的选择路径,以及每个条目的下一步操作。--markdown会发出一个 GitHub 摘要友好的报告,供人类在检查 CI 时使用。确定性退出码:
0干净 ·1编译/运行时错误(或在--strict下:警告、未访问结、截断或外部存根) ·2用法错误。请按退出码分支处理,不要直接 grep。MCP 工具:
claude mcp add inkcheck -- npx -y inkcheck mcp暴露了五工具智能体配置文件。使用INKCHECK_MCP_PROFILE=full获取兼容性目录。循环: 编辑
.story->compile_story->start_search-> 通过inkcheck_workflow路由下一个凭证操作 ->fix-> 编译并验证。inkcheck 是作文是对您生成或编辑的 Storygraph 可重复执行的机械检查;请在归还之前使用它来验证您自己的工作。覆盖循环:
explore_story(以及 CLI--json)会返回nextRun— 根据其itinerary(stop/deepen/broaden/reseed/investigate)打开nextRun.flags,然后重新运行,直到stop: true;或者让 CLI 自己去驱动:inkcheck story.ink --next。
仓库根目录下的 llms.txt 是关于上述所有内容的紧凑、对模型友好的摘要。
运作原理
编译
编译使用
inklecate(权威编译器)——通过$INKLECATE_PATH查找,然后是PATH,首次运行时自动从固定的官方 ink 1.2.1 发布版下载到~/.cache/inkcheck。下载的归档在解压前会使用固定的 SHA-256 哈希值进行验证。故事使用-c编译,因此所有节点访问都会被计数。探索 在 inkjs(官方 JS 运行时移植版)中运行编译后的故事,复用池化的 story 实例,以便编译后的 JSON 每次传递只解析一次,状态通过
LoadJson回溯。Inkcheck 从--story-seed初始化故事随机性(默认 1),然后在每个保存的分支中保留 Ink 的 RNG 状态;作者编写的SEED_RANDOM(...)仍具有权威性。状态按内容哈希去重。INCLUDE都会被跟随。CLI 使用有界、自适应的搜索。互补的几趟 pass ——后选择优先、先选择优先、内部-外部 DFS、多样性优先 beam,以及种子随机游走——以确定性轮次交织运行,共十轮。初始权重(大致为 20/20/26/15/20%,或形状配置在
--auto作用下的建议)每轮都会朝向仍然可以产出发现的 pass 重新分配,并有意为每个活跃 pass 设置 8% 的分数下限。研究专用策略重放会将这一意图转化为可审计的累计整数服务,并根据各趟 pass 实际观察到的执行窗口(而非全局状态计数)对近因性进行归一化。它要求至少三个窗口才开始估算收益,在一两次测量窗口后若未续期则使信号过期,并且只允许针对续期的运行时/断言证据或明确的目标进展进行实验性分配;广泛覆盖仍然由既定调度器负责。在完整推广语料库全部通过之前,正式生成器保持不变。这些 pass 互补:DFS 排序系统会系统地遍历子树,beam 会在硬前缀上限内将预算分散到各变量状态谱系中,随机游走会重新滚动每个选择点,因此早期的选择组合会被采样而非重复。每一条发现都会合并为一份报告,并标注是由哪一个 pass 发现的,执行的计划会出现在--json输出中。感知工作量的
--concurrency auto是本地包默认值。它的实时 1,024 状态、内部-外部 DFS 先导,会成为常规首个自适应轮次的前缀,然后要么继续顺序执行,要么与有界持久化 worker 中未触碰过的 pass 重叠;如果在该先导过程中遇到时间或内存限制——或在任何 worker 初始化之前截止时间就已到了——有效的先导会作为一个明确限定资源截断的局部报告返回,而绝不能被误标为状态耗尽。80 单元 100K 门精确保留了发现、校验和自适应计划,并且只有两个开放式前端激活;匹配 5M The Intercept 深度 30/深度 100 门局域网保留了精确的证据,拒绝了深度绑定任务,并将持续任务从 657.7s 改进到 489.0。所有状态都在一个上限内,重复校验的评估为零。显式1保留顺序执行;显式的 2-16 上限保留固定并发。参见 concurrency 评估。实验性的
--RUNTIME=shared会保留一个全局状态标识,并通过深度、新颖度和预先播种的 frontier 视图来展示未完成的 action。任何视图选择的状态都会扩展一次;现在释放的 RUNTIME JSON 会立即发布,紧凑的父类链接仅在待处理的 descendant 存在时需要确切的回放路径时才会保留,过期的视图 ID 会定期压缩。报告会展示组件消耗情况及可选的显式检查点信封。变量状态与变量转换稀有性会记录为评估遥测。实验性的
--search=shared-variable会将每八个共享 front 选择替换为变量稀有性视图。它的得分结合了目标变量快照的观测频率以及该边上最稀有变化;不能超过它固定的 slice,因此由于图谱结构新颖性、深度、以及种子化展示都仍然保留其表示方式。当任何一次系统性 pass 访问到每个可达状态而没有命中任何限制时,整个投资组合都会停止:进一步的所有状态都将是冗余的。一个默认的全可探索故事,默认的 10,000,000 状态预算,只会在它实际拥有的少数状态范围内结束——大默认在故事是穷尽的情况下没有成本。
Beam pass 回答"beam 到底应该优化什么"的问题:幸存者会均匀分布在变量签名组之间(多样性优先),组内按新颖度排序——新访问过的节点、然后新变量签名、然后新提供的选择集。它不需要种子就能决定它,并且每当它不得不剪掉一个可达状态时,它都会报告为截断。所以 beam 永远不会默默声称自己全覆盖了运行范围。
除非使用
--no-min-repro跳过,否则 CLI 会从请求的--max-states预算中预留出让 BFS 大致 10% 的预算,用于广度优先短缩分片。BFS 会尽量通过较短的选择轨迹来找到共享发现,并可能产生额外的浅层发现。需要先把不变量钟罩兴夺难与时间界限放在考量之中;报告会显示在不变量截断时的准确时间。
覆盖范围限制
探索有边界。截断报告是访问过哪些状态的证据,而不是关于整个故事的证明。
报告会说明其运行限制(深度、状态预算、搜索种子、故事种子),如果被截断,裁剪掉限制时间之前的状态(
截断原因在--json中,包括memory),并给出针对性建议该提高哪个标准。像内存不足这种较大的运行会干净地停止,并返回由于去重哈希集/tri的样子 深度优先搜索(DFS)兼容跨越了全部状态空间,并让输出结果无限制分布。对于玩家而言,输入
--min-depth或--max-depth与--max-states,需要保证最坏情况下的组合行为;报告会明确说明是否访问完。如果在某个 pass 下真的访问完所有状态且没有触碰到任何限制,那么报告会说明"穷尽所有状态"(
exhaustive),此时, 即使耗费了更多 sample 也不会当作截断——但我们仍然会因为"资源"不足被标记为 "UNKNOWN" 位置,因为在这种情况下,我们不会去确认这些状态。由于宿主游戏不可用,
EXTERNAL模块会停用为 0。报告会列出每个 stub;严格模式下会进行报错,而不会声称"我探测成功"。随机性以当前 story seed 为种子,
--story-seed参数可复现,但如果只跑一次,--story-seed中无法枚举每个种子。反复开展真实游戏测试,手动调整--story-seed和--stop等"条件反转",才能让结果频率有意义。不可达的节点可能是有意休眠、被引擎置入、或者从外部不可达。不可达的 triage 是"可选审查",不等于"删除"。
Roadmap
路线由产品与工程真相 scorecard 主导。任何史诗都应该在相同约束下,做到可测量的改进,并且不会削弱有界覆盖、关键证据保留、确定性重放或资源上限。
覆盖范围透明度提升:更清晰地报告截断、深度上限、访问过的结尾、跳过的搜索空间、以及哪些已被探索/未被探索。
报告质量优化:更好的源码定位、更短的重现路径、稳定的问题身份、更清晰的运行错误汇总、未访问节点和覆盖限制。
作者可声明的故事确定性规则:工程确定性保证规则,如"gold 不能为负"、"health 不超过最大值"或"结局前必需变量已设置"。
目标导向变量搜索:允许作者和 NPC 在保留通用搜索预算和精确覆盖限制语言的同时查找已批准的状态。
可选托管 AI 目标助手:一种一流的、显式启用的人类界面,帮助非技术作者提出变量目标和断言供审批,然后将所有执行和验证委托给 Inkcheck 确定性非 AI 引擎。提供者、同意、来源共享、保留时间、禁用等所有控制必须显式声明;生成的规则绝不能在非预期且未经验证的情况下被静默信任或应用。
复现持久性:记住已知失败的路径,并确保即使在遍历策略不断改进时,未来的运行也会继续检查它们。
紧凑战役的检查点:保留大型故事前沿的有用部分,同时不必要的检查点产物不能主导内存/磁盘,并且会退化为在序列化限制之前的不可变部分报告。
公共兼容性夹具:同意安全的示例和合成边缘情况,用于回归测试、性能比较和信任建立。
可执行性:可执行性 ready 是"无隐藏提示"协议、确定性运行时/断言夹具、bootstrap/tool/reference/safety/proof 目标、机器工具,以及各工具/技能/模型的属性。两个不同 agent 实现中,通过两次观察性运行仍然是发布门禁 (#67)。
搜索改进扼流套件:在测试任意策略更改默认之前,跨结构族、预算、深度和种子的广泛而预先声明的计分卡。
有界专业搜索:检测机械形状,并为复合门、循环/计数器、storylet 资格、断言边界和行为多样性前沿派发小型专业探测。
大故事性能控制:快速、标准、深度预设,并给出更清晰的时间/覆盖权衡。
结构性 lint:可选检查项,用于检查缺失的标签、不一致的标签策略或项目元数据约定。
许可证
MIT* 编译
编译使用
inklecate(可用的编译器)– 通过$INKLECATE_PATH(环境变量)、PATH、最后自动从固定的 ink 1.2.1 发行版下载到~/.cache/inkcheck。下载的归档文件在提取前会用固定的 SHA-256 哈希值进行验证。故事使用-c编译,因此所有 Knot 访问都会被计数。探索 在 inkjs(官方 JS 运行时移植版)中运行编译后的故事,复用池中的故事实例,因此编译后的 JSON 每次通过只解析一次,状态通过
LoadState重绕。Inkcheck 从--seed初始化故事随机性(默认 1),然后保存每个分支中的 Ink RNG 状态;作者编写的SEED_RANDOM(...)仍然可以执行。。状态会按内容哈希去重。INCLUDE会被跟踪。CLI 采用有界、自适应搜索。A complementary set of passes——last choice first、first choice first、inside-out DFS、diversity-first beam,以及 seeding random walk——以我们轮的交替运行: