@takagaki/cortex-decisions-viewer 0.12.142 → 0.12.145

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/render.js CHANGED
@@ -4540,7 +4540,7 @@ function buildTutorialData(site, repoSlug) {
4540
4540
  specs.push({
4541
4541
  title: "自分の名前を変更してみよう",
4542
4542
  desc: "関係者一覧の自分のレコードをAIに直してもらう",
4543
- prompt: TUT_MEMBER_PROMPT,
4543
+ prompt: tutMemberPrompt(!!site.memoryV2),
4544
4544
  });
4545
4545
  }
4546
4546
  // Backlogに記票する体験(課題管理にBacklogを使う案件のみ出す)
@@ -4608,12 +4608,17 @@ function tutorialChallenge4Prompt(decisions) {
4608
4608
  * 中身は利用者に聞き返させる(AI導線ボタンのプロンプトと同じ方針)。
4609
4609
  * 規約がどこにも無い手順(外部サービスへのつなぎ方・投稿経路の判定)だけを骨子として残す。
4610
4610
  */
4611
+ const TUT_MEMBER_STATUS_LINE = "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。";
4611
4612
  const TUT_MEMBER_PROMPT = [
4612
4613
  "Cortex/Members/README.md と Cortex/Members/template.md を読んで規約を把握してから、Cortex/Members/records/ にあるわたし自身の関係者のレコードの表示名(title)を変更してください。Gold層へ書き込む練習です。名簿にわたしのレコードが無ければ、新規に1件作ってかまいません。",
4613
4614
  "わたしが誰で、何をどう変えたいかは、まずわたしに質問してください。",
4614
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
4615
+ TUT_MEMBER_STATUS_LINE,
4615
4616
  "書き込む前に、作成・変更する内容を提示して承認を得てください。",
4616
4617
  ].join("\n");
4618
+ // 記憶 v2 の案件には status の指示を出さない(common.no-draft-lock)。非 v2 は今のまま
4619
+ function tutMemberPrompt(memoryV2) {
4620
+ return memoryV2 ? TUT_MEMBER_PROMPT.replace(TUT_MEMBER_STATUS_LINE + "\n", "") : TUT_MEMBER_PROMPT;
4621
+ }
4617
4622
  const TUT_BACKLOG_PROMPT = [
4618
4623
  "Backlogの課題に、わたしの名義でコメントを1件投稿してください。Backlogの画面を開かずにAIから記票する練習です。",
4619
4624
  "課題を取れる道具(Backlog のコネクタ)を道具の検索で探してください。同じ働きの道具が2つ以上あれば、Cortex/sources.json の backlog の接続の domain(このファイルがまだ無いプロジェクトは 課題管理/issues-config.json の targets の domain)と同じスペースを読むものを選びます。",
@@ -4991,8 +4996,6 @@ a.pager-btn:hover { text-decoration: none; }
4991
4996
  background: #eceef1; color: #41474f;
4992
4997
  }
4993
4998
  .badge.draft { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
4994
- /* 直近のGold昇格で作られたレコードの印。draft(黄・要対応)と区別できるよう、新着を示す緑系にする */
4995
- .badge.latest { background: #dcfce7; color: #166534; border: 1px solid #86efac; }
4996
4999
  .badge.error { background: #fee2e2; color: #b91c1c; border: 1px solid #fca5a5; }
4997
5000
  .draft-note {
4998
5001
  display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;
@@ -5022,15 +5025,15 @@ a.pager-btn:hover { text-decoration: none; }
5022
5025
  }
5023
5026
  .story-quiet { margin: -6px 0; padding: 0 18px; font-size: 12.5px; color: var(--muted); }
5024
5027
  .story-quiet-date { font-variant-numeric: tabular-nums; }
5028
+ .story-quiet-failed { color: #b91c1c; }
5025
5029
  .story-card-heading { margin: 0 0 8px; font-size: 15px; }
5026
- .story-card-edit { display: inline-block; margin-top: 8px; font-size: 12.5px; }
5030
+ .story-card-actions { margin-top: 10px; justify-content: flex-start; }
5027
5031
  .story-card .body h2 { font-size: 14px; margin: 14px 0 6px; }
5028
5032
  .story-card .body h3 { font-size: 13.5px; margin: 12px 0 6px; }
5029
5033
  /* 週・月のあらすじカード(#901)。週・月のファイルがある案件だけ使う */
5030
5034
  .story-empty { margin: 0; font-size: 13px; color: var(--muted); }
5031
5035
  .story-phase { margin: 0 0 8px; font-weight: 600; }
5032
5036
  .story-phase-label { display: inline-block; margin-right: 8px; font-size: 12px; color: var(--muted); font-weight: 400; }
5033
- .story-digest-human h4 { font-size: 13.5px; margin: 12px 0 6px; }
5034
5037
  /* ---- Home(案件の自己記述)---- */
5035
5038
  /* 未記入の警告。**画面でいちばん強い赤にする**——27案件中24案件が未記入のまま
5036
5039
  毎晩のAI生成が走っている状態で、控えめに出しても読まれない */
@@ -5305,25 +5308,18 @@ a.pager-btn:hover { text-decoration: none; }
5305
5308
  .ip-decide-msg:empty { display: none; }
5306
5309
  .ip-decide-msg.is-error { color: #b45309; }
5307
5310
  .ip-decided { font-size: 13px; font-weight: 600; color: #15803d; }
5308
- /* 決定の「その後」(担当者の答えの 1 行)。節は .followup-section */
5309
- .followup-section { margin: 14px 0 4px; }
5310
- /* 置き換え(#699 F3) */
5311
- .badge.retired { background: #f5f5f4; color: #57534e; border: 1px solid #d6d3d1; }
5312
- /* 取り下げ済みルールの薄い表示 */
5313
- .card.is-faded { opacity: .55; }
5314
- /* 論点・固さ(#1094)。欄の無い記録には付かない */
5315
- .badge.topic { background: #f5f3ff; color: #5b21b6; border: 1px solid #ddd6fe; font-weight: 500; }
5311
+ /* 筋・固さ(#1094)。欄の無い記録には付かない */
5312
+ .badge.strand { background: #f5f3ff; color: #5b21b6; border: 1px solid #ddd6fe; font-weight: 500; }
5316
5313
  .badge.firmness-fixed { background: #ecfdf5; color: #047857; border: 1px solid #a7f3d0; }
5317
5314
  .badge.firmness-tentative { background: #fffbeb; color: #92400e; border: 1px solid #fde68a; }
5318
5315
  .badge.firmness-open { background: #f8fafc; color: #475569; border: 1px dashed #cbd5e1; }
5319
- .decision-topic { margin-bottom: 4px; }
5316
+ .decision-strand { margin-bottom: 4px; }
5320
5317
  .supersede-section { margin: 14px 0 4px; }
5321
5318
  .supersede-list { list-style: none; margin: 0 0 8px; padding: 0; }
5322
5319
  .supersede-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; font-size: 13.5px; line-height: 1.7; padding: 2px 0; }
5323
5320
  .supersede-id { font-size: 12.5px; color: var(--muted); word-break: break-all; }
5324
5321
  .supersede-candidate { font-size: 12px; color: #92400e; background: #fffbeb; border: 1px solid #fde68a; border-radius: 4px; padding: 0 6px; }
5325
5322
  .supersede-candidate-note { font-size: 13px; color: #92400e; margin: 0 0 4px; }
5326
- .followup-human { font-size: 13.5px; margin: 0 0 6px; color: #166534; }
5327
5323
  /* 押したあとの帯。draft(黄・要対応)と入れ替わるので、済んだと分かる緑にする */
5328
5324
  .promoted-note {
5329
5325
  display: flex; gap: 8px; align-items: flex-start;
@@ -6791,11 +6787,6 @@ ${calendarAddUrl.toString()}
6791
6787
  function draftBadge(rec) {
6792
6788
  return rec && unconfirmed(rec) ? el("span", { class: "badge draft", text: "AI生成・未確認" }) : null;
6793
6789
  }
6794
- // 直近のGold昇格で作られたレコードの印。レコードの date は決定日なので、日付順に並べても
6795
- // 「今回の実行で何が増えたか」は分からない。ビルド時に git から判定した結果(isLatest)を出す
6796
- function latestBadge(rec) {
6797
- return rec && rec.isLatest ? el("span", { class: "badge latest", text: "最新の生成" }) : null;
6798
- }
6799
6790
  // 詳細ページの警告。バッジより強く「そのまま信じないでほしい」と伝える。
6800
6791
  // **確認済みにできる記録には、その場で上げるボタンを並べる**(下の promotableRecordPath)。
6801
6792
  // ボタンが出せないとき(受け口が未設定・パスが解決できない)は、これまでどおり
@@ -6924,8 +6915,6 @@ ${calendarAddUrl.toString()}
6924
6915
  function markPromoted(rec, note) {
6925
6916
  // **元データも直す。** 一覧へ戻って開き直しても未確認に戻らないようにする
6926
6917
  rec.rstatus = "active";
6927
- // 確認済みにした記録は人の手のある記録(削除の確認の先頭の行が変わる・#1094 4-1)
6928
- rec.humanTouched = true;
6929
6918
  var host = note.parentNode;
6930
6919
  if (!host) return;
6931
6920
  var badge = host.querySelector(".detail-meta .badge.draft");
@@ -6948,67 +6937,23 @@ ${calendarAddUrl.toString()}
6948
6937
  return ps.filter(function (one) { return !ipAnswered(rec, one); });
6949
6938
  }
6950
6939
 
6951
- // 状態の絞り込み。**未確認と置き換え済みを同じセレクトに並べる**(導線を増やさない)
6940
+ // 状態の絞り込み。未確認のみ(draft)の選択肢だけを持つ
6952
6941
  function statusLabel(v) {
6953
- if (v === RETIRED_FILTER) return "置き換え済み";
6954
- if (v === RETRACTED_FILTER) return "取り下げ";
6955
6942
  return v === "draft" ? "未確認のみ" : v;
6956
6943
  }
6957
6944
  /** 一覧に出す選択肢。**該当が1件も無い状態は選択肢に出さない**(押しても0件の項目を並べない) */
6958
6945
  function statusFilterOptions(items) {
6959
6946
  var opts = [];
6960
6947
  if (hasUnverified(items)) opts.push("draft");
6961
- // 置き換え済み(#699 F3)。決定にしか付かない印なので、決定の一覧でだけ選択肢になる
6962
- if ((items || []).some(isRetired)) opts.push(RETIRED_FILTER);
6963
- // 取り下げ(便 4-2d)。ルールにしか付かない印なので、ルールの一覧でだけ選択肢になる
6964
- if ((items || []).some(isRetracted)) opts.push(RETRACTED_FILTER);
6965
6948
  return opts;
6966
6949
  }
6967
- /** 絞り込みの判定。frontmatter の status との素の比較は「未確認のみ」と置き換え済み以外のとき */
6950
+ /** 絞り込みの判定。frontmatter の status との素の比較は「未確認のみ」以外のとき */
6968
6951
  function matchesStatusFilter(rec) {
6969
6952
  if (!listState.status) return true;
6970
- // 決定以外の一覧(タブを移っても絞り込みは残る)では絞らない——全件が消えないように
6971
- if (listState.status === RETIRED_FILTER) return rec && rec._kind === "decision" ? isRetired(rec) : true;
6972
- if (listState.status === RETRACTED_FILTER) return rec && rec._kind === "generic" && rec._section === "Rules" ? isRetracted(rec) : true;
6973
6953
  // 「未確認のみ」は口に聞く(札と同じ答え)。それ以外の値は従来どおりの素の比較
6974
6954
  if (listState.status === "draft") return unconfirmed(rec);
6975
6955
  return rec.rstatus === listState.status;
6976
6956
  }
6977
- /* -------------------------------------------------------------------------
6978
- * 決定の「その後」(人の答え・frontmatter の followup:)
6979
- * -------------------------------------------------------------------------
6980
- * 画面に出すのは、担当者が答えた 1 行(4 語)だけ。夜間の帳簿は画面に出さない・読まない
6981
- * (PR のマージを完了と数える差を画面から外す・#1094 35d)。答えを書く押しボタンも置かない。
6982
- * 🔴 答えが無い決定では要素を 1 つも作らない。
6983
- */
6984
- /** 担当者の答え(frontmatter の followup:)の 1 行。日付は括弧で添える */
6985
- var FOLLOWUP_HUMAN_LABEL = {
6986
- confirmed: "担当者が正しいと確認",
6987
- done: "担当者が実施済みにしました",
6988
- dropped: "担当者が取りやめと記録",
6989
- ignore: "担当者が追わなくてよいと記録",
6990
- };
6991
- /** 表からラベルを引く(__proto__ や toString のような鍵で Object の中身を拾わない) */
6992
- function followupLabel(table, k) {
6993
- return Object.prototype.hasOwnProperty.call(table, k) ? table[k] : "";
6994
- }
6995
- function hasFollowupHuman(rec) {
6996
- return !!(rec && rec.followupHuman && followupLabel(FOLLOWUP_HUMAN_LABEL, rec.followupHuman.state));
6997
- }
6998
- function followupHumanLine(fh) {
6999
- return el("p", { class: "followup-human", text: followupLabel(FOLLOWUP_HUMAN_LABEL, fh.state) + "(" + fh.at + ")" });
7000
- }
7001
-
7002
- /** 詳細の節「その後の記録」。**担当者の答えが無ければ null**(要素を作らない) */
7003
- function followupSection(rec) {
7004
- if (!hasFollowupHuman(rec)) return null;
7005
- var box = el("section", { class: "followup-section" }, [
7006
- el("div", { class: "section-label", text: "その後の記録" }),
7007
- ]);
7008
- box.appendChild(followupHumanLine(rec.followupHuman));
7009
- return box;
7010
- }
7011
-
7012
6957
  /* -------------------------------------------------------------------------
7013
6958
  * 置き換え(#699 F3・cortex-engine #1094 段 4 の 4-1)
7014
6959
  * -------------------------------------------------------------------------
@@ -7018,33 +6963,6 @@ ${calendarAddUrl.toString()}
7018
6963
  * 新しい側がまだ人の確認を経ていない)。
7019
6964
  * 🔴 古い側の superseded_by(夜間の精製が書く写し)は画面でも読まない。
7020
6965
  */
7021
- var RETIRED_FILTER = "retired";
7022
- /** もう有効でない(確定した置き換えが 1 本以上) */
7023
- function isRetired(rec) {
7024
- return !!(rec && rec.supersededBy && rec.supersededBy.retired);
7025
- }
7026
- /** 一覧・詳細の印。判定は置き換えの逆引き(supersedes.ts)だけが正 */
7027
- function retiredBadge(rec) {
7028
- if (!isRetired(rec)) return null;
7029
- return el("span", { class: "badge retired", text: "置き換え済み" });
7030
- }
7031
- /**
7032
- * ルールの取り下げ(cortex-engine #1094 便 4-2d)。ビルドが relations[retracted_by] から rec.retractedBy
7033
- * (取り下げを決めた決定・無ければキーごと無い)を載せてある。**1 本以上あれば取り下げ済み**。
7034
- * 札・薄く出す・詳細の節は、決定の「置き換えられた」と同じ部品を使う(本文は消さない)
7035
- */
7036
- var RETRACTED_FILTER = "retracted";
7037
- function isRetracted(rec) {
7038
- return !!(rec && rec._kind === "generic" && rec.retractedBy && rec.retractedBy.length);
7039
- }
7040
- function retractedBadge(rec) {
7041
- if (!isRetracted(rec)) return null;
7042
- return el("span", { class: "badge retired", text: "取り下げ" });
7043
- }
7044
- /** 取り下げ済みのルールを薄く出す(一覧のカード) */
7045
- function retractedFadedClass(rec) {
7046
- return isRetracted(rec) ? " is-faded" : "";
7047
- }
7048
6966
  /**
7049
6967
  * 詳細の節「関連の資料」(cortex-engine #1094 F8)。記録を生んだ会話に貼られた資料へのリンク。
7050
6968
  * 根拠(「参照」)とは混ぜない。ビルドが engine と同じ門で検めてあるが、画面でも http(s) だけをリンクにする(二重に見る)。
@@ -7066,21 +6984,6 @@ ${calendarAddUrl.toString()}
7066
6984
  box.appendChild(ul);
7067
6985
  return box;
7068
6986
  }
7069
- /** 詳細の節「取り下げを決めた決定」。取り下げの無い記録では null(要素を作らない) */
7070
- function retractSection(r) {
7071
- if (!isRetracted(r)) return null;
7072
- var box = el("div", { class: "supersede-section" });
7073
- box.appendChild(el("div", { class: "section-label", text: "取り下げを決めた決定" }));
7074
- var ul = el("ul", { class: "supersede-list supersede-by" });
7075
- r.retractedBy.forEach(function (b) {
7076
- var row = supersedeRow(b.id, b.date, false);
7077
- // 決定が実在しない(まだ同期されていない等)ときも、行を空にせず ID を出す
7078
- if (!row.firstChild) row.appendChild(el("span", { class: "supersede-id mono", text: b.id }));
7079
- ul.appendChild(row);
7080
- });
7081
- box.appendChild(ul);
7082
- return box;
7083
- }
7084
6987
  /** 候補の帯(症状)。行の札は「候補」とだけ言い、理由はこの帯 1 行に寄せる(繰り返さない) */
7085
6988
  var SUPERSEDE_CANDIDATE_NOTE = "前の決定は人が直しているため、置き換えは候補です";
7086
6989
  /** 決定 1 件の行。SITE にあれば題名で詳細へのリンク、無ければ ID だけ */
@@ -7145,24 +7048,23 @@ ${calendarAddUrl.toString()}
7145
7048
  }
7146
7049
 
7147
7050
  /* -------------------------------------------------------------------------
7148
- * 論点・固さ・決めた人(記憶 v2・cortex-engine #1094)
7051
+ * 筋・固さ・決めた人(記憶 v2・cortex-engine #1094)
7149
7052
  * -------------------------------------------------------------------------
7150
- * 欄(topic / firmness / decidedBy)は**ビルド側で語彙・形を確かめてある**。欄の無い記録では
7053
+ * 欄(strand / firmness / decidedBy)は**ビルド側で語彙・形を確かめてある**。欄の無い記録では
7151
7054
  * キーごと無いので、画面は有無だけを見る。🔴 **欄の無い記録だけの案件では要素を 1 つも作らない**
7152
7055
  * (絞り込み・固さの札・決めた人の節が出ない=今と同じ DOM)。
7153
- * 「置き換えられた」の判定は isRetired(ビルドが supersedes.ts で組んだ答え)をそのまま使う。
7154
7056
  */
7155
- function hasTopic(rec) {
7156
- return !!(rec && typeof rec.topic === "string" && rec.topic);
7057
+ function hasStrand(rec) {
7058
+ return !!(rec && typeof rec.strand === "string" && rec.strand);
7157
7059
  }
7158
- /** 論点の札の一覧(札を持つ決定が無ければ空) */
7159
- function topicOptions(items) {
7060
+ /** 筋の札の一覧(札を持つ決定が無ければ空) */
7061
+ function strandOptions(items) {
7160
7062
  var seen = {};
7161
7063
  var out = [];
7162
7064
  (items || []).forEach(function (d) {
7163
- if (!hasTopic(d) || Object.prototype.hasOwnProperty.call(seen, d.topic)) return;
7164
- seen[d.topic] = true;
7165
- out.push(d.topic);
7065
+ if (!hasStrand(d) || Object.prototype.hasOwnProperty.call(seen, d.strand)) return;
7066
+ seen[d.strand] = true;
7067
+ out.push(d.strand);
7166
7068
  });
7167
7069
  return out.sort(function (a, b) { return a.localeCompare(b, "ja"); });
7168
7070
  }
@@ -7175,9 +7077,9 @@ ${calendarAddUrl.toString()}
7175
7077
  }
7176
7078
  return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
7177
7079
  }
7178
- /** 論点の札(一覧の行)。札が無ければ null */
7179
- function topicBadge(rec) {
7180
- return hasTopic(rec) ? el("span", { class: "badge topic", title: "論点", text: rec.topic }) : null;
7080
+ /** 筋の札(一覧の行)。札が無ければ null */
7081
+ function strandBadge(rec) {
7082
+ return hasStrand(rec) ? el("span", { class: "badge strand", title: "筋", text: rec.strand }) : null;
7181
7083
  }
7182
7084
  var FIRMNESS_CLASS = { "確定": "fixed", "仮": "tentative", "検討中": "open" };
7183
7085
  /** 固さの小札。語彙外は出さない(ビルド側でも捨てている・二重の網) */
@@ -7209,7 +7111,7 @@ ${calendarAddUrl.toString()}
7209
7111
  if (url) return el("a", { class: "chip decided-by-link", href: url, target: "_blank", rel: "noopener", text: who.name });
7210
7112
  return el("span", { class: "chip", text: who.name });
7211
7113
  }
7212
- /** 検索に使う決めた人の表記(decidedBy があればそちら、無ければ deciders) */
7114
+ /** 検索に使う決めた人の表記(decidedBy だけ) */
7213
7115
  function deciderWords(d) {
7214
7116
  if (Array.isArray(d.decidedBy) && d.decidedBy.length) {
7215
7117
  return d.decidedBy.map(function (w) {
@@ -7220,7 +7122,7 @@ ${calendarAddUrl.toString()}
7220
7122
  return w && typeof w.name === "string" ? w.name : "";
7221
7123
  }).join(" ");
7222
7124
  }
7223
- return (d.deciders || []).join(" ");
7125
+ return "";
7224
7126
  }
7225
7127
 
7226
7128
  // 未確認が1件も無い一覧では絞り込みを出さない
@@ -7419,6 +7321,11 @@ ${calendarAddUrl.toString()}
7419
7321
  "先頭の frontmatter(識別カードと設定)は触らないでください。日付・進捗・実績値は書かないでください(変わるものの正本は課題管理ツール等の外部にあります)。",
7420
7322
  "書き込む前に、書いた内容を提示して承認を得てください。",
7421
7323
  ].join("\\n");
7324
+ // 「AIで編集」の起動文の status の指示。**記憶 v2 の案件には出さない**(common.no-draft-lock・draft/active の印を持たない)。
7325
+ // 非 v2 は今のまま(statusKeepLine と同じ文)。v2 では null を返し、呼び出し側が filter(Boolean) で落とす
7326
+ function goldStatusLine() {
7327
+ return SITE.memoryV2 ? null : "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。";
7328
+ }
7422
7329
  var GOLD_SKILL = {
7423
7330
  "Decisions": {
7424
7331
  noun: "決定",
@@ -7433,9 +7340,9 @@ ${calendarAddUrl.toString()}
7433
7340
  target + " を読んでから、" + subject + "を修正してください。",
7434
7341
  "何を直すかは、まずわたしに質問してください。",
7435
7342
  "決定の内容そのものが変わる場合は、この記録を書き換えず、supersedes で新しい記録を作ってください。",
7436
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7343
+ goldStatusLine(),
7437
7344
  "書き込む前に、変更内容を提示して承認を得てください。",
7438
- ].join("\\n");
7345
+ ].filter(Boolean).join("\\n");
7439
7346
  },
7440
7347
  },
7441
7348
  "Glossary": {
@@ -7450,9 +7357,9 @@ ${calendarAddUrl.toString()}
7450
7357
  return [
7451
7358
  target + " を読んでから、" + subject + "を修正してください。",
7452
7359
  "何を直すかは、まずわたしに質問してください。",
7453
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7360
+ goldStatusLine(),
7454
7361
  "書き込む前に、変更内容を提示して承認を得てください。",
7455
- ].join("\\n");
7362
+ ].filter(Boolean).join("\\n");
7456
7363
  },
7457
7364
  },
7458
7365
  "Members": {
@@ -7467,9 +7374,9 @@ ${calendarAddUrl.toString()}
7467
7374
  return [
7468
7375
  target + " を読んでから、" + subject + "を修正してください。",
7469
7376
  "何を直すかは、まずわたしに質問してください。",
7470
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7377
+ goldStatusLine(),
7471
7378
  "書き込む前に、変更内容を提示して承認を得てください。",
7472
- ].join("\\n");
7379
+ ].filter(Boolean).join("\\n");
7473
7380
  },
7474
7381
  },
7475
7382
  "Rules": {
@@ -7484,9 +7391,9 @@ ${calendarAddUrl.toString()}
7484
7391
  return [
7485
7392
  target + " を読んでから、" + subject + "を修正してください。",
7486
7393
  "何を直すかは、まずわたしに質問してください。",
7487
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7394
+ goldStatusLine(),
7488
7395
  "書き込む前に、変更内容を提示して承認を得てください。",
7489
- ].join("\\n");
7396
+ ].filter(Boolean).join("\\n");
7490
7397
  },
7491
7398
  },
7492
7399
  };
@@ -8512,7 +8419,7 @@ ${calendarAddUrl.toString()}
8512
8419
  }
8513
8420
  }
8514
8421
 
8515
- var listState = { tab: DEFAULT_TAB, q: "", month: "", status: "", topic: "", page: 1 };
8422
+ var listState = { tab: DEFAULT_TAB, q: "", month: "", status: "", strand: "", page: 1 };
8516
8423
 
8517
8424
  // 一覧のページネーション(描画コスト対策。1ページあたりの件数)
8518
8425
  var PAGE_SIZE = 30;
@@ -8558,7 +8465,7 @@ ${calendarAddUrl.toString()}
8558
8465
 
8559
8466
  /**
8560
8467
  * 一覧カードの上の段(左側)に出す、記録に既にある中身(#1094・オーナー決定 10/14)。
8561
- * 用語=別名(synonyms)・ルール=いつからか(derived_from の決定の日付)・関係者=読み仮名(yomi)と所属(org)。
8468
+ * 用語=別名(synonyms)・関係者=読み仮名(yomi)と所属(org)。
8562
8469
  * 無い記録は空の配列を返す(段そのものを作らない)。ID・メールアドレスは出さない。
8563
8470
  */
8564
8471
  function cardFacets(rec) {
@@ -8574,19 +8481,6 @@ ${calendarAddUrl.toString()}
8574
8481
  var shown = syn.slice(0, 3).join("・") + (syn.length > 3 ? " ほか " + (syn.length - 3) : "");
8575
8482
  out.push(el("span", { class: "card-facet card-facet-alias", text: "別名 " + shown }));
8576
8483
  }
8577
- } else if (rec.rtype === "rule" || sec === "Rules" || sec === "ルール") {
8578
- var days = [];
8579
- (rec.relations || []).forEach(function (rl) {
8580
- if (!rl || rl.rel !== "derived_from") return;
8581
- var d = byId[rl.target];
8582
- var m = d && d._kind === "decision" && typeof d.date === "string" ? d.date.match(/^\\d{4}-(\\d{2})-(\\d{2})$/) : null;
8583
- if (m) days.push(d.date);
8584
- });
8585
- if (days.length) {
8586
- days.sort();
8587
- var p = days[0].split("-");
8588
- out.push(el("span", { class: "card-facet card-facet-since", text: parseInt(p[1], 10) + "/" + parseInt(p[2], 10) + " の決定から" }));
8589
- }
8590
8484
  } else if (isMemberRec(rec)) {
8591
8485
  var yomi = typeof fm.yomi === "string" ? fm.yomi.trim() : "";
8592
8486
  var org = typeof fm.org === "string" ? fm.org.trim() : "";
@@ -8673,7 +8567,7 @@ ${calendarAddUrl.toString()}
8673
8567
  text: "決定・用語・レポートを起点に、つながり(根拠・出典・リンク)を1列ずつ辿る表示です。行をクリックすると右に次の列が開きます。",
8674
8568
  },
8675
8569
  "story": {
8676
- text: "このプロジェクトの日々の動きを、日次・週次・月次に分けてまとめた記録です。直したいことや足したいことは、各カードの「GitHub で追記する」から書けます。",
8570
+ text: "このプロジェクトの日々の動きを、日次・週次・月次に分けてまとめた記録です。直したいことや足したいことは、各カードの「GitHubで編集」か「AIで編集」から書けます。",
8677
8571
  },
8678
8572
  "dir:レポート": {
8679
8573
  text: "レポートの生成は終了し、履歴として凍結されています(レポートはSlack配信に一本化されました)。以下は過去に生成されたレコードです。",
@@ -8722,6 +8616,28 @@ ${calendarAddUrl.toString()}
8722
8616
  renderList();
8723
8617
  }
8724
8618
 
8619
+ // ストーリーの日・週・月のカードの直し口(仕様 7-5)。「AIで編集」と「GitHubで編集」を並べる。人の追記の節は置かない。
8620
+ // 🔴 AI の起動文に入れるパスは、build が日付の形(YYYY-MM-DD・YYYY-MM)だけ通した鍵から作る(aiFenceScrub も通す)。frontmatter の date・relations は触らせない
8621
+ var STORY_DAYS_BASE = "Cortex/Story/Days/";
8622
+ var STORY_WEEKS_BASE = "Cortex/Story/Weeks/";
8623
+ var STORY_MONTHS_BASE = "Cortex/Story/Months/";
8624
+ function storyEditPrompt(path) {
8625
+ return [
8626
+ aiFenceScrub(path) + " を読んでから、このストーリーのページを直してください。",
8627
+ "何を直すか、足したいことは何かを、まずわたしに質問してください。",
8628
+ "先頭の frontmatter(date・relations)は触らないでください。機械が付けた印のコメントも消さないでください。",
8629
+ "このページの外の記録(決定・用語・関係者・ルール)は書き換えないでください。",
8630
+ "書き込む前に、変更内容を提示して承認を得てください。",
8631
+ ].join("\\n") + AI_COMMON;
8632
+ }
8633
+ function storyEditRow(path, editUrl) {
8634
+ var row = el("div", { class: "detail-actions-row story-card-actions" }, [
8635
+ aiLink("ai-edit-btn", storyEditPrompt(path), "AIで編集"),
8636
+ ]);
8637
+ if (editUrl) row.appendChild(el("a", { class: "edit-btn", href: editUrl, target: "_blank", rel: "noopener", text: "GitHubで編集" }));
8638
+ return row;
8639
+ }
8640
+
8725
8641
  // 日ごとのカード(新しい日が上=build が並べた順のまま)。動きのない日は「◯月◯日は動きはありませんでした」の1行
8726
8642
  function renderStoryDaily() {
8727
8643
  var days = SITE.story || [];
@@ -8734,9 +8650,10 @@ ${calendarAddUrl.toString()}
8734
8650
  days.forEach(function (d) {
8735
8651
  // 動きのない日は薄い 1 行(日付+文言。畳んだ行は「9/10〜9/18」)
8736
8652
  if (d.quiet) {
8737
- list.appendChild(el("div", { class: "story-quiet" }, [
8653
+ list.appendChild(el("div", { class: "story-quiet" + (d.failed ? " story-quiet-failed" : "") }, [
8738
8654
  el("span", { class: "story-quiet-date", text: d.heading || d.date }),
8739
- el("span", { text: d.pending ? " はまだ書けていません" : " は動きはありませんでした" }),
8655
+ // 夜の更新が成功した日は「動きはありませんでした」・成功していない日は失敗として出す(畳んだ行は「この間」)
8656
+ el("span", { text: d.failed ? (d.fromDate ? " この間の更新に失敗しています" : " この日の更新に失敗しています") : " は動きはありませんでした" }),
8740
8657
  ]));
8741
8658
  return;
8742
8659
  }
@@ -8744,18 +8661,17 @@ ${calendarAddUrl.toString()}
8744
8661
  el("h3", { class: "story-card-heading", text: d.heading || d.date }),
8745
8662
  d.bodyHtml ? el("div", { class: "body", html: d.bodyHtml }) : null,
8746
8663
  // その日のファイルを GitHub で開く(表示の文字にファイル名を出さない)。URL が無い案件は出さない
8747
- d.editUrl ? el("a", { class: "story-card-edit", href: d.editUrl, target: "_blank", rel: "noopener", text: "GitHub で追記する" }) : null,
8664
+ storyEditRow(STORY_DAYS_BASE + d.date.slice(0, 7) + "/" + d.date + ".md", d.editUrl),
8748
8665
  ]));
8749
8666
  });
8750
8667
  app.appendChild(list);
8751
8668
  }
8752
8669
 
8753
8670
  // 週・月のあらすじカード(局面・流れ・人の追記・GitHub のリンク)。見出し・局面は build が作った文字列(heading/phase)をそのまま使う
8754
- function storyDigestCard(entry, phaseLabel) {
8755
- var human = entry.humanHtml ? el("div", { class: "story-digest-human" }, [
8756
- el("h4", { text: "人の追記" }),
8757
- el("div", { class: "body", html: entry.humanHtml }),
8758
- ]) : null;
8671
+ function storyDigestCard(entry, phaseLabel, kind) {
8672
+ // 「人の追記」の節は置かない。古いファイルに節が残っていても、見出しと枠は出さず中身だけ本文の続きに出す
8673
+ var human = entry.humanHtml ? el("div", { class: "body", html: entry.humanHtml }) : null;
8674
+ var base = kind === "month" ? STORY_MONTHS_BASE : STORY_WEEKS_BASE;
8759
8675
  return el("section", { class: "story-card" }, [
8760
8676
  el("h3", { class: "story-card-heading", text: entry.heading }),
8761
8677
  entry.phase ? el("p", { class: "story-phase" }, [
@@ -8764,7 +8680,7 @@ ${calendarAddUrl.toString()}
8764
8680
  ]) : null,
8765
8681
  entry.flowHtml ? el("div", { class: "body", html: entry.flowHtml }) : null,
8766
8682
  human,
8767
- entry.editUrl ? el("a", { class: "story-card-edit", href: entry.editUrl, target: "_blank", rel: "noopener", text: "GitHub で追記する" }) : null,
8683
+ storyEditRow(base + entry.key + ".md", entry.editUrl),
8768
8684
  ]);
8769
8685
  }
8770
8686
 
@@ -8813,14 +8729,14 @@ ${calendarAddUrl.toString()}
8813
8729
  for (var wk = curMonday; !have[wk] && wk >= earliestMonday; wk = storyPrevWeekKey(wk)) {
8814
8730
  list.appendChild(el("section", { class: "story-card" }, [
8815
8731
  el("h3", { class: "story-card-heading", text: storyWeekLabel(wk) }),
8816
- el("p", { class: "story-empty", text: "週が閉じて 2 日後の夜に作ります" }),
8732
+ el("p", { class: "story-empty", text: "週の終わりの日の夜に作ります" }),
8817
8733
  ]));
8818
8734
  }
8819
8735
  }
8820
8736
  if (!weeks.length && !list.children.length) {
8821
- list.appendChild(el("p", { class: "story-empty", text: "あらすじはまだありません(週が閉じて 2 日後の夜に作ります)" }));
8737
+ list.appendChild(el("p", { class: "story-empty", text: "あらすじはまだありません(週の終わりの日の夜に作ります)" }));
8822
8738
  } else {
8823
- weeks.forEach(function (w) { list.appendChild(storyDigestCard(w, "この週の局面")); });
8739
+ weeks.forEach(function (w) { list.appendChild(storyDigestCard(w, "この週の局面", "week")); });
8824
8740
  }
8825
8741
  app.appendChild(list);
8826
8742
  }
@@ -8839,11 +8755,11 @@ ${calendarAddUrl.toString()}
8839
8755
  for (var mo = curMonth; !have[mo] && mo >= earliestMonth; mo = storyPrevMonthKey(mo)) {
8840
8756
  list.appendChild(el("section", { class: "story-card" }, [
8841
8757
  el("h3", { class: "story-card-heading", text: monthLabel(mo) }),
8842
- el("p", { class: "story-empty", text: "月が閉じて 3 日後の夜に作ります" }),
8758
+ el("p", { class: "story-empty", text: "月の終わりの日の夜に作ります" }),
8843
8759
  ]));
8844
8760
  }
8845
8761
  }
8846
- months.forEach(function (m) { list.appendChild(storyDigestCard(m, "この月の局面")); });
8762
+ months.forEach(function (m) { list.appendChild(storyDigestCard(m, "この月の局面", "month")); });
8847
8763
  app.appendChild(list);
8848
8764
  }
8849
8765
 
@@ -16984,7 +16900,7 @@ ${calendarAddUrl.toString()}
16984
16900
  * ## なぜ makeModal を使わないのか(一番大事)
16985
16901
  *
16986
16902
  * **makeModal は開いているモーダルを畳む**(existing.__close(true))。
16987
- * ところが確認が要る5か所は**すべて能力モーダルの中にいる**——
16903
+ * ところが確認が要る場所(confirmDanger の呼び出し 3 か所)は**すべて能力モーダルの中にいる**——
16988
16904
  * openCapabilityModal の items.forEach(m.modal.appendChild(n)) は
16989
16905
  * **ノードの移動**なので、利用者が「追加」を押した時点でフォームはモーダルの子。
16990
16906
  * makeModal で確認を開くと**親ごと消え、フォームが無くなる**。
@@ -19719,12 +19635,12 @@ ${calendarAddUrl.toString()}
19719
19635
  if (statusOptsD.length) {
19720
19636
  filters.appendChild(buildSelect("すべての状態", statusOptsD, listState.status, function (v) { listState.status = v; listState.page = 1; drawCards(); }, statusLabel));
19721
19637
  }
19722
- // 論点の札(#1094)。札を持つ決定が 1 件も無い案件では出さない
19723
- var topicOpts = topicOptions(visibleRecords(SITE.decisions));
19724
- if (topicOpts.length) {
19725
- var topicSel = buildSelect("すべての論点", topicOpts, listState.topic, function (v) { listState.topic = v; listState.page = 1; drawCards(); });
19726
- topicSel.classList.add("topic-filter");
19727
- filters.appendChild(topicSel);
19638
+ // 筋の札(#1094)。札を持つ決定が 1 件も無い案件では出さない
19639
+ var strandOpts = strandOptions(visibleRecords(SITE.decisions));
19640
+ if (strandOpts.length) {
19641
+ var strandSel = buildSelect("すべての筋", strandOpts, listState.strand, function (v) { listState.strand = v; listState.page = 1; drawCards(); });
19642
+ strandSel.classList.add("strand-filter");
19643
+ filters.appendChild(strandSel);
19728
19644
  }
19729
19645
  app.appendChild(filters);
19730
19646
 
@@ -19749,7 +19665,7 @@ ${calendarAddUrl.toString()}
19749
19665
  }
19750
19666
 
19751
19667
  /**
19752
- * 今の絞り込み(検索語・期間・状態・論点)を当てた決定の一覧(並びは
19668
+ * 今の絞り込み(検索語・期間・状態・筋)を当てた決定の一覧(並びは
19753
19669
  * SITE.decisions の順=新しい順のまま)。drawCards と、詳細の「前へ/次へ」
19754
19670
  * (#2)の両方がここを通る——一覧の並びと前後移動の並びがずれないように、口を1つにする。
19755
19671
  */
@@ -19760,21 +19676,21 @@ ${calendarAddUrl.toString()}
19760
19676
  var out = all.filter(function (d) {
19761
19677
  if (listState.month && d.date.slice(0, 7) !== listState.month) return false;
19762
19678
  if (!matchesStatusFilter(d)) return false;
19763
- if (!matchesTopicFilter(d)) return false;
19679
+ if (!matchesStrandFilter(d)) return false;
19764
19680
  if (q) {
19765
19681
  var hay = (d.title + " " + d.summary + " " + d.searchText + " " + deciderWords(d)).toLowerCase();
19766
19682
  if (hay.indexOf(q) === -1) return false;
19767
19683
  }
19768
19684
  return true;
19769
19685
  });
19770
- // 同じ論点の中は新しい順(決定日の降順 → ID の降順)
19771
- if (listState.topic) out.sort(newestDecisionFirst);
19686
+ // 同じ筋の中は新しい順(決定日の降順 → ID の降順)
19687
+ if (listState.strand) out.sort(newestDecisionFirst);
19772
19688
  return out;
19773
19689
  }
19774
- /** 論点の絞り込み(#1094)。選んでいなければ全件、選んだら同じ札の決定だけ */
19775
- function matchesTopicFilter(d) {
19776
- if (!listState.topic) return true;
19777
- return hasTopic(d) && d.topic === listState.topic;
19690
+ /** 筋の絞り込み(#1094)。選んでいなければ全件、選んだら同じ札の決定だけ */
19691
+ function matchesStrandFilter(d) {
19692
+ if (!listState.strand) return true;
19693
+ return hasStrand(d) && d.strand === listState.strand;
19778
19694
  }
19779
19695
 
19780
19696
  function drawCards() {
@@ -19798,11 +19714,9 @@ ${calendarAddUrl.toString()}
19798
19714
  pg.slice.forEach(function (d) {
19799
19715
  var head = cardHead(d, [
19800
19716
  draftBadge(d),
19801
- retiredBadge(d),
19802
- latestBadge(d),
19803
19717
  el("span", { class: "mono", text: d.date || "----" }),
19804
19718
  firmnessBadge(d),
19805
- topicBadge(d),
19719
+ strandBadge(d),
19806
19720
  ], d.deleted ? " is-deleted" : "");
19807
19721
  // 消したレコードは一覧でも取り消し線(次のビルドまで一覧には残る)
19808
19722
  var card = el("div", { class: "card", title: d.id, "data-record-id": d.id }, head.concat([
@@ -19857,11 +19771,9 @@ ${calendarAddUrl.toString()}
19857
19771
  pg.slice.forEach(function (r) {
19858
19772
  var head = cardHead(r, [
19859
19773
  draftBadge(r),
19860
- retractedBadge(r),
19861
- latestBadge(r),
19862
19774
  r.date ? el("span", { class: "mono", text: r.date }) : null,
19863
19775
  ].concat(cardFacets(r)), r.deleted ? " is-deleted" : "");
19864
- var card = el("div", { class: "card" + retractedFadedClass(r), title: r.id, "data-record-id": r.id }, head.concat([
19776
+ var card = el("div", { class: "card", title: r.id, "data-record-id": r.id }, head.concat([
19865
19777
  r.summary ? el("p", { class: "card-summary", text: r.summary }) : null,
19866
19778
  ]));
19867
19779
  card.addEventListener("click", function () { go(r.id); });
@@ -20275,10 +20187,6 @@ ${calendarAddUrl.toString()}
20275
20187
  // 出し分けはサーバの DELETABLE_SECTIONS と同じ4区画。ここは「押せないボタンを
20276
20188
  // 出さない」ためのもので、**守りはサーバ側**(promote と同じ関係)。
20277
20189
  var DELETABLE_PATH = /^Cortex\\/(Decisions|Glossary|Members|Rules)\\/records\\/[^/]+\\.md$/;
20278
- // 削除で除外リストにも載る区画(サーバの DELETABLE_SECTIONS で値が null でない区画の写し)。
20279
- // Decisions は cortex-engine #551 Q7 で足した——消した下書きの決定の題名が README の「除外決定」に載り、
20280
- // 夜間の AI は同じ題の決定を二度と作らない(engine が「除外決定」を読むようになった)
20281
- var DELETE_EXCLUDES = { Decisions: true, Glossary: true, Members: true, Rules: true };
20282
20190
  function deletableRecordPath(rec) {
20283
20191
  if (!SITE.intake) return "";
20284
20192
  var p = repoPathOf(rec);
@@ -20287,31 +20195,6 @@ ${calendarAddUrl.toString()}
20287
20195
  var base = p.slice(p.lastIndexOf("/") + 1).toLowerCase();
20288
20196
  return base === "readme.md" || base === "template.md" ? "" : p;
20289
20197
  }
20290
- /** 削除で除外リストに載る区画なら、その区画の表示名。載らない区画(今は無い)は空文字 */
20291
- function deleteExclusionLabel(p) {
20292
- var m = /^Cortex\\/([^/]+)\\//.exec(p);
20293
- var dir = m ? m[1] : "";
20294
- return Object.prototype.hasOwnProperty.call(DELETE_EXCLUDES, dir) ? dirLabel(dir) : "";
20295
- }
20296
- /**
20297
- * 確認の文面。**何が起きるかを具体に書く**(消えるだけなのか、除外リストにも載るのか)。
20298
- *
20299
- * **人の手のある記録だけ、先頭の問いの行を替える**(cortex-engine #1094 段 4 問い 2・オーナーの
20300
- * 言葉のまま)。どの記録も消せるので、人が直した記録を消すときに一言だけ添える。問いを 2 か所に
20301
- * 分けない(症状の帯と問いの行を別々に足さない)。人の手はビルドが決める rec.humanTouched
20302
- * (status が人の値か、確認の帳簿に確認の行がある)。題名・除外の一覧の行は今のまま。
20303
- */
20304
- function deleteConfirmLines(rec, path) {
20305
- var lines = [rec.humanTouched === true ? "この記録は人が直しています。消しますか?" : "このレコードを削除しますか?", rec.title];
20306
- var label = deleteExclusionLabel(path);
20307
- if (label) {
20308
- // 🔴 **区画の呼び名をここに入れない。** 表示名を「関係者」に改めた一方、実際に書かれる
20309
- // 節の見出しは「## 除外メンバー」のまま(engine が実行時にその綴りで照合しており、改名
20310
- // すると削除した人が翌晩に全員復活する)。食い違う名前を出すより、節の名前を言わない
20311
- lines.push("削除すると、夜間のAIが同じ内容を再登録しないよう、除外の一覧にも追記されます。");
20312
- }
20313
- return lines;
20314
- }
20315
20198
  async function sendDeleteRecord(rec, path, msg, btn, onOk) {
20316
20199
  var intake = SITE.intake;
20317
20200
  if (!intake) return;
@@ -20413,8 +20296,9 @@ ${calendarAddUrl.toString()}
20413
20296
  *
20414
20297
  * **どの記録にも出す**(cortex-engine #1094 段 4 問い 2・2026-10-04 のオーナー決定)。8/28 の裁定
20415
20298
  * 「人間の承認が挟まったものは削除の選択肢を出さない」は置き換えた——画面を見る人には裏の
20416
- * 履歴が見えず、見た目の違いが無いのにボタンの有無が分かれるのは分からないため。人の手のある
20417
- * 記録は確認の文面(deleteConfirmLines)で一言添える。intake も status では断らない。
20299
+ * 履歴が見えず、見た目の違いが無いのにボタンの有無が分かれるのは分からないため。人の手のある記録にも
20300
+ * 同じ口を出す。確認は挟まない([spec:common.screen-delete-no-confirm]・git の履歴から戻せる。1 回押すと
20301
+ * op=delete-record が 1 回送られる)。intake も status では断らない。
20418
20302
  *
20419
20303
  * 呼び出し側は2つ:
20420
20304
  * - draftNote …… 未確認の記録。「確認済みにする」と並べて警告帯の中に置く
@@ -20424,13 +20308,12 @@ ${calendarAddUrl.toString()}
20424
20308
  var path = deletableRecordPath(rec);
20425
20309
  if (!path) return null;
20426
20310
  // **語尾の「…」は 2026-08-29 のオーナーFBで外した。** 二択の相方(「確認済みにする」)と
20427
- // 語の形が揃わず、片方だけが下書きのように見えていた。押した先に確認モーダルが必ず出ることは
20428
- // 語尾ではなく操作そのもの(confirmDanger を await する下の行)で担保している
20311
+ // 語の形が揃わず、片方だけが下書きのように見えていた。**確認は挟まない**
20312
+ // ([spec:common.screen-delete-no-confirm]・git の履歴から戻せる)
20429
20313
  var btn = el("button", { class: "record-delete-btn", type: "button", text: "削除する" });
20430
20314
  var msg = el("div", { class: "record-delete-msg" });
20431
20315
  btn.addEventListener("click", async function () {
20432
- // **確認を await する。** 落とすと Promise が truthy で確認なしに消える
20433
- if (!(await confirmDanger(deleteConfirmLines(rec, path), { okLabel: "削除する", returnTo: btn }))) return;
20316
+ // [spec:common.screen-delete-no-confirm] 確認モーダルは挟まず、押したらそのまま 1 回送る
20434
20317
  await sendDeleteRecord(rec, path, msg, btn, function () { markRecordDeleted(rec); markPageStale(); });
20435
20318
  });
20436
20319
  return { btn: btn, msg: msg };
@@ -20450,15 +20333,11 @@ ${calendarAddUrl.toString()}
20450
20333
  editRow.appendChild(del.btn);
20451
20334
  return del.msg; // 結果を出す行は操作列の下(呼び出し側が最後に並べる)
20452
20335
  }
20453
- /** 詳細ページの末尾(本文・参照の後)に、つながっている ID・その後の記録・AIの変更履歴・frontmatter を並べる */
20336
+ /** 詳細ページの末尾(本文・参照の後)に、つながっている ID・AIの変更履歴・frontmatter を並べる */
20454
20337
  function appendRecordFooter(rec) {
20455
20338
  // 「つながっている ID」は本文の後・「更新履歴」の前(関係者の記録だけ・#686)
20456
20339
  var linked = buildLinkedIds(rec);
20457
20340
  if (linked) app.appendChild(linked);
20458
- // 決定の「その後の記録」(担当者の答えの 1 行)も同じ席——**本文と参照を読んでから、その後を見る順**。
20459
- // 決定以外の記録・答えが無い決定は rec.followupHuman を持たないので null(要素を作らない)
20460
- var fu = followupSection(rec);
20461
- if (fu) app.appendChild(fu);
20462
20341
  var history = changeLogSection(rec);
20463
20342
  if (history) app.appendChild(history);
20464
20343
  var fmp = renderFmPanel(rec.fm);
@@ -20694,8 +20573,6 @@ ${calendarAddUrl.toString()}
20694
20573
 
20695
20574
  var metaR = el("div", { class: "detail-meta", title: r.id, "data-record-id": r.id }, [
20696
20575
  draftBadge(r),
20697
- retractedBadge(r),
20698
- latestBadge(r),
20699
20576
  r.date ? el("span", { class: "mono", text: r.date }) : null,
20700
20577
  r.summary ? el("span", { text: r.summary }) : null,
20701
20578
  ]);
@@ -20714,14 +20591,10 @@ ${calendarAddUrl.toString()}
20714
20591
  app.appendChild(genBody);
20715
20592
  loadBody(r, genBody);
20716
20593
 
20717
- // 関連の資料(#1094 F8)。本文の後・取り下げの節の前。ルール・用語にしか載らない
20594
+ // 関連の資料(#1094 F8)。本文の後。ルール・用語にしか載らない
20718
20595
  var relm2 = relatedMaterialsSection(r);
20719
20596
  if (relm2) app.appendChild(relm2);
20720
20597
 
20721
- // 取り下げ(便 4-2d)。本文の後・「その後の記録」の前。取り下げの無い記録では何も作らない
20722
- var retr = retractSection(r);
20723
- if (retr) app.appendChild(retr);
20724
-
20725
20598
  appendRecordFooter(r);
20726
20599
  }
20727
20600
 
@@ -20755,7 +20628,6 @@ ${calendarAddUrl.toString()}
20755
20628
  derived_from: { color: "#0d9488", label: "生成元", kind: "gold" },
20756
20629
  relates_to: { color: "#94a3b8", label: "関連", kind: "gold" },
20757
20630
  supersedes: { color: "#dc2626", label: "置換", kind: "gold" },
20758
- retracted_by: { color: "#dc2626", label: "取り下げ", kind: "gold", onlyWhenPresent: true },
20759
20631
  reference: { color: "#d1d5db", label: "参照", kind: "evidence" },
20760
20632
  source: { color: "#d1d5db", label: "出典", kind: "evidence" },
20761
20633
  link: { color: "#e2e8f0", label: "リンク", kind: "evidence" },
@@ -21380,7 +21252,7 @@ ${calendarAddUrl.toString()}
21380
21252
 
21381
21253
  var EDGE_DARK = {
21382
21254
  based_on: "rgba(125,165,255,0.85)", derived_from: "rgba(94,234,212,0.75)",
21383
- relates_to: "rgba(148,163,184,0.6)", supersedes: "rgba(248,113,113,0.9)", retracted_by: "rgba(248,113,113,0.9)",
21255
+ relates_to: "rgba(148,163,184,0.6)", supersedes: "rgba(248,113,113,0.9)",
21384
21256
  reference: "rgba(180,196,230,0.32)", source: "rgba(180,196,230,0.32)", link: "rgba(180,196,230,0.22)",
21385
21257
  about: "rgba(196,181,253,0.22)",
21386
21258
  decided_by: "rgba(244,114,182,0.75)",
@@ -21636,8 +21508,6 @@ ${calendarAddUrl.toString()}
21636
21508
 
21637
21509
  var meta = el("div", { class: "detail-meta" }, [
21638
21510
  draftBadge(d),
21639
- retiredBadge(d),
21640
- latestBadge(d),
21641
21511
  el("span", { class: "mono", text: d.date || "----" }),
21642
21512
  firmnessBadge(d),
21643
21513
  ]);
@@ -21656,22 +21526,17 @@ ${calendarAddUrl.toString()}
21656
21526
  app.appendChild(el("div", { class: "summary-box", text: d.summary }));
21657
21527
  }
21658
21528
 
21659
- // 論点(#1094)。札の無い決定では何も作らない
21660
- if (hasTopic(d)) {
21661
- app.appendChild(el("div", { class: "section-label", text: "論点" }));
21662
- app.appendChild(el("div", { class: "decision-topic" }, [el("span", { class: "chip", text: d.topic })]));
21529
+ // 筋(#1094)。札の無い決定では何も作らない
21530
+ if (hasStrand(d)) {
21531
+ app.appendChild(el("div", { class: "section-label", text: "筋" }));
21532
+ app.appendChild(el("div", { class: "decision-strand" }, [el("span", { class: "chip", text: d.strand })]));
21663
21533
  }
21664
21534
 
21665
- // 決めた人(#1094)。decided_by に読めた人がいればそちらを出し、いなければ(欄が無い・空・全部崩れ)今どおり deciders
21535
+ // 決めた人(#1094)。decided_by に読めた人がいれば出す(旧い deciders は読まない)
21666
21536
  var whoChips = Array.isArray(d.decidedBy) ? d.decidedBy.map(decidedByChip).filter(Boolean) : [];
21667
21537
  if (whoChips.length) {
21668
21538
  app.appendChild(el("div", { class: "section-label", text: "決めた人" }));
21669
21539
  app.appendChild(el("div", { class: "deciders decided-by" }, whoChips));
21670
- } else if (d.deciders && d.deciders.length) {
21671
- app.appendChild(el("div", { class: "section-label", text: "決定者" }));
21672
- app.appendChild(el("div", { class: "deciders" }, d.deciders.map(function (p) {
21673
- return el("span", { class: "chip", text: p });
21674
- })));
21675
21540
  }
21676
21541
 
21677
21542
  app.appendChild(el("div", { class: "section-label", text: "内容" }));
@@ -21718,7 +21583,7 @@ ${calendarAddUrl.toString()}
21718
21583
  // レコード情報(frontmatter)のパネルが英語の語のまま出さないためだけ(凡例の REL_LABEL には足さない)
21719
21584
  var REL_LABEL = {
21720
21585
  based_on: "根拠", derived_from: "由来", relates_to: "関連",
21721
- supersedes: "置換", superseded_by: "置換先", retracted_by: "取り下げ", reference: "参照", source: "出典", link: "リンク",
21586
+ supersedes: "置換", superseded_by: "置換先", reference: "参照", source: "出典", link: "リンク",
21722
21587
  about: "話題",
21723
21588
  decided_by: "決めた人",
21724
21589
  };
@@ -21733,7 +21598,7 @@ ${calendarAddUrl.toString()}
21733
21598
  (adjDir[e.from] = adjDir[e.from] || []).push({ id: e.to, rel: e.rel, dir: "out" });
21734
21599
  (adjDir[e.to] = adjDir[e.to] || []).push({ id: e.from, rel: e.rel, dir: "in" });
21735
21600
  });
21736
- var REL_ORDER = ["supersedes", "retracted_by", "based_on", "derived_from", "relates_to", "decided_by", "source", "reference", "link", "about"];
21601
+ var REL_ORDER = ["supersedes", "based_on", "derived_from", "relates_to", "decided_by", "source", "reference", "link", "about"];
21737
21602
 
21738
21603
  function recordText(rec) {
21739
21604
  if (!rec) return "";