muse-agent-example/db/ddl/107-example投影登记.sql
zizi b0bc7a8745 框架: 技能按动作-对象重组 + 先审后入创作闭环
一、技能重组(动作-对象命名)
- 旧目录 clean/confirm/continuation/db/detect/embed/… 重组为
  clean-book-text/decide-candidate/write-next-chapter/access-database/
  check-content-consistency/embed-knowledge/…(git 识别为 rename,内容保持)
- agents/*.md、AGENTS.md/CLAUDE.md 收编、example_skill 登记表同步新名

二、先审后入创作闭环(本次核心)
正文接受从"机械门一过就写正典"改为"机械门+语义审查双通过+用户批准+单事务原子提交",
DB 级兜底,编排层跳步即被硬拒。
- candidate_cas.py + example_candidate_cas(109):持久化 CAS 状态链
- fact_delta.py + example_fact_delta/example_fact_ledger(106):结构化事实增量,
  模型只提六型闭集增量+正文证据引文,仅用户批准的增量随正文同事务入账本
- projection_registry.py + example_projection_run(107):投影登记与恢复
- acceptance_state.py:接受前置实时状态重读
- lesson_registry.py + example_lesson(108):经验升格链,禁止自动升格
- DDL 105:example_candidate 增 semantic_status/semantic_report_sha256
- write_canonical.accept:语义兜底+同事务合并增量+登记投影;
  run_writer_pipeline/persist_writer_run/run_writer_semantic_detector/step2 接入全链
- claude_runtime:兼容新 CLI modelUsage 信息字段

三、审查修复(独立子代理四维审查后)
- 事实增量 propose→approve 翻态正道,不撞唯一键
- 冻结配置探针重刷(CLI 2.1.211→2.1.231 漂移),profileSha256/adapterVersion 再登记
- 可视化合同悬空路径/五六空间矛盾、 SoT 旧技能名漂移、行尾空白清理

测试:离线 65 套 + 真实库集成 5 套(CAS/接受故障注入/事实增量/投影/经验升格)+ 回放 79 项全绿。
创作内容(docs/design、生成正文 artifacts)按"框架与创作分开"未入本提交。
2026-08-14 10:24:08 +08:00

67 lines
4.1 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 投影运行登记表:example_projection_run(可变注册表)。
-- 摘要、handoff、embedding、章后抽取、看板缓存都只能是 Canonical 正文的幂等投影,
-- 不能反向成为事实源(08 数据权威)。本表把每个投影绑定到它派生自的正文 revision 与文本哈希:
-- 正文换新 revision 提交时,旧投影在同事务内翻 stale,新投影登记 pending;
-- 投影失败记 failed(带原因),绝不显示 completed;恢复走显式 retry(attempt+1)。
-- 幂等键 (work, chapter, kind, revision) 唯一:同一提交重放不重复登记。
-- 全部对象 IF NOT EXISTS / OR REPLACE,重复 apply 幂等。
CREATE TABLE IF NOT EXISTS example_projection_run (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
work_id BIGINT NOT NULL, -- → muse_content_work.id(软引用)
target_chapter INTEGER, -- 章级投影填章号;书级投影为空
kind VARCHAR(32) NOT NULL, -- 投影类型闭集(见 chk)
source_revision INTEGER NOT NULL, -- 派生自的正文块 revision
source_text_hash CHAR(64) NOT NULL, -- 派生时的正文文本哈希(裸 64 hex)
candidate_sha256 CHAR(64), -- 产生该正文的候选哈希(可空:非候选来源)
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/completed/failed/stale
attempt INTEGER NOT NULL DEFAULT 1, -- 重试次数(retry 时 +1)
detail JSONB, -- 失败原因/产物指针等安全摘要
idempotency_key VARCHAR(160) NOT NULL, -- work:chapter:kind:revN(重放幂等)
creator VARCHAR(64) NOT NULL DEFAULT '',
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) NOT NULL DEFAULT '',
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted BOOLEAN NOT NULL DEFAULT FALSE,
tenant_id BIGINT NOT NULL DEFAULT 0,
CONSTRAINT uk_example_projection_run UNIQUE (tenant_id, idempotency_key),
CONSTRAINT chk_example_projection_run_kind
CHECK (kind IN ('summary','handoff','embedding','extraction','dashboard')),
CONSTRAINT chk_example_projection_run_status
CHECK (status IN ('pending','completed','failed','stale')),
CONSTRAINT chk_example_projection_run_counters
CHECK (attempt >= 1 AND source_revision >= 1),
CONSTRAINT chk_example_projection_run_text_hash
CHECK (source_text_hash ~ '^[0-9a-f]{64}$'),
CONSTRAINT chk_example_projection_run_candidate_hash
CHECK (candidate_sha256 IS NULL OR candidate_sha256 ~ '^[0-9a-f]{64}$')
);
CREATE INDEX IF NOT EXISTS idx_example_projection_run_work
ON example_projection_run(tenant_id, work_id, target_chapter, kind, status);
CREATE INDEX IF NOT EXISTS idx_example_projection_run_status
ON example_projection_run(tenant_id, status);
CREATE OR REPLACE TRIGGER trg_example_projection_run_updated_at
BEFORE UPDATE ON example_projection_run FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- 状态迁移闭集:pending→completed/failed/stale;failed→pending(retry);completed→stale;
-- stale 与 completed 不得退回 pending 之外的活动态由应用层保证,DB 只锁"终态不得伪造回写 completed"。
CREATE OR REPLACE FUNCTION enforce_example_projection_run_transition()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
-- 只有 pending 的投影可以被报告完成;stale/failed/completed 不得直接"洗白"成 completed
IF NEW.status = 'completed' AND OLD.status <> 'pending' THEN
RAISE EXCEPTION '投影状态 % 不得直接置为 completed', OLD.status;
END IF;
IF OLD.status = 'stale' AND NEW.status IN ('completed','failed') THEN
RAISE EXCEPTION 'stale 投影不得再报告 completed/failed,必须先 retry 回 pending';
END IF;
RETURN NEW;
END;
$$;
CREATE OR REPLACE TRIGGER trg_example_projection_run_transition
BEFORE UPDATE ON example_projection_run
FOR EACH ROW EXECUTE FUNCTION enforce_example_projection_run_transition();