Skip to content

Commit fbb1314

Browse files
authored
Merge pull request #37 from vitry/feature/zcode-job-logs
feat: add durable private job logs
2 parents 86453e5 + 987744c commit fbb1314

47 files changed

Lines changed: 3586 additions & 168 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All notable changes follow Semantic Versioning.
44

55
## Unreleased
66

7+
- Added private durable per-job human-readable logs that retain the complete accepted safe semantic-progress history while job previews remain bounded to four entries. Exact-owner detailed status displays the private absolute path; compact, foreign, sibling-session, sidecar, relay, and terminal surfaces remain path-free, with no new log command or retention lifecycle.
78
- Fixed ZCode CLI 0.16.3 conversation progress compatibility: bounded initial, online-overflow, and recovery snapshots now establish silent sequence baselines; all five production delta operations are structurally accepted; and only validated tool/turn rows can emit bounded public progress. Online deltas require the exact exclusive baseline, and any overlap or ordinal/sequence gap fences further online progress until an authoritative snapshot or a recovery delta covering the trusted sequence resets it. Online frame state and watermarks now commit transactionally after asynchronous descriptions settle, so ignored frames cannot leak later tool summaries. Structurally accepted zero-event frames remain diagnostic-only and no longer suppress or stop snapshot fallback; only a frame with bounded public semantic progress establishes online health. Snapshot history, state patches, row text deltas, and removed-row content are never rendered, while fragments remain unsupported and fall back through the existing observational progress path.
89
- Fixed terminal ZCode failure handling so failures are no longer replaced by `ZCODE_RESULT_MISSING`: failed and cancelled jobs remain queryable through `$zcode:result`, stored errors appear in result and status output, and natural-language result references without an ID select the latest finished owned job. This does not repair upstream provider SSE or network failures.
910
- Added an instance-bound Rescue launcher rendered by the owned parent hook, so Root and child reuse one exact plugin-instance command instead of constructing companion paths. Installed and source-development namespaces remain intentionally isolated; `source-session-unproven` and unsafe-launcher failures are terminal with no setup retry or cross-instance redirect. Existing data locations remain unchanged, while the managed Role digest requires the normal owned upgrade through `$zcode:setup`.

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Every run is reserved as a durable, owner-scoped job. Installed plugin state liv
103103

104104
`SessionEnd` performs best-effort settlement of the ending session's writable Rescue. A claimed queued reservation remains unchanged while its worker lease is held. If the process exits before settlement completes, a later Rescue uses a reservation-time crash fallback and may settle a provably orphaned writable job; settlement does not transfer ownership, and only the original owner can access its result. During this reservation-time crash fallback, a held exact worker lease keeps the writable guard in place. When the exact worker lease is free and the existing broker control channel is unavailable, `SessionEnd` or the next Rescue archives the orphan as `failed` and releases the writable guard. This is abandonment, not confirmed remote stop. On a reachable broker, an unacknowledged `session/stop` still keeps the writable guard. Other sessions can use `$zcode:status --all` only for redacted workspace inspection.
105105

106-
Foreground runs stream ZCode activity to the current terminal. If no new activity arrives, they emit a 20-second heartbeat so a long model or tool call remains visibly alive. The same safe activity is stored on the job; `$zcode:status <job-id>` shows its phase, last activity time, and recent progress previews. For example:
106+
Foreground runs stream ZCode activity to the current terminal. If no new activity arrives, they emit a 20-second heartbeat so a long model or tool call remains visibly alive. Every accepted safe semantic progress event successfully dispatched by the existing bounded pipeline is also appended to a private, durable, human-readable `workspaces/<workspace-hash>/jobs/<job-id>.log`, beside `<job-id>.json`; the job's `progressPreview` remains only the last four events. The exact-owner detailed `$zcode:status <job-id>` displays progress previews, its phase and last activity time, plus `Log: <absolute-private-path>`. For example:
107107

108108
```text
109109
$zcode:rescue --wait repair the failing tests
@@ -115,8 +115,13 @@ Status: running
115115
Phase: running
116116
Progress:
117117
- ZCode started a tool call.
118+
Log: <absolute-private-path>
118119
```
119120

121+
The per-job log may also store current-turn visible assistant text selected by the exact existing linkage rules and the authoritative final output. Raw command stdout/stderr, arbitrary tool payloads (input/output/errors/metadata), raw reasoning, file or patch contents, environment values, credentials, capabilities, and hidden messages are never directly ingested as log source fields. This allowlist is not a semantic secret-redaction boundary: if visible assistant or final text itself quotes or paraphrases sensitive material, that selected text is retained. Keep secrets out of visible model text and protect the private log accordingly. Logs and progress are observational and cannot establish or alter terminal authority.
122+
123+
Only the exact-owner detailed status exposes the private path. Compact lists, foreign `--all` projections, sibling sessions, the bound Rescue status sidecar, Root relays, and terminal notices do not expose `logFile` or a log path. The status grammar remains `$zcode:status [job-id] [--wait] [--timeout-ms <milliseconds>] [--all]`: there is no `--log` option or log-reading command. Logs use the existing durable retention and remain after uninstall or selective runtime cleanup; there is no rotation, expiry, pruning, per-log delete, export, or search. They are deleted only by proven plugin-owned workspace-data erasure.
124+
120125
Background jobs have a separate lifecycle: ending the launching foreground command or Codex turn does not automatically cancel them. Use `$zcode:status <job-id>` to inspect one and `$zcode:cancel <job-id>` for explicit cancellation; ownership remains limited to the Codex session that reserved the job.
121126

122127
On supported foreground paths, `SIGINT` and `SIGTERM` are observed at safe protocol boundaries. Before a ZCode session exists, interruption cancels the queued reservation. Once the exact persisted ZCode session ID exists, the plugin sends `session/stop` only for that session. A confirmed stop durably marks the job cancelled; if `session/stop` fails or times out, the job remains running with the cancellation error available through status so cancellation can be retried. This is intentionally a session-level boundary: the plugin does not claim to stop or kill arbitrary detached grandchildren created by ZCode or nested tools.

README.zh-CN.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Setup 会把以下 schema 写入 `$CODEX_HOME/plugins/data/zcode-<marketplace>/w
103103

104104
`SessionEnd` 会对结束会话的可写 Rescue 执行 best-effort 结算。已 claim 的 queued reservation 在其 worker lease 仍被持有时保持不变。若进程在结算完成前退出,后续 Rescue 会执行预留时的崩溃回退,并可结算可证明的孤儿可写 job;结算不会转移 ownership,仍只有原 owner 能读取其结果。在这个预留时的崩溃回退中,仍被持有的精确 worker lease 会保留 writable guard。当精确 worker lease 已释放且现存 broker 控制通道不可用时,`SessionEnd` 或下一次 Rescue 会把孤儿归档为 `failed` 并释放 writable guard。这表示插件放弃追踪,不代表远端停止已确认。broker 仍可连接时,未确认的 `session/stop` 仍会保留 writable guard。其他会话只能通过 `$zcode:status --all` 查看脱敏后的 workspace 信息。
105105

106-
前台运行会把 ZCode 活动流式显示在当前终端。如果没有新活动,则每 20 秒输出一次心跳,让耗时较长的模型请求或工具调用仍然可见。同一份安全活动也会持久化到 job`$zcode:status <job-id>` 会显示阶段、最后活动时间和近期进度预览。例如:
106+
前台运行会把 ZCode 活动流式显示在当前终端。如果没有新活动,则每 20 秒输出一次心跳,让耗时较长的模型请求或工具调用仍然可见。现有有界 pipeline 成功派发的每个已接受安全语义进度事件,也会追加到私有、持久、便于人阅读的 `workspaces/<workspace-hash>/jobs/<job-id>.log`,它与 `<job-id>.json` 相邻;job 的 `progressPreview` 仍只保留最近 4 条。精确 owner 的详细 `$zcode:status <job-id>` 会显示进度预览、阶段和最后活动时间,以及 `Log: <absolute-private-path>`。例如:
107107

108108
```text
109109
$zcode:rescue --wait 修复失败的测试
@@ -115,8 +115,13 @@ Status: running
115115
Phase: running
116116
Progress:
117117
- ZCode started a tool call.
118+
Log: <absolute-private-path>
118119
```
119120

121+
每个 job 的日志还可以保存由现有精确 linkage 规则选出的当前 turn 的可见 assistant 文本,以及权威最终输出。原始命令 stdout/stderr、任意工具 payload(input/output/error/metadata)、原始推理、文件或 patch 内容、环境值、凭据、capabilities 和隐藏消息绝不直接摄取为日志源字段。此 allowlist 不是语义秘密脱敏边界:如果可见 assistant 或最终文本本身引用或转述了敏感材料,被选中的文本仍会保留。请勿让秘密进入可见模型文本,并相应保护私有日志。日志与进度只具观察性,不能建立或改变终态权威。
122+
123+
只有精确 owner 的详细 status 会暴露私有路径。紧凑列表、外部 `--all` 投影、同级 sibling session、绑定的 Rescue status sidecar、Root relay 和终态通知都不会暴露 `logFile` 或日志路径。status 语法仍为 `$zcode:status [job-id] [--wait] [--timeout-ms <milliseconds>] [--all]`:不提供 `--log` 选项或日志读取命令。日志沿用现有持久保留策略,在卸载或选择性 runtime 清理后仍保留;没有日志轮转、过期、裁剪、逐日志删除、导出或搜索功能。仅在删除已证明属于本插件的工作区数据时才删除这些日志。
124+
120125
后台任务有独立生命周期:启动它的前台命令或 Codex turn 结束时,后台任务不会自动取消。用 `$zcode:status <job-id>` 查看,用 `$zcode:cancel <job-id>` 显式取消;ownership 仍只属于预留该 job 的 Codex session。
121126

122127
在支持的前台路径上,插件会在安全协议边界处理 `SIGINT``SIGTERM`。ZCode session 尚未建立时,中断会取消排队中的预留;精确持久化的 ZCode session ID 一旦存在,插件只会对该 session 发送 `session/stop`。停止得到确认后,job 会持久标记为 cancelled;如果 `session/stop` 失败或超时,job 会保持 running,并通过 status 暴露取消错误,以便重试取消。这是刻意限定的 session 级边界:插件不声称停止或杀死 ZCode 或嵌套工具创建的任意 detached grandchildren。

SECURITY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Report suspected vulnerabilities privately through GitHub's private vulnerabilit
1313
- The digest-backed managed Role is owned only when its stable-data receipt, file bytes and SHA-256, selected config target, and exact Codex registration agree. Installation, migration, and manual cleanup fail closed when that receipt proof is incomplete. Never overwrite or delete foreign registrations, project Roles, higher-precedence overrides, or modified Role files.
1414
- The named child and Codex 0.147 generic compatibility child rely on exact host-issued thread identity inside the private same-UID data boundary. This prevents accidental sibling reuse; it is not a cryptographic boundary against a hostile process running as the same operating-system user.
1515
- Semantic progress is an allowlist over untrusted conversation frames. A command or query preview is one control-free line with a 96-character display bound, but truncation is not secret redaction. Never place credentials or authorization material in commands or searches; raw output, file contents, reasoning, and environment values are not allowed progress fields.
16+
- A private durable per-job log contains every accepted safe semantic progress event successfully dispatched by that bounded allowlist and may also contain current-turn visible assistant text selected by the exact existing linkage rules and authoritative final output. Raw command stdout/stderr, arbitrary tool payloads (input/output/errors/metadata), raw reasoning, file or patch contents, environment values, credentials, capabilities, and hidden messages are never directly ingested as log source fields. The log is not a semantic secret-redaction boundary: if visible assistant or final text itself quotes or paraphrases sensitive material, that selected text is retained. Keep secrets out of visible model text and protect the private log accordingly. The log is observational and cannot establish or alter terminal authority. Its absolute path is disclosed only by exact-owner detailed status, never by compact or foreign projections, sibling sessions, sidecars, relays, or terminal notices.
1617
- Child stderr and detailed progress stay in the child thread. Parent-visible output is limited to host lifecycle events and the final public result. Subscription or optional progress-sink failure is observational and cannot weaken the authoritative completion guard.
1718
- Rescue task material exists in the routing rollout only as the Root parent's single LF-terminated JSON line sent through `write_stdin` to `prepare rescue`. The companion requires a raw-capable TTY and enables raw mode before emitting task-free readiness and before accepting any task bytes; readiness is nonterminal. Root sends no EOF or U+0004. Non-TTY/readiness/raw-mode failure stops before delivery. Tool output must never contain or echo the payload. Prepared state is bound to the exact Codex session, initiating turn, canonical workspace, and executor identity; it is single consume, has a bounded expiry, and is subject to private-state cleanup. The task, source, and options must never appear in argv, environment variables, output, logs, artifacts, relays, status, task names, or any child assignment/transcript. Named and generic children are task-blind and capability-free and receive only the constant `invoke-prepared rescue` assignment.
1819
- A durable Rescue binding authorizes the same stopped child to continue only its exact ZCode session. The private `anchorJobId` and `currentJobId` remain inside protected plugin state and never cross the parent-to-child message boundary. Missing, closed, corrupt, permission-incompatible, workspace-mismatched, executor-mismatched, or provenance-inconsistent bindings fail closed.

docs/manual-uninstall.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Durable jobs and their history are retained by default so results and diagnostic
4242

4343
- `jobs/`, `job-owners/`, and `job-specs/` job records;
4444
- `prompts/` and `results/` artifacts;
45-
- persisted progress previews inside job records, plus diagnostic logs/history represented by those records and artifacts; and
45+
- persisted progress previews inside job records and private durable `jobs/<job-id>.log` history files; each log is retained after uninstall and selective runtime cleanup; and
4646
- `config/models.json` workspace model policy, if it should be retained for a later reinstall.
4747

4848
## Selective runtime-state cleanup while retaining history
@@ -60,6 +60,8 @@ Deleting these paths disables authorization, recovery, notification, broker cont
6060

6161
For full data erasure, after jobs are settled and after making any required backup, you may additionally remove the proven plugin-owned workspace directories under `<plugin-data-root>/workspaces/`. Removing a whole workspace directory permanently deletes its prompts, results, progress, logs/history, model policy, job ownership, and recovery evidence. Remove the plugin-data root itself only after proving it is the ZCode marketplace namespace and contains no data you want to retain.
6262

63+
A `jobs/<job-id>.log` is deleted only by proven plugin-owned workspace-data erasure as described above. There is no separate per-log deletion or cleanup path.
64+
6365
---
6466

6567
# 卸载后的手动清理
@@ -106,7 +108,7 @@ Setup 还可能在选定的 Codex user configuration 中留下:
106108

107109
- `jobs/``job-owners/``job-specs/` 任务记录;
108110
- `prompts/``results/` artifact;
109-
- job 记录中的持久 progress preview,以及这些记录和 artifact 所代表的诊断 logs/history
111+
- job 记录中的持久 progress preview,以及私有持久 `jobs/<job-id>.log` 历史文件;每份日志在卸载和选择性清理后仍保留
110112
- 如需供以后重新安装使用,可保留 `config/models.json` 工作区 model policy。
111113

112114
## 保留历史时选择性清理运行状态
@@ -123,3 +125,5 @@ Setup 还可能在选定的 Codex user configuration 中留下:
123125
删除这些路径会同时删除其代表的 authorization、恢复、通知、broker 控制和 review-gate 连续性。只有在活动已经明确结算后才执行这种选择性清理。
124126

125127
如果需要彻底清除数据,请先结束任务并完成必要备份,然后可以额外移除 `<plugin-data-root>/workspaces/` 下已证明属于本插件的工作区目录。删除整个工作区目录会永久删除其中的 prompts、results、progress、logs/history、model policy、job ownership 与恢复证据。仅当确认整个 plugin-data root 是 ZCode 的 marketplace namespace,且其中没有需要保留的数据时,才移除该根目录。
128+
129+
`jobs/<job-id>.log` 仅在删除已证明属于本插件的工作区数据时才删除;不存在单独逐日志删除或清理路径。

0 commit comments

Comments
 (0)