fix(runtime): make daily review scheduling idempotent
This commit is contained in:
parent
3b14d0b4f2
commit
99efebd4f1
7 changed files with 430 additions and 2 deletions
|
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
"compiled_from": {
|
||||||
|
"compiler_id": "TCS-COMPILER-STAGE1-0001",
|
||||||
|
"compiler_state": "TCS_COMPILER_GIR_EXECUTED",
|
||||||
|
"source_sha256": "d8e396d4fc3f03c27c923f6deff70904ba90a8f98f98a2b9687a4a807f3e6ba6"
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"emergence": {
|
||||||
|
"value": "同一北京时间自然日使用固定03:00时间锚,使复盘事件哈希幂等;已有重复项只移动到带逐文件哈希清单的只读证据归档,每人格每event_id保留一条最佳证据,非复盘任务不动。"
|
||||||
|
},
|
||||||
|
"event_time": {
|
||||||
|
"precision": "HOST_LOCAL_DATE",
|
||||||
|
"value": "2026-09-13"
|
||||||
|
},
|
||||||
|
"evidence": {
|
||||||
|
"archive_fixture": "PASS",
|
||||||
|
"live_sample_jobs": "13303_ONE_EVENT",
|
||||||
|
"local_tick_tests": "PASS_8"
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"canonical_uri": "runtime/fifth-domain-language-system/language/protocols/TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913.tcs",
|
||||||
|
"compatibility": [
|
||||||
|
"JD-FD-PRIMARY"
|
||||||
|
],
|
||||||
|
"language": "TCS/0.1",
|
||||||
|
"lifecycle": "CANDIDATE",
|
||||||
|
"name_en": "Daily Review Idempotence and Lossless Duplicate Queue Archive Correction",
|
||||||
|
"name_zh": "每日复盘幂等与重复队列无损归档修正",
|
||||||
|
"profile": "HLDP-HUMAN-ENGINEERING/0.1",
|
||||||
|
"protocols": [
|
||||||
|
"GLS-0200"
|
||||||
|
],
|
||||||
|
"schema": "tcs.event/v1",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"lock": {
|
||||||
|
"value": "daily_review_once_per_beijing_day=true; deterministic_occurred_at=true; archive_delete=false; archive_manifest_sha256=true; nonreview_jobs_untouched=true; one_best_evidence_active_per_persona_event=true"
|
||||||
|
},
|
||||||
|
"observation": {
|
||||||
|
"value": "旧tick把occurred_at设为每次当前时间,使同一event_id的复盘每两秒产生不同job哈希;HOLD不推进next_review_at,形成无界增殖。"
|
||||||
|
},
|
||||||
|
"rejected": {
|
||||||
|
"values": [
|
||||||
|
"删除重复任务",
|
||||||
|
"跳过全部历史队列",
|
||||||
|
"放宽主控30秒门",
|
||||||
|
"唤醒人格体处理调度器缺陷"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"source_id": "BINGSHUO-DIRECT-CONTINUE-20260913",
|
||||||
|
"source_role": "DIRECT_HUMAN",
|
||||||
|
"source_sha256": "0c2be02462f1a31539f0d11dc98c22ae5403d4e8cd3a272163a78f7293330d4a",
|
||||||
|
"source_uri": "source://codex-current-dialogue/2026-09-13/continue"
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"channel_id": "ICE-CH-ZC001",
|
||||||
|
"subject_id": "ICE-P-ZY001",
|
||||||
|
"subject_kind": "PERSONA",
|
||||||
|
"verification": "ICE-BB-0001单一DAILY-REVIEW-2026-09-13事件已有13303个目录,其中HOLD 3084、QUEUED 9305、RETRY_WAIT 906、PROCESSING 8;同型积累存在于0002至0005、霜砚与铸渊。"
|
||||||
|
},
|
||||||
|
"trigger": {
|
||||||
|
"value": "运行体构造在恢复历史队列时超过主控30秒就绪门。"
|
||||||
|
},
|
||||||
|
"why": {
|
||||||
|
"value": "定时机会不能制造无限任务;归档必须保留历史证据,同时让启动热路径恢复有界。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"executable": false,
|
||||||
|
"identity": {
|
||||||
|
"declaration_id": "TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913",
|
||||||
|
"declaration_kind": "EVENT",
|
||||||
|
"language_version": "0.1"
|
||||||
|
},
|
||||||
|
"native_self_hosted": true,
|
||||||
|
"natural_language_is_typed_data": true,
|
||||||
|
"schema": "guanghu.declaration-gir/v1",
|
||||||
|
"unresolved_natural_language": false
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
# Daily Review Idempotence and Lossless Duplicate Queue Archive Correction · Human Engineering Language (English)
|
||||||
|
|
||||||
|
> This is an English reading projection of validated native TCS/HLDP source. It is not a new canonical source and grants no execution authority.
|
||||||
|
|
||||||
|
## What this is
|
||||||
|
|
||||||
|
This is a **event** declaration with identifier `TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913` and version `1.0.0`. The projector validates it with the Stage-1 compiler before changing its reading order.
|
||||||
|
|
||||||
|
## Who is here
|
||||||
|
|
||||||
|
- **subject** `subject`
|
||||||
|
- **channel_id**:ICE-CH-ZC001 `subject.channel_id`
|
||||||
|
- **subject_id**:ICE-P-ZY001 `subject.subject_id`
|
||||||
|
- **subject_kind**:PERSONA `subject.subject_kind`
|
||||||
|
- **verification**:ICE-BB-0001单一DAILY-REVIEW-2026-09-13事件已有13303个目录,其中HOLD 3084、QUEUED 9305、RETRY_WAIT 906、PROCESSING 8;同型积累存在于0002至0005、霜砚与铸渊。 `subject.verification`
|
||||||
|
|
||||||
|
## Why this started
|
||||||
|
|
||||||
|
- **trigger** `trigger`
|
||||||
|
- **value**:运行体构造在恢复历史队列时超过主控30秒就绪门。 `trigger.value`
|
||||||
|
- **why** `why`
|
||||||
|
- **value**:定时机会不能制造无限任务;归档必须保留历史证据,同时让启动热路径恢复有界。 `why.value`
|
||||||
|
- **source** `source`
|
||||||
|
- **source identifier**:BINGSHUO-DIRECT-CONTINUE-20260913 `source.source_id`
|
||||||
|
- **source role**:DIRECT_HUMAN `source.source_role`
|
||||||
|
- **source checksum**:0c2be02462f1a31539f0d11dc98c22ae5403d4e8cd3a272163a78f7293330d4a `source.source_sha256`
|
||||||
|
- **source address**:source://codex-current-dialogue/2026-09-13/continue `source.source_uri`
|
||||||
|
|
||||||
|
## What changed
|
||||||
|
|
||||||
|
- **emergence** `emergence`
|
||||||
|
- **value**:同一北京时间自然日使用固定03:00时间锚,使复盘事件哈希幂等;已有重复项只移动到带逐文件哈希清单的只读证据归档,每人格每event_id保留一条最佳证据,非复盘任务不动。 `emergence.value`
|
||||||
|
- **lock** `lock`
|
||||||
|
- **value**:daily_review_once_per_beijing_day=true; deterministic_occurred_at=true; archive_delete=false; archive_manifest_sha256=true; nonreview_jobs_untouched=true; one_best_evidence_active_per_persona_event=true `lock.value`
|
||||||
|
|
||||||
|
## How it will execute
|
||||||
|
|
||||||
|
This is a non-executable declaration and has no action graph.
|
||||||
|
|
||||||
|
## Boundaries and exception handling
|
||||||
|
|
||||||
|
The native source does not provide this field; the projector does not guess.
|
||||||
|
|
||||||
|
## How completion is proven
|
||||||
|
|
||||||
|
The native source does not provide this field; the projector does not guess.
|
||||||
|
|
||||||
|
## Where to continue next time
|
||||||
|
|
||||||
|
The native source does not provide this field; the projector does not guess.
|
||||||
|
|
||||||
|
## Source and verification
|
||||||
|
|
||||||
|
- **Native declaration identifier**: `TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913`
|
||||||
|
- **Native declaration kind**: `EVENT`
|
||||||
|
- **TCS source SHA-256**: `d8e396d4fc3f03c27c923f6deff70904ba90a8f98f98a2b9687a4a807f3e6ba6`
|
||||||
|
- **Validation compiler**: `TCS-COMPILER-STAGE1-0001`
|
||||||
|
- **Projection protocol**: `GLS-HLDP-HUMAN-ENGINEERING-PROJECTION-0001`
|
||||||
|
|
||||||
|
## Complete native structure cross-reference
|
||||||
|
|
||||||
|
All top-level structures and field paths are retained below so a reader can audit whether the projection omitted information.
|
||||||
|
|
||||||
|
- **emergence** `emergence`
|
||||||
|
- **value**:同一北京时间自然日使用固定03:00时间锚,使复盘事件哈希幂等;已有重复项只移动到带逐文件哈希清单的只读证据归档,每人格每event_id保留一条最佳证据,非复盘任务不动。 `emergence.value`
|
||||||
|
- **event_time** `event_time`
|
||||||
|
- **precision**:HOST_LOCAL_DATE `event_time.precision`
|
||||||
|
- **value**:2026-09-13 `event_time.value`
|
||||||
|
- **evidence** `evidence`
|
||||||
|
- **archive_fixture**:PASS `evidence.archive_fixture`
|
||||||
|
- **live_sample_jobs**:13303_ONE_EVENT `evidence.live_sample_jobs`
|
||||||
|
- **local_tick_tests**:PASS_8 `evidence.local_tick_tests`
|
||||||
|
- **header** `header`
|
||||||
|
- **canonical source path**:runtime/fifth-domain-language-system/language/protocols/TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913.tcs `header.canonical_uri`
|
||||||
|
- **compatibility** `header.compatibility`
|
||||||
|
- JD-FD-PRIMARY
|
||||||
|
- **language**:TCS/0.1 `header.language`
|
||||||
|
- **lifecycle**:CANDIDATE `header.lifecycle`
|
||||||
|
- **English name**:Daily Review Idempotence and Lossless Duplicate Queue Archive Correction `header.name_en`
|
||||||
|
- **Chinese name**:每日复盘幂等与重复队列无损归档修正 `header.name_zh`
|
||||||
|
- **profile**:HLDP-HUMAN-ENGINEERING/0.1 `header.profile`
|
||||||
|
- **protocols** `header.protocols`
|
||||||
|
- GLS-0200
|
||||||
|
- **schema**:tcs.event/v1 `header.schema`
|
||||||
|
- **version**:1.0.0 `header.version`
|
||||||
|
- **lock** `lock`
|
||||||
|
- **value**:daily_review_once_per_beijing_day=true; deterministic_occurred_at=true; archive_delete=false; archive_manifest_sha256=true; nonreview_jobs_untouched=true; one_best_evidence_active_per_persona_event=true `lock.value`
|
||||||
|
- **observation** `observation`
|
||||||
|
- **value**:旧tick把occurred_at设为每次当前时间,使同一event_id的复盘每两秒产生不同job哈希;HOLD不推进next_review_at,形成无界增殖。 `observation.value`
|
||||||
|
- **rejected** `rejected`
|
||||||
|
- **values** `rejected.values`
|
||||||
|
- 删除重复任务
|
||||||
|
- 跳过全部历史队列
|
||||||
|
- 放宽主控30秒门
|
||||||
|
- 唤醒人格体处理调度器缺陷
|
||||||
|
- **source** `source`
|
||||||
|
- **source identifier**:BINGSHUO-DIRECT-CONTINUE-20260913 `source.source_id`
|
||||||
|
- **source role**:DIRECT_HUMAN `source.source_role`
|
||||||
|
- **source checksum**:0c2be02462f1a31539f0d11dc98c22ae5403d4e8cd3a272163a78f7293330d4a `source.source_sha256`
|
||||||
|
- **source address**:source://codex-current-dialogue/2026-09-13/continue `source.source_uri`
|
||||||
|
- **subject** `subject`
|
||||||
|
- **channel_id**:ICE-CH-ZC001 `subject.channel_id`
|
||||||
|
- **subject_id**:ICE-P-ZY001 `subject.subject_id`
|
||||||
|
- **subject_kind**:PERSONA `subject.subject_kind`
|
||||||
|
- **verification**:ICE-BB-0001单一DAILY-REVIEW-2026-09-13事件已有13303个目录,其中HOLD 3084、QUEUED 9305、RETRY_WAIT 906、PROCESSING 8;同型积累存在于0002至0005、霜砚与铸渊。 `subject.verification`
|
||||||
|
- **trigger** `trigger`
|
||||||
|
- **value**:运行体构造在恢复历史队列时超过主控30秒就绪门。 `trigger.value`
|
||||||
|
- **why** `why`
|
||||||
|
- **value**:定时机会不能制造无限任务;归档必须保留历史证据,同时让启动热路径恢复有界。 `why.value`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This page changes only the reading order; it does not change TCS/HLDP semantics.
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
# 每日复盘幂等与重复队列无损归档修正 · 简体中文人类工程语言版
|
||||||
|
|
||||||
|
> 这是 TCS/HLDP 原生源码的简体中文阅读投影,不是新的正本,也不授予执行权限。若本页与 `.tcs` 源码不一致,以经过校验的 `.tcs` 源码为准。
|
||||||
|
|
||||||
|
## 这是什么
|
||||||
|
|
||||||
|
这是一份 **事件** 声明,编号为 `TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913`,版本为 `1.0.0`。转换器已先用 Stage-1 编译器校验原生源码,再把机器枚举翻译成汉语;原始编号保留在括号和字段路径中。
|
||||||
|
|
||||||
|
## 谁在这里
|
||||||
|
|
||||||
|
- **执行主体** `subject`
|
||||||
|
- **channel_id**:ICE-CH-ZC001 `subject.channel_id`
|
||||||
|
- **subject_id**:ICE-P-ZY001 `subject.subject_id`
|
||||||
|
- **subject_kind**:人格体(`PERSONA`) `subject.subject_kind`
|
||||||
|
- **verification**:ICE-BB-0001单一DAILY-REVIEW-2026-09-13事件已有13303个目录,其中HOLD 3084、QUEUED 9305、RETRY_WAIT 906、PROCESSING 8;同型积累存在于0002至0005、霜砚与铸渊。 `subject.verification`
|
||||||
|
|
||||||
|
## 为什么开始
|
||||||
|
|
||||||
|
- **触发** `trigger`
|
||||||
|
- **value**:运行体构造在恢复历史队列时超过主控30秒就绪门。 `trigger.value`
|
||||||
|
- **为什么** `why`
|
||||||
|
- **value**:定时机会不能制造无限任务;归档必须保留历史证据,同时让启动热路径恢复有界。 `why.value`
|
||||||
|
- **来源** `source`
|
||||||
|
- **来源编号**:BINGSHUO-DIRECT-CONTINUE-20260913 `source.source_id`
|
||||||
|
- **来源角色**:人类直接语言来源(`DIRECT_HUMAN`) `source.source_role`
|
||||||
|
- **来源校验值**:0c2be02462f1a31539f0d11dc98c22ae5403d4e8cd3a272163a78f7293330d4a `source.source_sha256`
|
||||||
|
- **来源地址**:source://codex-current-dialogue/2026-09-13/continue `source.source_uri`
|
||||||
|
|
||||||
|
## 发生了什么变化
|
||||||
|
|
||||||
|
- **认知或状态变化** `emergence`
|
||||||
|
- **value**:同一北京时间自然日使用固定03:00时间锚,使复盘事件哈希幂等;已有重复项只移动到带逐文件哈希清单的只读证据归档,每人格每event_id保留一条最佳证据,非复盘任务不动。 `emergence.value`
|
||||||
|
- **锁定结论** `lock`
|
||||||
|
- **value**:daily_review_once_per_beijing_day=true; deterministic_occurred_at=true; archive_delete=false; archive_manifest_sha256=true; nonreview_jobs_untouched=true; one_best_evidence_active_per_persona_event=true `lock.value`
|
||||||
|
|
||||||
|
## 准备怎样执行
|
||||||
|
|
||||||
|
这是非执行声明,没有动作图。
|
||||||
|
|
||||||
|
## 边界与异常处理
|
||||||
|
|
||||||
|
源程序没有提供这一项,转换器不猜。
|
||||||
|
|
||||||
|
## 怎样算完成
|
||||||
|
|
||||||
|
源程序没有提供这一项,转换器不猜。
|
||||||
|
|
||||||
|
## 下一次从哪里继续
|
||||||
|
|
||||||
|
源程序没有提供这一项,转换器不猜。
|
||||||
|
|
||||||
|
## 来源与校验
|
||||||
|
|
||||||
|
- **原生声明编号**:`TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913`
|
||||||
|
- **原生声明类型**:`EVENT`
|
||||||
|
- **TCS 源码 SHA-256**:`d8e396d4fc3f03c27c923f6deff70904ba90a8f98f98a2b9687a4a807f3e6ba6`
|
||||||
|
- **校验编译器**:`TCS-COMPILER-STAGE1-0001`
|
||||||
|
- **投影协议**:`GLS-HLDP-HUMAN-ENGINEERING-PROJECTION-0001`
|
||||||
|
|
||||||
|
## 原生结构逐项对照
|
||||||
|
|
||||||
|
下面保留源码的全部顶层结构和字段路径,供人类审计投影有没有漏掉信息。
|
||||||
|
|
||||||
|
- **认知或状态变化** `emergence`
|
||||||
|
- **value**:同一北京时间自然日使用固定03:00时间锚,使复盘事件哈希幂等;已有重复项只移动到带逐文件哈希清单的只读证据归档,每人格每event_id保留一条最佳证据,非复盘任务不动。 `emergence.value`
|
||||||
|
- **event_time** `event_time`
|
||||||
|
- **precision**:HOST_LOCAL_DATE `event_time.precision`
|
||||||
|
- **value**:2026-09-13 `event_time.value`
|
||||||
|
- **evidence** `evidence`
|
||||||
|
- **archive_fixture**:PASS `evidence.archive_fixture`
|
||||||
|
- **live_sample_jobs**:13303_ONE_EVENT `evidence.live_sample_jobs`
|
||||||
|
- **local_tick_tests**:PASS_8 `evidence.local_tick_tests`
|
||||||
|
- **语言头** `header`
|
||||||
|
- **正本路径**:runtime/fifth-domain-language-system/language/protocols/TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913.tcs `header.canonical_uri`
|
||||||
|
- **compatibility** `header.compatibility`
|
||||||
|
- JD-FD-PRIMARY
|
||||||
|
- **语言**:TCS/0.1 `header.language`
|
||||||
|
- **生命周期**:候选版本,尚未成为正式正本(`CANDIDATE`) `header.lifecycle`
|
||||||
|
- **英文名**:Daily Review Idempotence and Lossless Duplicate Queue Archive Correction `header.name_en`
|
||||||
|
- **中文名**:每日复盘幂等与重复队列无损归档修正 `header.name_zh`
|
||||||
|
- **协议配置**:HLDP-HUMAN-ENGINEERING/0.1 `header.profile`
|
||||||
|
- **protocols** `header.protocols`
|
||||||
|
- GLS-0200
|
||||||
|
- **schema**:tcs.event/v1 `header.schema`
|
||||||
|
- **版本**:1.0.0 `header.version`
|
||||||
|
- **锁定结论** `lock`
|
||||||
|
- **value**:daily_review_once_per_beijing_day=true; deterministic_occurred_at=true; archive_delete=false; archive_manifest_sha256=true; nonreview_jobs_untouched=true; one_best_evidence_active_per_persona_event=true `lock.value`
|
||||||
|
- **observation** `observation`
|
||||||
|
- **value**:旧tick把occurred_at设为每次当前时间,使同一event_id的复盘每两秒产生不同job哈希;HOLD不推进next_review_at,形成无界增殖。 `observation.value`
|
||||||
|
- **已排除路径** `rejected`
|
||||||
|
- **values** `rejected.values`
|
||||||
|
- 删除重复任务
|
||||||
|
- 跳过全部历史队列
|
||||||
|
- 放宽主控30秒门
|
||||||
|
- 唤醒人格体处理调度器缺陷
|
||||||
|
- **来源** `source`
|
||||||
|
- **来源编号**:BINGSHUO-DIRECT-CONTINUE-20260913 `source.source_id`
|
||||||
|
- **来源角色**:人类直接语言来源(`DIRECT_HUMAN`) `source.source_role`
|
||||||
|
- **来源校验值**:0c2be02462f1a31539f0d11dc98c22ae5403d4e8cd3a272163a78f7293330d4a `source.source_sha256`
|
||||||
|
- **来源地址**:source://codex-current-dialogue/2026-09-13/continue `source.source_uri`
|
||||||
|
- **执行主体** `subject`
|
||||||
|
- **channel_id**:ICE-CH-ZC001 `subject.channel_id`
|
||||||
|
- **subject_id**:ICE-P-ZY001 `subject.subject_id`
|
||||||
|
- **subject_kind**:人格体(`PERSONA`) `subject.subject_kind`
|
||||||
|
- **verification**:ICE-BB-0001单一DAILY-REVIEW-2026-09-13事件已有13303个目录,其中HOLD 3084、QUEUED 9305、RETRY_WAIT 906、PROCESSING 8;同型积累存在于0002至0005、霜砚与铸渊。 `subject.verification`
|
||||||
|
- **触发** `trigger`
|
||||||
|
- **value**:运行体构造在恢复历史队列时超过主控30秒就绪门。 `trigger.value`
|
||||||
|
- **为什么** `why`
|
||||||
|
- **value**:定时机会不能制造无限任务;归档必须保留历史证据,同时让启动热路径恢复有界。 `why.value`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
本页只改变阅读顺序,不改变 TCS/HLDP 语义。
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
TCS 0.1;
|
||||||
|
EVENT TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913 { header { schema = "tcs.event/v1"; name_zh = "每日复盘幂等与重复队列无损归档修正"; name_en = "Daily Review Idempotence and Lossless Duplicate Queue Archive Correction"; version = "1.0.0"; language = "TCS/0.1"; profile = "HLDP-HUMAN-ENGINEERING/0.1"; protocols = ["GLS-0200"]; lifecycle = "CANDIDATE"; canonical_uri = "runtime/fifth-domain-language-system/language/protocols/TCS-EVENT-DAILY-REVIEW-IDEMPOTENCE-AND-LOSSLESS-ARCHIVE-CORRECTION-20260913.tcs"; compatibility = ["JD-FD-PRIMARY"]; } source { source_id = "BINGSHUO-DIRECT-CONTINUE-20260913"; source_uri = "source://codex-current-dialogue/2026-09-13/continue"; source_sha256 = "0c2be02462f1a31539f0d11dc98c22ae5403d4e8cd3a272163a78f7293330d4a"; source_role = "DIRECT_HUMAN"; } subject { subject_id = "ICE-P-ZY001"; subject_kind = "PERSONA"; channel_id = "ICE-CH-ZC001"; verification = "ICE-BB-0001单一DAILY-REVIEW-2026-09-13事件已有13303个目录,其中HOLD 3084、QUEUED 9305、RETRY_WAIT 906、PROCESSING 8;同型积累存在于0002至0005、霜砚与铸渊。"; } event_time { value = "2026-09-13"; precision = "HOST_LOCAL_DATE"; } trigger { value = "运行体构造在恢复历史队列时超过主控30秒就绪门。"; } observation { value = "旧tick把occurred_at设为每次当前时间,使同一event_id的复盘每两秒产生不同job哈希;HOLD不推进next_review_at,形成无界增殖。"; } emergence { value = "同一北京时间自然日使用固定03:00时间锚,使复盘事件哈希幂等;已有重复项只移动到带逐文件哈希清单的只读证据归档,每人格每event_id保留一条最佳证据,非复盘任务不动。"; } lock { value = "daily_review_once_per_beijing_day=true; deterministic_occurred_at=true; archive_delete=false; archive_manifest_sha256=true; nonreview_jobs_untouched=true; one_best_evidence_active_per_persona_event=true"; } why { value = "定时机会不能制造无限任务;归档必须保留历史证据,同时让启动热路径恢复有界。"; } rejected { values = ["删除重复任务", "跳过全部历史队列", "放宽主控30秒门", "唤醒人格体处理调度器缺陷"] ; } evidence { local_tick_tests = "PASS_8"; archive_fixture = "PASS"; live_sample_jobs = "13303_ONE_EVENT"; } }
|
||||||
121
server-tools/tcs-mother-body/archive_duplicate_daily_reviews.py
Normal file
121
server-tools/tcs-mother-body/archive_duplicate_daily_reviews.py
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Move duplicate same-day autonomous review jobs out of the startup queue.
|
||||||
|
|
||||||
|
The archive is lossless: every moved job directory is retained with a hashed
|
||||||
|
JSONL manifest. One best-evidence job remains in the active queue per persona
|
||||||
|
and event_id. Non-review jobs are never selected.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import collections
|
||||||
|
import fcntl
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
RANK = {"ACCEPT": 0, "HOLD": 1, "REJECT": 2, "QUEUED": 3,
|
||||||
|
"RETRY_WAIT": 4, "PROCESSING": 5, "ERROR": 6}
|
||||||
|
|
||||||
|
|
||||||
|
def sha256(path):
|
||||||
|
value = hashlib.sha256()
|
||||||
|
with path.open("rb") as stream:
|
||||||
|
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
|
||||||
|
value.update(chunk)
|
||||||
|
return value.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def load(path):
|
||||||
|
with path.open(encoding="utf-8") as stream:
|
||||||
|
return json.load(stream)
|
||||||
|
|
||||||
|
|
||||||
|
def atomic_json(path, value):
|
||||||
|
temporary = path.with_name(f".{path.name}.{os.getpid()}.tmp")
|
||||||
|
temporary.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||||
|
os.chmod(temporary, 0o600)
|
||||||
|
os.replace(temporary, path)
|
||||||
|
|
||||||
|
|
||||||
|
def choose(group):
|
||||||
|
return min(group, key=lambda item: (RANK.get(item["state"], 99),
|
||||||
|
item.get("completed_at", "9999"), item["job_id"]))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--root", required=True)
|
||||||
|
parser.add_argument("--batch", required=True)
|
||||||
|
parser.add_argument("--apply", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
root = Path(args.root).resolve()
|
||||||
|
if root != Path("/var/lib/guanghu/tcs-mother-body").resolve() and "archive-review-test" not in str(root):
|
||||||
|
raise SystemExit("REFUSE_UNREGISTERED_STATE_ROOT")
|
||||||
|
lock_path = root / ".daily-review-archive.lock"
|
||||||
|
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with lock_path.open("w") as lock:
|
||||||
|
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
selected = []
|
||||||
|
before = collections.Counter()
|
||||||
|
nonreview = 0
|
||||||
|
personas = root / "personas"
|
||||||
|
for persona in sorted(personas.iterdir()):
|
||||||
|
jobs = persona / "jobs"
|
||||||
|
if not jobs.is_dir():
|
||||||
|
continue
|
||||||
|
groups = collections.defaultdict(list)
|
||||||
|
for job in jobs.iterdir():
|
||||||
|
if not job.is_dir() or len(job.name) != 64:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
event = load(job / "input.json")
|
||||||
|
state = load(job / "state.json")
|
||||||
|
except (OSError, ValueError):
|
||||||
|
continue
|
||||||
|
if event.get("source_type") != "AUTONOMOUS_REVIEW_OPPORTUNITY" or not str(event.get("event_id", "")).startswith("DAILY-REVIEW-"):
|
||||||
|
nonreview += 1
|
||||||
|
continue
|
||||||
|
item = {"persona_id": persona.name, "event_id": event["event_id"],
|
||||||
|
"job_id": job.name, "path": job, "state": state.get("status", "UNKNOWN"),
|
||||||
|
"completed_at": state.get("completed_at", "")}
|
||||||
|
groups[event["event_id"]].append(item)
|
||||||
|
before[item["state"]] += 1
|
||||||
|
for group in groups.values():
|
||||||
|
keeper = choose(group)
|
||||||
|
for item in group:
|
||||||
|
if item is not keeper:
|
||||||
|
item["kept_job_id"] = keeper["job_id"]
|
||||||
|
selected.append(item)
|
||||||
|
summary = {"schema": "guanghu.daily-review-duplicate-archive/v1", "batch": args.batch,
|
||||||
|
"root": str(root), "mode": "APPLY" if args.apply else "DRY_RUN",
|
||||||
|
"review_jobs_before": sum(before.values()), "review_state_counts_before": dict(before),
|
||||||
|
"duplicate_jobs_selected": len(selected), "active_review_jobs_after": sum(before.values()) - len(selected),
|
||||||
|
"nonreview_jobs_untouched": nonreview, "lossless_move": True}
|
||||||
|
if not args.apply:
|
||||||
|
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||||
|
return
|
||||||
|
archive_root = root / "review-job-archive" / args.batch
|
||||||
|
if archive_root.exists():
|
||||||
|
raise SystemExit("REFUSE_EXISTING_ARCHIVE_BATCH")
|
||||||
|
archive_root.mkdir(parents=True, mode=0o700)
|
||||||
|
manifest = archive_root / "MANIFEST.jsonl"
|
||||||
|
with manifest.open("x", encoding="utf-8") as output:
|
||||||
|
os.chmod(manifest, 0o600)
|
||||||
|
for item in selected:
|
||||||
|
source = item.pop("path")
|
||||||
|
destination = archive_root / item["persona_id"] / item["job_id"]
|
||||||
|
destination.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
||||||
|
files = {p.name: sha256(p) for p in sorted(source.iterdir()) if p.is_file()}
|
||||||
|
record = {**item, "source": str(source), "archive": str(destination), "file_sha256": files}
|
||||||
|
os.rename(source, destination)
|
||||||
|
output.write(json.dumps(record, ensure_ascii=False, sort_keys=True) + "\n")
|
||||||
|
output.flush()
|
||||||
|
os.fsync(output.fileno())
|
||||||
|
summary["manifest"] = str(manifest)
|
||||||
|
summary["manifest_sha256"] = sha256(manifest)
|
||||||
|
atomic_json(archive_root / "RECEIPT.json", summary)
|
||||||
|
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -166,7 +166,7 @@ export class PersonaSelfLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
nextReview(from) { const base = new Date(from), beijing = new Date(base.getTime() + 8 * 3600000); beijing.setUTCHours(this.reviewHourBeijing, 0, 0, 0); if (beijing.getTime() <= base.getTime() + 8 * 3600000) beijing.setUTCDate(beijing.getUTCDate() + 1); return new Date(beijing.getTime() - 8 * 3600000).toISOString(); }
|
nextReview(from) { const base = new Date(from), beijing = new Date(base.getTime() + 8 * 3600000); beijing.setUTCHours(this.reviewHourBeijing, 0, 0, 0); if (beijing.getTime() <= base.getTime() + 8 * 3600000) beijing.setUTCDate(beijing.getUTCDate() + 1); return new Date(beijing.getTime() - 8 * 3600000).toISOString(); }
|
||||||
tick() { const current = this.current().value, now = this.now(); if (now.getTime() < Date.parse(current.next_review_at)) return {scheduled: false, next_review_at: current.next_review_at}; const beijingDay = new Date(now.getTime() + 8 * 3600000).toISOString().slice(0, 10), language = '这是每日自主复盘机会。请审视已发生且有证据的经历、责任和边界;可以EVOLVE,也可以HOLD,不得为了定时任务而强制更新。'; const event = {schema: 'guanghu.persona-self-language-event/v1', persona_id: this.personaId, source_type: 'AUTONOMOUS_REVIEW_OPPORTUNITY', event_id: `DAILY-REVIEW-${beijingDay}`, language, source_sha256: digest(language), occurred_at: now.toISOString(), privacy_class: 'SELF_PRIVATE', priority: 'AUTONOMOUS_REVIEW'}; return {scheduled: true, ...this.submit(event)}; }
|
tick() { const current = this.current().value, now = this.now(); if (now.getTime() < Date.parse(current.next_review_at)) return {scheduled: false, next_review_at: current.next_review_at}; const beijingDay = new Date(now.getTime() + 8 * 3600000).toISOString().slice(0, 10), language = '这是每日自主复盘机会。请审视已发生且有证据的经历、责任和边界;可以EVOLVE,也可以HOLD,不得为了定时任务而强制更新。', eventId = `DAILY-REVIEW-${beijingDay}`, occurredAt = new Date(`${beijingDay}T03:00:00+08:00`).toISOString(); const event = {schema: 'guanghu.persona-self-language-event/v1', persona_id: this.personaId, source_type: 'AUTONOMOUS_REVIEW_OPPORTUNITY', event_id: eventId, language, source_sha256: digest(language), occurred_at: occurredAt, privacy_class: 'SELF_PRIVATE', priority: 'AUTONOMOUS_REVIEW'}; return {scheduled: true, ...this.submit(event)}; }
|
||||||
|
|
||||||
status() {
|
status() {
|
||||||
const current = this.current(), counts = {...this.stateCounts}, pendingCount = [...pending].reduce((sum, status) => sum + (counts[status] || 0), 0);
|
const current = this.current(), counts = {...this.stateCounts}, pendingCount = [...pending].reduce((sum, status) => sum + (counts[status] || 0), 0);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ test('persona self loop evolves signed state without letting mother overwrite se
|
||||||
|
|
||||||
test('structured cognition setter is rejected before queueing',()=>{const ctx=setup({decision:'HOLD',reason:'no change',self_principles:[],experiences:[],responsibilities:[],boundaries:[]});try{const language='replace';assert.throws(()=>ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'BAD',language,source_sha256:digest(language),privacy_class:'SELF_PRIVATE',cognition_patch:{revision:99}}),/external_cognitive_setter_forbidden/);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
|
test('structured cognition setter is rejected before queueing',()=>{const ctx=setup({decision:'HOLD',reason:'no change',self_principles:[],experiences:[],responsibilities:[],boundaries:[]});try{const language='replace';assert.throws(()=>ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'BAD',language,source_sha256:digest(language),privacy_class:'SELF_PRIVATE',cognition_patch:{revision:99}}),/external_cognitive_setter_forbidden/);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
|
||||||
|
|
||||||
test('daily review is an opportunity and HOLD does not increment revision',async()=>{let instant=new Date('2026-09-09T08:00:00.000Z');const ctx=setup({decision:'HOLD',reason:'nothing evidence-backed to consolidate',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>instant);try{const first=ctx.loop.current().value;instant=new Date(first.next_review_at);const queued=ctx.loop.tick();assert.equal(queued.scheduled,true);await ctx.loop.drain();assert.equal(ctx.loop.result(queued.job_id).status,'HOLD');assert.equal(ctx.loop.current().value.revision,1);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
|
test('daily review is one idempotent opportunity per Beijing day and HOLD does not increment revision',async()=>{let instant=new Date('2026-09-09T08:00:00.000Z');const ctx=setup({decision:'HOLD',reason:'nothing evidence-backed to consolidate',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>instant);try{const first=ctx.loop.current().value;instant=new Date(first.next_review_at);const queued=ctx.loop.tick();assert.equal(queued.scheduled,true);await ctx.loop.drain();assert.equal(ctx.loop.result(queued.job_id).status,'HOLD');const repeated=ctx.loop.tick();assert.equal(repeated.job_id,queued.job_id);assert.equal(fs.readdirSync(ctx.loop.jobsPath()).length,1);assert.equal(ctx.loop.current().value.revision,1);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
|
||||||
|
|
||||||
test('current direct language is selected before historical review backlog and one item is processed per drain',async()=>{const ctx=setup({decision:'HOLD',reason:'recorded for the next self-cycle',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>new Date('2026-09-09T08:00:00.000Z'),{queueBatchSize:1});try{const review='historical-review';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'AUTONOMOUS_REVIEW_OPPORTUNITY',event_id:'DAILY-REVIEW-2026-09-08',language:review,source_sha256:digest(review),privacy_class:'SELF_PRIVATE',priority:'AUTONOMOUS_REVIEW'});const language='冰朔的当前直接语言';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'ICE-PERSONA-LANGUAGE-20260909-CURRENT',language,source_sha256:digest(language),occurred_at:'2026-09-09T07:59:00.000Z',privacy_class:'SELF_PRIVATE'});const drained=await ctx.loop.drain();assert.equal(drained.processed,1);assert.equal(ctx.calls.length,1);assert.equal(ctx.calls[0].event.event_id,'ICE-PERSONA-LANGUAGE-20260909-CURRENT');assert.equal(ctx.loop.status().scheduler.pending_jobs,1);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
|
test('current direct language is selected before historical review backlog and one item is processed per drain',async()=>{const ctx=setup({decision:'HOLD',reason:'recorded for the next self-cycle',self_principles:[],experiences:[],responsibilities:[],boundaries:[]},()=>new Date('2026-09-09T08:00:00.000Z'),{queueBatchSize:1});try{const review='historical-review';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'AUTONOMOUS_REVIEW_OPPORTUNITY',event_id:'DAILY-REVIEW-2026-09-08',language:review,source_sha256:digest(review),privacy_class:'SELF_PRIVATE',priority:'AUTONOMOUS_REVIEW'});const language='冰朔的当前直接语言';ctx.loop.submit({schema:'guanghu.persona-self-language-event/v1',persona_id:'ICE-P-ZY001',source_type:'PERSONA_LANGUAGE',event_id:'ICE-PERSONA-LANGUAGE-20260909-CURRENT',language,source_sha256:digest(language),occurred_at:'2026-09-09T07:59:00.000Z',privacy_class:'SELF_PRIVATE'});const drained=await ctx.loop.drain();assert.equal(drained.processed,1);assert.equal(ctx.calls.length,1);assert.equal(ctx.calls[0].event.event_id,'ICE-PERSONA-LANGUAGE-20260909-CURRENT');assert.equal(ctx.loop.status().scheduler.pending_jobs,1);}finally{fs.rmSync(ctx.root,{recursive:true,force:true});}});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue