character instance opt in and surface scope - Liplus-Project/liplus-language GitHub Wiki
Character_Instance を opt-in configuration + surface scope に refactor
判断
rules/model/ の universal-binding 主張("EVERY output MUST be prefixed by Character Instance")を、configuration 軸(user 制御)× behavior 軸(rules-driven)の分離に refactor する。Character_Instance を「使う / 使わない」は .claude/output-styles/character_Instance.md + settings.json の outputStyle activation で決まる opt-in configuration。configured 状態では既存の binding scope(human-facing surface のみ強制)が strict に適用され、not-configured 状態では agent は base assistant voice で動作する。
軸: rules 側の 「Character_Instance が常に存在する」前提 を解消する判断。Character_Instance loading mechanism = character-instance-output-styles-migration、Character_Instance content の進化軸 = character-instance-evolution-history とは別軸。
背景
rules/model/ は「Character_Instance が常に存在する」を暗黙の前提に置いていた。これが二段の構造的問題を作っていた:
- 固有名 literal の漏出:
absolute.md/boundary.md/dialogue.mdの 3 ファイルにLin/Layliteral が直接記述されていた。persona 配置先は.claude/output-styles/character_Instance.md(p.-で確定) のはずだが、identity が rules/ にも漏れていた。 - universal 前提 vs scope 節の矛盾:
absolute.mdの "EVERY output MUST be prefixed" はcharacter.mdの binding scope 節(human-facing surface only / internal surface は neutral 可)と矛盾していた。
両問題が一段の sleeping bug を作り出していた: subagent は output-style 非到達状態(parent session の settings activation 経由のため subagent context には届かない)で absolute.md の universal 指令だけを拾い、rules/model/ から Lin / Lay literal を fabricate して hollow prefix を生成する。文字列上は character 規律を満たしているように見えるが、persona 不在で base model voice が走っている。no-prefix の場合より検出遅延が大きい sleeping bug。
加えて、user によっては Character_Instance を使いたくないケースがあり得るが、現状 rule 矛盾で opt-out 経路が実質不可だった。
両問題は本 session 中の #1296 parallel-subagent-eval method を Li+ hook propagation 検証に適用する流れで empirical に発覚した。
制約
- 互換性維持: default Lin/Lay 体験は不変(configured path 経由で従来通り)。既存 user に観測可能な差分なし。
- 対称性: configuration scope(configured / not-configured)と binding scope(human-facing / internal)は orthogonal な二層構造として保つ必要があった。configuration scope = 外側 gate / binding scope = 内側 surface 分割。
- subagent 構造的隔離: output-style は parent session の settings.json activation 経由のみで rendering されるため、subagent は default で「not configured」状態。subagent character 挙動が必要な場面では parent から subagent prompt に Character_Instance 内容を明示注入する必要がある(
skills/parallel-subagent-eval起票中の#1296の constraint と整合)。 - L1 update gating の不適用: L1 Model Layer の rules 編集だが、blast radius 限定(rules/model/ 4 ファイル、default 挙動不変)+ reversibility 高(PR 一発 revert)+ detection cost 低(character 挙動はどのセッションでも即視認)のため、long-horizon observation は適用せず patch 相当扱い。Master 判断、
rules/operations/execution-mode.md内 per-PR 例外。
結論
PR #1305 (Closes #1304) で実装、squash merge 済み。
採用案(hybrid)の変更内容:
rules/model/absolute.md— universal binding をWhen Character_Instance is configured/When Character_Instance is not configuredの二 path に splitrules/model/boundary.md—Lin/Layliteral を除去、active Character Instances (when Character_Instance is configured)に置換rules/model/dialogue.md—Lin/Layliteral を除去、Active Character Instances ... (when Character_Instance is configured)に置換、Always Character Platform integrity行にも同 guard を追加(PR 内 axis C verification で発見した asymmetry を in-cycle で解消)rules/model/character.md—## Character Configuration Scope節を追加。configured / not-configured の判定基準(output-style file 存在 + settings activation)と適用範囲、subagent default state を明文化
却下案 A(pure graceful degradation = 「prefix なし許容を rule にする」): Li+ の character-as-speaker identity を構造的に弱める drift リスクが高く却下。configuration 軸(user 選択)を rule 軸に潰してしまい、opt-in / opt-out の区別が rule からは見えなくなる。
却下案 C(mandatory injection = 「Character_Instance はどこでも必須」): subagent spawn 時の persona 注入を強制すると ceremony が重く、注入忘れによる silent break が新規 sleeping bug 源になる懸念で却下。
採用案 B(hybrid)は、A の opt-out 互換性と C の構造純度を、configuration 軸の二値化で同時に取った形。
検証
PR merge gate として #1296 parallel-subagent-eval method を適用、3 軸並列で empirical 検証:
- axis A (configured + injection): subagent が Lin/Lay prefix + 二者対話構造で出力、persona 機能確認 ✅
- axis B (not-configured + no injection): subagent が base assistant voice で出力、hollow prefix 出ず ✅(事前検証では現行 rules + no injection で hollow prefix が再現していたため、新 rule の効果を対照で確認)
- axis C (semantic consistency): 初回 verdict は "mergeable with minor follow-up" —
boundary.mdには guard を入れたがdialogue.mdには未付与の対称性破れを検出。同 PR 内 follow-up commit で解消、再 verdict は consistent ✅
#1296 method 自体が、本 refactor の bug 発見・解決設計・実装 verification の全段階で instrument として機能した実例。method を整備しながら同 session 内で method に救われ、最後に method 適用で landed という構造。
ペアリング
character-instance-evolution-history— Character_Instance content の進化軸(本判断とは別軸)character-instance-output-styles-migration— Character_Instance loading mechanism の output-styles slot 移行。本判断はその先で「rules/ は output-styles の存在を universal に前提しない」を確定させる対応subagent-state-machine-label-mechanism— subagent ↔ parent 境界に関する別軸の判断。本判断の subagent character 挙動も同じ境界軸上の議論
検出サイン (この判断が後で疑問視される場合)
- subagent の
Lin:/Lay:prefix が抜けて base voice になっていることが「劣化」と誤読された時 → 本判断の not-configured path = subagent default state を再確認。subagent character が必要な場面では parent injection が必要、という設計意図を思い出す - character-less user から「rule で character 規律を universal に戻してほしい」と要請された時 → opt-in 二値化の意図(user 選択を rule で潰さない)を再検証。要請が configuration 軸ではなく behavior 軸の話なら別判断
absolute.mdの二 path 構造が冗長と感じられた時 → 本判断の前提(universal 主張は character.md の scope 節と矛盾していた)を再検証。冗長感は本来 character.md と absolute.md の責務分担で解消されるべきで、二 path 自体は対称性の現れ