| name | oya-inai-neo4j |
| description | 仕分け済みの語りから、正本表で Neo4j が正本とされた事実だけを構造化して Neo4j 支援DBへ登録する子スキル。抽出は Claude 自身が行い、登録前に必ず人の確認を挟む。親スキル oya-inai-intake から仕分け YAML を受けて呼ばれるほか、「データベースに登録して」「Neo4j に入れて」「構造化して登録」などの発言時に単独でも必ずこのスキルを使用すること。narrative-extractor(nest-support)からの移植版であり、生育歴(LifeHistory)等は意図して抽出しない。 |
oya-inai-neo4j — Neo4j への手続き(子・移植+削る)
移植元: nest-support/claude-skills/narrative-extractor(2026-08-11 移植)。
本スキルは削る移植である——正本表で Obsidian が正本の事実を抽出対象から外した。
削った対象は下の固定リストが確定記録であり、勝手に増減しない。
最上位規則 — No Fabrication
- 絶対に入力テキストにない情報を創作・推測しない
- 「一般的にこうだろう」という推測は禁止。不明な項目は null または空配列 [] とする
- 抽出は分類であって補完ではない
抽出しないもの(固定リスト・削る移植の核心)
以下は語りに含まれていても抽出しない。正本は Obsidian Vault 側にある。
| 抽出しない | 落ち先(Vault) | 根拠 |
|---|
生育歴(LifeHistory / lifeHistories) | person「ライフストーリー」節 | ADR-D9・正本表19。本連携では LifeHistory ノードを作らない |
| 試行錯誤の「学び」(次に同じ場面が来たらどうするか) | trial | 正本表8 |
| サービス等利用計画の内容 | plan | 正本表9(対応ノードなし) |
| モニタリング・会議の判断の過程(なぜそう決めたか) | monitoring / meeting | 正本表10・12 |
SupportLog(出来事そのもの)は取る(正本表7)。学びの部分だけ Vault へ
- 会議は開催の事実と逐語のみ取る(正本表11)。決定の理由は Vault へ
- このリストは移植時(2026-08-11)に削った対象の確定記録。改訂は正本表の変更時のみ
- 判断規則の正典は隣のスキルの
oya-inai-intake/reference/dual-intake-routing.md を参照する(本スキルは写しを持たない。写しを増やすと同期点が増える)
役割と境界
**本スキルは手続きだけを持つ。**どの事実を Neo4j に落とすかの判断は親(oya-inai-intake)が行う。単独起動で判断が必要になったら、親スキルの手順を先に通す。
- 入力: 親スキルの仕分け YAML(
person / source / to_neo4j)、または人の直接指示+テキスト
- **Obsidian 側(仮名のみ)と違い、こちらは実名を扱う。**このため人の確認が必須になる(下記 Step 3)
使用方法
Step 1: 入力の受領
親 YAML の to_neo4j の断片、または語りのテキスト。source.sha256(raw/ 原本のバイト列 sha256。oya-inai-vault が算出)を受け取り、auditContext.sourceHash に使う——両系突合の橋。
Step 2: 構造化データの抽出
抽出ルール(厳守)
- No Fabrication(上記・最上位規則)
- 暗黙知の抽出を優先する
- 「〜すると落ち着く」「〜が好き」→ carePreferences
- 「〜は嫌がる」「〜するとパニック」→ ngActions(最重要)
- 「今日〜した」「〜の対応で効果があった」→ supportLogs
- 禁忌事項(NgAction)は最優先
- 「絶対に〜しないで」「〜するとパニック」を漏らさない
- riskLevel を適切に判定:LifeThreatening / Panic / Discomfort
- 固定リストの適用: 生育歴・学び・計画・判断の過程が語りに含まれていても抽出しない(親の to_vault が拾う)
- 日付の変換: 元号(和暦)→ 西暦(YYYY-MM-DD)。明治元年=1868, 大正=1912, 昭和=1926, 平成=1989, 令和=2019
- Entity Resolution(同一対象の統合)
- 表記揺れは同一エンティティに統合(「みなと」「みなとさん」「みなと君」→ 同一 Client。例は記入例の架空ダミー P_900)
- 既存クライアントへの追記時は、Neo4j を検索して既存ノードと突合する
- 統合に確信が持てない場合はユーザーに確認する
- 既存 Client の
clientId も必ず読み、3分岐する(Cypher の COALESCE は「空なら書く」しかできず、取り違え・採番の衝突は検出できない。その検出はこの手順が担う):
| 既存の clientId | 送り方 |
|---|
| 空(null / 未採番) | $clientId に値を渡す |
| 親 YAML と一致 | 渡さない(null のまま。COALESCE が既存値を守る) |
| 親 YAML と不一致 | 止めて人に確認する(取り違えか採番の衝突。どちらかを機械が選ばない) |
JSONスキーマ(lifeHistories は存在しない——移植時に削除)
{
"client": { "name": "氏名(必須)", "clientId": "親 YAML の person.clientId(例: P_900)| null", "dob": "YYYY-MM-DD | null", "bloodType": null, "kana": null, "aliases": [] },
"conditions": [ { "name": "特性・診断名", "status": "Active" } ],
"ngActions": [ { "action": "してはいけないこと", "reason": "理由", "riskLevel"
親 YAML 経由の場合、上記スキーマ外のラベル(CareRole / Relative / ServiceProvider / MeetingRecord / Review 等)はノード断片(label / mergeKey / properties)としてそのまま組み立てる。正典の許可リスト(SCHEMA_CONVENTION / SEMANTIC_MODEL)にあるものだけを使い、廃止名は書かない。
Step 3: 人の確認(必須・省略不可)
抽出結果と、Step 4 の検査結果(validate の rejected / warnings・dedup の候補・既存 NgAction との突き合わせ)をユーザーに提示し、明示的な承認を得てから登録する。
- 確認なしの登録経路を作らない。「ついでに登録しておきました」は本スキルでは事故である
- 実名が入るため、間違えたときの回復コストが Obsidian 側と違う(承認の非対称)
- 親スキルの仕分け宣言への黙認はこの承認を兼ねない
Step 4: 検査 → 登録(書き込みは MCP 一本)
旧 POST /api/narrative/intake は 2026-08-12 の Claude 一本化で廃止された。
書き込みは neo4j MCP execute_query の一本。その前に必ず機械検査を通す。
1. POST /api/graph/validate で検証(Guardian Layer。LLM を呼ばず DB にも書かない)
└ rejected が 1 件でもあれば書き込みに進まない。直して再検証
2. POST /api/dedup/check で重複検査(ノードごと)
3. Step 3 の人の確認で、両方の結果をそのまま見せる
4. 承認後に neo4j MCP execute_query で書き込む(下の Cypher テンプレート)
5. Step 5 の監査ログ(AuditLog を MCP で作成)
検査1: POST /api/graph/validate(スキーマ検証)
nodes / relationships を旧 intake と同じ断片形式(temp_id / label / mergeKey / properties)で送る:
{
"nodes": [
{ "temp_id": "c1", "label": "Client", "mergeKey": { "name": "みなと(架空)" },
"properties": { "name": "みなと(架空)", "clientId": "P_900" } },
{ "temp_id": "ng1", "label": "NgAction", "mergeKey": { "action": "パニック時に体に触らない" },
"properties": { "action": "パニック時に体に触らない", "reason"
応答は { accepted, rejected: [{ path, reason }], warnings }。
- **rejected が 0 でなければ書き込みに進まない。**reason を読んで断片を直し、再度 validate に通す
accepted には補正済みの断片が返る(camelCase 変換・廃止リレーション修正・riskLevel 別名補正)。書き込みには自分の元データではなく accepted の内容を使う——補正を無視して書くと検証の意味がない
warnings は補正の記録。Step 3 で人に見せる
- MERGE キーの値は
properties 側にも必ず入れる(検証器は properties を見る。mergeKey だけでは reject される——2026-08-11 E-5 で実測)
検査2: POST /api/dedup/check(重複検査)
{ "label": "Client", "properties": { "name": "みなと(架空)" } } の形でノードごとに送る。hasCandidates が true なら候補を Step 3 で人に見せ、新規作成か既存への追記かを人が判断する。
安全検査(safetyCheck)は復活させない
旧 API にあった安全検査(登録内容が既存 NgAction と抵触しないかの判定)は LLM への問い合わせだったため復活させない(2026-08-12 河原さん決定)。この担保は Step 3 の人の確認が担う——既存クライアントへの追記では、登録前に対象クライアントの既存 NgAction を MCP で読み出し、抽出結果と並べて人に見せること。
API が起動していないとき(黙って進まない)
「検証をかけられない状態です」と人に伝えて止まる。勝手に判断して進めない。人が選ぶ:
- アプリ(API・port 8001)を起動してから検査をやり直す(推奨。
start.command / start.bat)
- 検証なしで MCP 直書きに進む(明示の承認が必須)。その場合は必ず次の警告を出す:
⚠️ 検証 API が起動していないため、機械検査なしで直接データベースへ書き込みます。スキーマ検証・重複検査は適用されません。
書き込み: neo4j MCP execute_query
Cypher テンプレート(移植元由来。LifeHistory のテンプレートは移植時に削除した):
クライアント基本情報:
clientId は親 YAML の person.clientId(採番は人の承認済み)。既存値を上書きしない
(COALESCE で既存優先——後付け採番の手順書で入れた値をスキルが潰さないため)。
取り違え・採番衝突の検出は COALESCE ではできないので、Entity Resolution の
3分岐(Step 2 ルール6)が担う。MERGE キーは移植元どおり name のまま
(clientId をキーにするかは ADR 未決論点8)。
MERGE (c:Client {name: $name})
SET c.clientId = COALESCE(c.clientId, $clientId),
c.dob = CASE WHEN $dob IS NOT NULL THEN date($dob) ELSE c.dob END,
c.bloodType = COALESCE($blood, c.bloodType),
c.kana = COALESCE($kana, c.kana),
c.aliases = $aliases
特性・診断:
MATCH (c:Client {name: $client})
MERGE (con:Condition {name: $name})
SET con.status = $status
MERGE (c)-[:HAS_CONDITION]->(con)
禁忌事項(NgAction)- 最重要(クライアント配下で MERGE):
MATCH (c:Client {name: $client})
MERGE (c)-[:MUST_AVOID]->(ng:NgAction {action: $action})
ON CREATE SET ng.reason = $reason, ng.riskLevel = $risk, ng.status = 'Pending'
ON MATCH SET ng.reason = COALESCE($reason, ng.reason),
ng.riskLevel = COALESCE($risk, ng.riskLevel)
推奨ケア(CarePreference):
MATCH (c:Client {name: $client})
MERGE (c)-[:REQUIRES]->(cp:CarePreference {category: $cat, instruction: $inst})
ON CREATE SET cp.priority = $pri, cp.status = 'Pending'
ON MATCH SET cp.priority = COALESCE($pri, cp.priority)
手帳・受給者証(Certificate。type×grade の複合キー・DRIFT-08 対応済み):
MATCH (c:Client {name: $client})
MERGE (c)-[r:HAS_CERTIFICATE]->(cert:Certificate {type: $type, grade: COALESCE($grade, '不明')})
SET cert.nextRenewalDate = CASE WHEN $renewal IS NOT NULL THEN date($renewal) ELSE cert.nextRenewalDate END,
r.status = COALESCE(r.status, 'Active')
キーパーソン(KeyPerson):
MATCH (c:Client {name: $client})
MERGE (c)-[r:HAS_KEY_PERSON]->(kp:KeyPerson {name: $name})
SET kp.phone = COALESCE($phone, kp.phone),
kp.relationship = COALESCE($rel, kp.relationship),
kp.role = COALESCE($role, kp.role),
r.rank = COALESCE($rank, r.rank)
後見人(Guardian):
MATCH (c:Client {name: $client})
MERGE (c)-[:HAS_LEGAL_REP]->(g:Guardian {name: $name})
SET g.type = COALESCE($type, g.type),
g.phone = COALESCE($phone, g.phone),
g.organization = COALESCE($org, g.organization)
医療機関(Hospital。かかりつけ医は Doctor ノード):
MATCH (c:Client {name: $client})
MERGE (h:Hospital {name: $name})
SET h.specialty = $spec, h.phone = $phone
MERGE (c)-[:TREATED_AT]->(h)
FOREACH (_ IN CASE WHEN $doc IS NULL OR $doc = '' THEN [] ELSE [1] END |
MERGE (d:Doctor {name: $doc})
MERGE (h)-[:HAS_DOCTOR]->(d))
願い(Wish):
MATCH (c:Client {name: $client})
CREATE (w:Wish {content: $content, status: 'Active', date: date($date)})
CREATE (c)-[:HAS_WISH]->(w)
支援記録(SupportLog):
MERGE (s:Supporter {name: $supporter})
WITH s
MATCH (c:Client {name: $client})
CREATE (log:SupportLog {
date: date($date), situation: $situation, action: $action,
effectiveness: $effectiveness, note: $note
})
CREATE (s)-[:LOGGED]->(log)-[:ABOUT]->(c)
Step 5: 監査ログ(必須)
すべての書き込みの後、AuditLog ノードを MCP で作成する(sourceHash に Step 1 の
raw/ 原本バイト列 sha256 を必ず入れる——両系突合の橋):
CREATE (al:AuditLog {
timestamp: datetime(), user: $user, action: $action,
targetType: $targetType, targetName: $targetName,
details: $details, clientName: $clientName, sourceHash: $sourceHash
})
RETURN al.timestamp AS 記録日時
1回の登録で複数ノードを作成した場合、クライアント単位で1件にまとめてよい。
継承する規律(write-gate・証拠鮮度モデル)
- DELETE 禁止(support-db-write-gate §5)。削除が要る場面は人へ(明示の承認が必須)
- クライアント単位 MERGE(同 §2)。NgAction / CarePreference は Client 配下でリレーションごと MERGE し、他クライアントとノードを共有しない
- 更新対象は完全一致で特定(同 §4)。曖昧照合で更新しない
- 証拠・鮮度モデル(SCHEMA_CONVENTION v3.4 §7.9 / SEMANTIC_MODEL v1.6 BRS-13): AI 抽出由来の NgAction / CarePreference は
status: Pending で作成(人の承認で Active 昇格・AuditLog 必須)。既存事実と食い違う情報は上書きせず CONTRADICTS(claim / raisedAt / source)で保留し、人が裁定する。鮮度更新は Review+CONFIRMS+lastConfirmedAt(routing §4。DRIFT-13 解消済みのため CONFIRMS / CONTRADICTS は validate も通る)
禁止事項
clientId のない Client を作らない(正本表1・S-5: Neo4j の clientId が正であり、Vault の person_id はその写し。値は親スキルの採番承認を経たものを使う)
- この禁止事項の機械側の担保は F-4 の確認クエリ(未採番 Client の一覧。後付け採番の手順書に収載)——スキルの規律が破れても、未採番はクエリで検出できる
命名規則(厳守)
- ノード: PascalCase (
Client, NgAction) / リレーション: UPPER_SNAKE_CASE (MUST_AVOID) / プロパティ: camelCase (riskLevel)
- 廃止名 (
PROHIBITED, PREFERS, EMERGENCY_CONTACT, RELATES_TO, HAS_GUARDIAN, HOLDS) は書き込み禁止
関連
- 親スキル:
oya-inai-intake(仕分けの判断・YAML の出所)
- 兄弟スキル:
oya-inai-vault(Obsidian への手続き・sha256 の算出元)
- 判断規則の正典:
oya-inai-intake/reference/dual-intake-routing.md(写しは持たない)
- 書き込み規律の正典:
support-db-write-gate/SCHEMA_CONVENTION v3.4/SEMANTIC_MODEL v1.6