/** * WPML compatibility functions * * @global array $duplicated_posts Array to store the posts being duplicated. * * @package Yoast\WP\Duplicate_Post * @since 3.2 */ add_action( 'admin_init', 'duplicate_post_wpml_init' ); /** * Add handlers for WPML compatibility. */ function duplicate_post_wpml_init() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 ); } } global $duplicated_posts; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break. $duplicated_posts = []; /** * Copy post translations. * * @global SitePress $sitepress Instance of the Main WPML class. * @global array $duplicated_posts Array of duplicated posts. * * @param int $post_id ID of the copy. * @param WP_Post $post Original post object. * @param string $status Status of the new post. */ function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) { global $sitepress; global $duplicated_posts; remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 ); remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 ); $current_language = $sitepress->get_current_language(); $trid = $sitepress->get_element_trid( $post->ID ); if ( ! empty( $trid ) ) { $translations = $sitepress->get_element_translations( $trid ); $new_trid = $sitepress->get_element_trid( $post_id ); foreach ( $translations as $code => $details ) { if ( $code !== $current_language ) { if ( $details->element_id ) { $translation = get_post( $details->element_id ); if ( ! $translation ) { continue; } $new_post_id = duplicate_post_create_duplicate( $translation, $status ); if ( ! is_wp_error( $new_post_id ) ) { $sitepress->set_element_language_details( $new_post_id, 'post_' . $translation->post_type, $new_trid, $code, $current_language ); } } } } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above. $duplicated_posts[ $post->ID ] = $post_id; } } /** * Duplicate string packages. * * @global array() $duplicated_posts Array of duplicated posts. */ function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break. global $duplicated_posts; foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id ); if ( is_array( $original_string_packages ) ) { foreach ( $original_string_packages as $original_string_package ) { $translated_original_strings = $original_string_package->get_translated_strings( [] ); foreach ( $new_string_packages as $new_string_package ) { $cache = new WPML_WP_Cache( 'WPML_Package' ); $cache->flush_group_cache(); $new_strings = $new_string_package->get_package_strings(); foreach ( $new_strings as $new_string ) { if ( isset( $translated_original_strings[ $new_string->name ] ) ) { foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) { do_action( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. 'wpml_add_string_translation', $new_string->id, $language, $translated_string['value'], $translated_string['status'] ); } } } } } } } } デモ台本(Neo4j Browserでこの順に実行) – Raqqa

デモ台本(Neo4j Browserでこの順に実行)

0) デモ対象の会社を確認

何が起こっているか
「このデモは demo社のデータで実施します」と宣言。

MATCH (c:Company)
RETURN c.company_key, c.name, c.currency
ORDER BY c.company_key;

1) 期間のスコープを見せる

何が起こっているか
「対象は 2025-08〜11 の月次です」と範囲を固定。

MATCH (c:Company {company_key:'demo'})
MATCH (p:Period {company_key:'demo'})
RETURN p.period_key, p.period_type, p.period_start, p.period_end, p.label
ORDER BY p.period_key;

2) まず“健康な月”を見せて基準を作る

何が起こっているか
異常月の話に入る前に、8月・9月のGMが安定していることを見せる。

MATCH (r:KPIResult {company_key:'demo', kpi_key:'gross_margin_rate'})
RETURN r.period_key, r.value, r.calc_basis, r.notes
ORDER BY r.period_key;

3) “異常の発見”を提示(主役シーン)

何が起こっているか
「10月に粗利益率が急落している」
→ ここがストーリーの起点。

MATCH (r:KPIResult {company_key:'demo', kpi_key:'gross_margin_rate'})
WITH r ORDER BY r.period_key
RETURN r.period_key, r.value, r.notes;

(口頭補足)
「9月 29.1 → 10月 24.8 と急落。ここが異常月です。」


4) 異常月だけにフォーカス

何が起こっているか
“原因探索モード”に切り替える。

MATCH (r:KPIResult {
  company_key:'demo',
  period_key:'2025-10',
  kpi_key:'gross_margin_rate'
})
RETURN r.period_key, r.kpi_key, r.value, r.calc_basis, r.notes;

5) “証拠(Evidence)”で説明可能性を提示

何が起こっているか
「AIの推測ではなく、根拠ログ/事実と紐づけて説明できます。」

MATCH (r:KPIResult {
  company_key:'demo',
  period_key:'2025-10',
  kpi_key:'gross_margin_rate'
})-[rel:HAS_EVIDENCE]->(e:Evidence)
RETURN e.evidence_key, rel.relation_type, rel.notes, e.summary
ORDER BY e.evidence_key;

(口頭補足例)

  • Steel price
  • Yield
  • Rework
  • Skill shortage
    など 複数の証拠が“同じ異常”を支持している点を強調。

6) “寄与度(Component Contribution)”で構造化原因を見せる

何が起こっているか
「粗利益率の悪化を、要因レイヤに分解して定量説明します。」

MATCH (r:KPIResult {
  company_key:'demo',
  period_key:'2025-10',
  kpi_key:'gross_margin_rate'
})-[rel:CONTRIBUTES_TO]->(c:Component)
RETURN c.component_key, rel.contribution_score, rel.contribution_type, rel.notes
ORDER BY rel.contribution_score DESC;

(見せ場)

  • CMP-MAT-COST
  • CMP-PROC-COST
  • CMP-QUALITY-LOSS
  • CMP-SKILL-CAPABILITY
    などが上位に来るはず。

7) “設計上の因果仮説”として KPI→Component の関係を見せる

何が起こっているか
「このKPIは、そもそもこういう構成要素で説明する設計です。」
“モデルの骨格”を見せて納得感を出す。

MATCH (k:KPI {company_key:'demo', kpi_key:'gross_margin_rate'})
OPTIONAL MATCH (k)-[r:HAS_COMPONENT]->(c:Component)
RETURN c.component_key, r.weight, r.role
ORDER BY r.weight DESC;

8) “KPI連鎖”で波及的な異常を見せる

何が起こっているか
「粗利益率の落ち込みは単独でなく、
価格・使用量・歩留・リワーク・標準時間など周辺KPIにも現れています。」

MATCH (r:KPIResult {company_key:'demo', period_key:'2025-10'})
WHERE r.kpi_key IN [
  'gross_margin_rate',
  'material_price_variance',
  'material_usage_variance',
  'yield_loss_rate',
  'standard_time_deviation',
  'setup_time_rate',
  'rework_rate',
  'process_lead_time_variance',
  'inventory_turnover',
  'on_time_delivery_rate'
]
RETURN r.kpi_key, r.value, r.notes
ORDER BY r.kpi_key;

9) “改善ストーリー”として11月の回復を見せる

何が起こっているか
「対策が入ると、翌月から指標が戻る」
→ 経営/現場が一番欲しい話。

MATCH (r:KPIResult {company_key:'demo', kpi_key:'gross_margin_rate'})
WHERE r.period_key IN ['2025-10','2025-11']
RETURN r.period_key, r.value, r.notes
ORDER BY r.period_key;

オプション(もし Process/Step/Skill まで入っている場合)

狙い
「寄与度→現場オペ」へ落とすための橋渡し。
(データが無いと空になるので OPTIONAL で)

MATCH (r:KPIResult {company_key:'demo', period_key:'2025-10'})
-[rel:CONTRIBUTES_TO]->(comp:Component)
OPTIONAL MATCH (comp)-[:DRIVES_PROCESS|:RELATED_TO|:IMPACTS*1..2]->(p:Process)
RETURN comp.component_key, rel.contribution_score, collect(DISTINCT p.process_key)[0..5] AS related_processes
ORDER BY rel.contribution_score DESC;

顧客に伝える“話の骨子”(1分版)

  1. 対象期間:2025-08〜11
  2. 異常検知:10月の粗利益率が急落
  3. 説明可能性:Evidence で根拠提示
  4. 要因分解:Component 寄与で構造化
  5. 設計との整合:KPI→Component の骨格
  6. 波及の確認:関連KPIも同月に悪化
  7. 回復の兆し:11月の改善
  8. 次アクション
    • 材料費(価格・使用量)
    • 工程コスト(溶接/組立の時間・リワーク)
    • スキル/キャパ
      に対策優先度を置ける

もし “041_demo_queries.cypher” を活かすなら

041 はこの台本の

    1. 異常の発見
    1. Evidence
    1. 寄与度
    1. 回復

あたりを 綺麗にまとめた閲覧用の可能性が高いので、
中身が今のラベル名と一致しているなら

  • デモ当日は 041 を“見せる用のカンペ集”として使う
    のが一番スムーズです。

必要なら、この台本をそのまま
cypher/demo/041_demo_queries.cypher に合わせて

  • 1ファイル版 “DEMO_RUNBOOK.cypher”
    (コメント付きで順番通り実行できる形)

に整形して渡します。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です