refactor(persona): five-layer architecture v2 (P1/P2/P4/P5) - #29
Conversation
…ers + examples/post-history
Implements P1/P2/P4/P5 of docs/persona-architecture-v2.md, aligning the persona
system with Character Card / SillyTavern best practice: split by injection
position/role, separate "who" (identity) from prompt-engineering (post-history
strong directives), and lock voice with few-shot examples.
- P1: renderRuntimeGuidance applies {{self}}/{{user}}/{{language}} macros to ALL
persona-authored layers (identity/examples/style/posthistory), not just style.
- P2: all 6 persona bodies macro-ized for self/user (display names 雨姐/大姐姐
preserved); dongbei style hardcoded 老蒯 -> {{user}}; _shared/proactive.md
hardcoded 魔尊 -> neutral 用户 (L0 must stay persona-independent — it is NOT
macro-substituted). Fixes a latent cross-combination voice leak.
- P4: new L2 examples.md (few-shot dialogue) per persona — locks tone.
- P5: new L4 posthistory.md per persona — anti-OOC / format-lock / auth boundary,
assembled last (positional bias = strongest weight).
- Assembly [identity, shared, examples, style, posthistory].filter — byte-identical
to v1 when L2/L4 absent (backward compatible).
- Budget guard 6000 -> 8000 (tech-persona-card spec 6.3 recommended max).
- DESIGN.md (five-layer table) + docs/persona-architecture-v2.md updated.
Verified: npm test (376) + npm run verify:skills green; assert script renders all
6x6 combos with zero macro leak and no voice cross-talk.
Remaining (separate): P3 single-source-of-truth, P6 lorebook on-demand injection.
telagod
left a comment
There was a problem hiding this comment.
🔍 Self-review (作者自审,挑刺视角)
整体:架构方向正确,36×组合渲染零泄漏、test 376 / verify 24 全绿,可合。但以下几处值得在合并前权衡或留作紧接的后续。
🟡 应在本 PR 或紧随其后处理
-
L0 共享层「不过宏」缺少护栏(本 PR 的 bug 来源)。
loadSharedBehavior()不做宏替换,所以_shared/*.md里任何{{...}}或具体人称都会原样泄漏。本 PR 正是踩了这个坑(proactive.md的魔尊改宏后泄漏,已修为中立词「用户」)。
建议:加一条测试——断言config/personas/_shared/*.md不含{{也不含任何 persona 人称。这条测试能在未来自动拦住同类回归。 -
L2/L4 新层没有专属测试。
examples.md/posthistory.md的加载与注入目前只被「无泄漏」烟雾测试间接覆盖,没有用例断言「带 examples 的 persona 渲染结果确实包含范例层」。
建议:补一个最小用例(含/不含分文件两种路径),锁住 L2/L4 行为。
🟢 设计权衡(已知,记录在案即可)
-
组装顺序与提案 §5.1 理想序有出入。
实际为identity(L1) → shared(L0) → examples(L2) → style(L3) → posthistory(L4);提案理想序是L0 → L1 → L2 → L3 → L4。这里把 identity 放在 shared 前,是为了与 v1 逐字节兼容(L2/L4 缺省时输出不变)。属有意取舍,但文档应注明实际序,避免日后误读。 -
L4「末段强指令」在 flat-injection 宿主里权重打折。
SillyTavern 的 post-history 是每轮注入到聊天历史之后;而 Claude Code 的 CLAUDE.md 是一次性 system 注入,L4 实为「system prompt 末尾」,位置偏见红利弱于原版。文档已注明,符合预期,不阻塞。 -
persona-card.json的identity/behavior/style路径仍指向不存在的文件。
运行时真正读的是扁平的<slug>.md+ 新增分文件,card 里声明的三个路径仍是空头支票。这正是 P3(单一事实源) 要收的尾,本 PR 不处理,但 reviewer 应知此不一致仍在。
⚪ 风格/内容(可选打磨)
- 六角色的范例对话用了同一组场景(登录 timing attack / N+1 慢查询 / 改表 vs 缓存)。
好处是横向可比、便于校对语气差异;代价是略显模板化。若要更鲜活,后续可给每角色换 1 个本色场景(如雨姐配「上线前回滚」、师妹配「拆炸弹式找 bug」)。不阻塞。
✅ 已验证
[identity, shared, examples, style, posthistory].filter(Boolean)—— L2/L4 缺省时与 v1 逐字节等价。- 6×6 组合:零宏泄漏、无跨角色串味、名号
雨姐/大姐姐无损。 - 预算 6000→8000 对齐 spec §6.3,abyss 实测 ~6.1k 留有余量。
…ank lines Follow-up to PR #29 self-review: - New test: _shared/*.md must stay persona-neutral (no {{ macros — L0 is not macro-substituted — and no persona pronouns). This guard would have caught the proactive.md 魔尊 leak fixed earlier in this PR. - New test: L2 examples.md / L4 posthistory.md are injected when present and the helper returns '' (dropped by filter) when absent — locks the backward-compat contract. - renderRuntimeGuidance: collapse \n{3,} -> \n\n so layer joins never emit a stray triple blank line. Export readPersonaLayer for testability.
Distilled from the persona-architecture-v2 refactor (PR telagod#29). A knowledge skill covering the end-to-end spine for non-trivial changes: research → proposal doc → phased guarded implementation → PR self-review → harden → merge. Core iron law: guarded commit chain (assert && test && verify && commit) so dirty changes never land. Complements automating-devops (the git/CI/release knowledge base); this is the process orchestration layer. Knowledge-only, Read-only. forge lint/scan clean; verify:skills 24->25; npm test 377 passed.
What
Implements P1/P2/P4/P5 of
docs/persona-architecture-v2.md— re-architects the persona system from the old "identity / shared / style" split into a five-layer, injection-position-based model aligned with Character Card V2/V3 + SillyTavern best practice.The core insight (from the design review): separate "who the persona is" from "prompt-engineering / role-lock directives", and lock voice with few-shot examples instead of adjectives.
Layers
config/personas/<slug>.mdconfig/personas/<slug>/examples.mdconfig/personas/_shared/*.mdoutput-styles/*.mdconfig/personas/<slug>/posthistory.mdChanges
renderRuntimeGuidanceapplies{{self}}/{{user}}/{{language}}macros to all persona-authored layers, not just style. Cross-combinations no longer mix voices.雨姐/大姐姐preserved).examples.mdper persona (few-shot).posthistory.mdper persona (strongest position).[identity, shared, examples, style, posthistory].filter(Boolean)— byte-identical to v1 when L2/L4 absent (backward compatible).6000 → 8000(spec §6.3 recommended max) for the two new always-on layers.DESIGN.md+ proposal doc updated.Verification
npm test+npm run verify:skillsgreen (enforced by the commit chain).Follow-up (separate)
index.jsonderived frompersona-card.json).