@takagaki/cortex-decisions-viewer 0.12.141 → 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)と同じスペースを読むものを選びます。",
@@ -4962,6 +4967,8 @@ button.site-icon[aria-busy="true"] .site-icon-plus { opacity: 0; }
4962
4967
  新しい見た目は作らず、.card:hover と同じ強調(アクセント色の枠)を使い回す */
4963
4968
  .card.is-returned-to { border-color: var(--accent); }
4964
4969
  .card-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 12.5px; color: var(--muted); margin-bottom: 6px; }
4970
+ .card-facet { overflow-wrap: anywhere; min-width: 0; }
4971
+ .card-facet-yomi { font-size: 11.5px; }
4965
4972
  .card-titlerow { display: flex; align-items: baseline; gap: 12px; margin: 0 0 6px; }
4966
4973
  .card-titlerow .card-title { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; margin: 2px 0 0; }
4967
4974
  /* card-title はカードの見出し(#1 新しいタブでも開けるよう <a> にした)。見た目は元の <div> と揃える */
@@ -4989,8 +4996,6 @@ a.pager-btn:hover { text-decoration: none; }
4989
4996
  background: #eceef1; color: #41474f;
4990
4997
  }
4991
4998
  .badge.draft { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
4992
- /* 直近のGold昇格で作られたレコードの印。draft(黄・要対応)と区別できるよう、新着を示す緑系にする */
4993
- .badge.latest { background: #dcfce7; color: #166534; border: 1px solid #86efac; }
4994
4999
  .badge.error { background: #fee2e2; color: #b91c1c; border: 1px solid #fca5a5; }
4995
5000
  .draft-note {
4996
5001
  display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;
@@ -5020,15 +5025,15 @@ a.pager-btn:hover { text-decoration: none; }
5020
5025
  }
5021
5026
  .story-quiet { margin: -6px 0; padding: 0 18px; font-size: 12.5px; color: var(--muted); }
5022
5027
  .story-quiet-date { font-variant-numeric: tabular-nums; }
5028
+ .story-quiet-failed { color: #b91c1c; }
5023
5029
  .story-card-heading { margin: 0 0 8px; font-size: 15px; }
5024
- .story-card-edit { display: inline-block; margin-top: 8px; font-size: 12.5px; }
5030
+ .story-card-actions { margin-top: 10px; justify-content: flex-start; }
5025
5031
  .story-card .body h2 { font-size: 14px; margin: 14px 0 6px; }
5026
5032
  .story-card .body h3 { font-size: 13.5px; margin: 12px 0 6px; }
5027
5033
  /* 週・月のあらすじカード(#901)。週・月のファイルがある案件だけ使う */
5028
5034
  .story-empty { margin: 0; font-size: 13px; color: var(--muted); }
5029
5035
  .story-phase { margin: 0 0 8px; font-weight: 600; }
5030
5036
  .story-phase-label { display: inline-block; margin-right: 8px; font-size: 12px; color: var(--muted); font-weight: 400; }
5031
- .story-digest-human h4 { font-size: 13.5px; margin: 12px 0 6px; }
5032
5037
  /* ---- Home(案件の自己記述)---- */
5033
5038
  /* 未記入の警告。**画面でいちばん強い赤にする**——27案件中24案件が未記入のまま
5034
5039
  毎晩のAI生成が走っている状態で、控えめに出しても読まれない */
@@ -5303,25 +5308,18 @@ a.pager-btn:hover { text-decoration: none; }
5303
5308
  .ip-decide-msg:empty { display: none; }
5304
5309
  .ip-decide-msg.is-error { color: #b45309; }
5305
5310
  .ip-decided { font-size: 13px; font-weight: 600; color: #15803d; }
5306
- /* 決定の「その後」(担当者の答えの 1 行)。節は .followup-section */
5307
- .followup-section { margin: 14px 0 4px; }
5308
- /* 置き換え(#699 F3) */
5309
- .badge.retired { background: #f5f5f4; color: #57534e; border: 1px solid #d6d3d1; }
5310
- /* 取り下げ済みルールの薄い表示 */
5311
- .card.is-faded { opacity: .55; }
5312
- /* 論点・固さ(#1094)。欄の無い記録には付かない */
5313
- .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; }
5314
5313
  .badge.firmness-fixed { background: #ecfdf5; color: #047857; border: 1px solid #a7f3d0; }
5315
5314
  .badge.firmness-tentative { background: #fffbeb; color: #92400e; border: 1px solid #fde68a; }
5316
5315
  .badge.firmness-open { background: #f8fafc; color: #475569; border: 1px dashed #cbd5e1; }
5317
- .decision-topic { margin-bottom: 4px; }
5316
+ .decision-strand { margin-bottom: 4px; }
5318
5317
  .supersede-section { margin: 14px 0 4px; }
5319
5318
  .supersede-list { list-style: none; margin: 0 0 8px; padding: 0; }
5320
5319
  .supersede-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; font-size: 13.5px; line-height: 1.7; padding: 2px 0; }
5321
5320
  .supersede-id { font-size: 12.5px; color: var(--muted); word-break: break-all; }
5322
5321
  .supersede-candidate { font-size: 12px; color: #92400e; background: #fffbeb; border: 1px solid #fde68a; border-radius: 4px; padding: 0 6px; }
5323
5322
  .supersede-candidate-note { font-size: 13px; color: #92400e; margin: 0 0 4px; }
5324
- .followup-human { font-size: 13.5px; margin: 0 0 6px; color: #166534; }
5325
5323
  /* 押したあとの帯。draft(黄・要対応)と入れ替わるので、済んだと分かる緑にする */
5326
5324
  .promoted-note {
5327
5325
  display: flex; gap: 8px; align-items: flex-start;
@@ -6789,11 +6787,6 @@ ${calendarAddUrl.toString()}
6789
6787
  function draftBadge(rec) {
6790
6788
  return rec && unconfirmed(rec) ? el("span", { class: "badge draft", text: "AI生成・未確認" }) : null;
6791
6789
  }
6792
- // 直近のGold昇格で作られたレコードの印。レコードの date は決定日なので、日付順に並べても
6793
- // 「今回の実行で何が増えたか」は分からない。ビルド時に git から判定した結果(isLatest)を出す
6794
- function latestBadge(rec) {
6795
- return rec && rec.isLatest ? el("span", { class: "badge latest", text: "最新の生成" }) : null;
6796
- }
6797
6790
  // 詳細ページの警告。バッジより強く「そのまま信じないでほしい」と伝える。
6798
6791
  // **確認済みにできる記録には、その場で上げるボタンを並べる**(下の promotableRecordPath)。
6799
6792
  // ボタンが出せないとき(受け口が未設定・パスが解決できない)は、これまでどおり
@@ -6922,8 +6915,6 @@ ${calendarAddUrl.toString()}
6922
6915
  function markPromoted(rec, note) {
6923
6916
  // **元データも直す。** 一覧へ戻って開き直しても未確認に戻らないようにする
6924
6917
  rec.rstatus = "active";
6925
- // 確認済みにした記録は人の手のある記録(削除の確認の先頭の行が変わる・#1094 4-1)
6926
- rec.humanTouched = true;
6927
6918
  var host = note.parentNode;
6928
6919
  if (!host) return;
6929
6920
  var badge = host.querySelector(".detail-meta .badge.draft");
@@ -6946,67 +6937,23 @@ ${calendarAddUrl.toString()}
6946
6937
  return ps.filter(function (one) { return !ipAnswered(rec, one); });
6947
6938
  }
6948
6939
 
6949
- // 状態の絞り込み。**未確認と置き換え済みを同じセレクトに並べる**(導線を増やさない)
6940
+ // 状態の絞り込み。未確認のみ(draft)の選択肢だけを持つ
6950
6941
  function statusLabel(v) {
6951
- if (v === RETIRED_FILTER) return "置き換え済み";
6952
- if (v === RETRACTED_FILTER) return "取り下げ";
6953
6942
  return v === "draft" ? "未確認のみ" : v;
6954
6943
  }
6955
6944
  /** 一覧に出す選択肢。**該当が1件も無い状態は選択肢に出さない**(押しても0件の項目を並べない) */
6956
6945
  function statusFilterOptions(items) {
6957
6946
  var opts = [];
6958
6947
  if (hasUnverified(items)) opts.push("draft");
6959
- // 置き換え済み(#699 F3)。決定にしか付かない印なので、決定の一覧でだけ選択肢になる
6960
- if ((items || []).some(isRetired)) opts.push(RETIRED_FILTER);
6961
- // 取り下げ(便 4-2d)。ルールにしか付かない印なので、ルールの一覧でだけ選択肢になる
6962
- if ((items || []).some(isRetracted)) opts.push(RETRACTED_FILTER);
6963
6948
  return opts;
6964
6949
  }
6965
- /** 絞り込みの判定。frontmatter の status との素の比較は「未確認のみ」と置き換え済み以外のとき */
6950
+ /** 絞り込みの判定。frontmatter の status との素の比較は「未確認のみ」以外のとき */
6966
6951
  function matchesStatusFilter(rec) {
6967
6952
  if (!listState.status) return true;
6968
- // 決定以外の一覧(タブを移っても絞り込みは残る)では絞らない——全件が消えないように
6969
- if (listState.status === RETIRED_FILTER) return rec && rec._kind === "decision" ? isRetired(rec) : true;
6970
- if (listState.status === RETRACTED_FILTER) return rec && rec._kind === "generic" && rec._section === "Rules" ? isRetracted(rec) : true;
6971
6953
  // 「未確認のみ」は口に聞く(札と同じ答え)。それ以外の値は従来どおりの素の比較
6972
6954
  if (listState.status === "draft") return unconfirmed(rec);
6973
6955
  return rec.rstatus === listState.status;
6974
6956
  }
6975
- /* -------------------------------------------------------------------------
6976
- * 決定の「その後」(人の答え・frontmatter の followup:)
6977
- * -------------------------------------------------------------------------
6978
- * 画面に出すのは、担当者が答えた 1 行(4 語)だけ。夜間の帳簿は画面に出さない・読まない
6979
- * (PR のマージを完了と数える差を画面から外す・#1094 35d)。答えを書く押しボタンも置かない。
6980
- * 🔴 答えが無い決定では要素を 1 つも作らない。
6981
- */
6982
- /** 担当者の答え(frontmatter の followup:)の 1 行。日付は括弧で添える */
6983
- var FOLLOWUP_HUMAN_LABEL = {
6984
- confirmed: "担当者が正しいと確認",
6985
- done: "担当者が実施済みにしました",
6986
- dropped: "担当者が取りやめと記録",
6987
- ignore: "担当者が追わなくてよいと記録",
6988
- };
6989
- /** 表からラベルを引く(__proto__ や toString のような鍵で Object の中身を拾わない) */
6990
- function followupLabel(table, k) {
6991
- return Object.prototype.hasOwnProperty.call(table, k) ? table[k] : "";
6992
- }
6993
- function hasFollowupHuman(rec) {
6994
- return !!(rec && rec.followupHuman && followupLabel(FOLLOWUP_HUMAN_LABEL, rec.followupHuman.state));
6995
- }
6996
- function followupHumanLine(fh) {
6997
- return el("p", { class: "followup-human", text: followupLabel(FOLLOWUP_HUMAN_LABEL, fh.state) + "(" + fh.at + ")" });
6998
- }
6999
-
7000
- /** 詳細の節「その後の記録」。**担当者の答えが無ければ null**(要素を作らない) */
7001
- function followupSection(rec) {
7002
- if (!hasFollowupHuman(rec)) return null;
7003
- var box = el("section", { class: "followup-section" }, [
7004
- el("div", { class: "section-label", text: "その後の記録" }),
7005
- ]);
7006
- box.appendChild(followupHumanLine(rec.followupHuman));
7007
- return box;
7008
- }
7009
-
7010
6957
  /* -------------------------------------------------------------------------
7011
6958
  * 置き換え(#699 F3・cortex-engine #1094 段 4 の 4-1)
7012
6959
  * -------------------------------------------------------------------------
@@ -7016,33 +6963,6 @@ ${calendarAddUrl.toString()}
7016
6963
  * 新しい側がまだ人の確認を経ていない)。
7017
6964
  * 🔴 古い側の superseded_by(夜間の精製が書く写し)は画面でも読まない。
7018
6965
  */
7019
- var RETIRED_FILTER = "retired";
7020
- /** もう有効でない(確定した置き換えが 1 本以上) */
7021
- function isRetired(rec) {
7022
- return !!(rec && rec.supersededBy && rec.supersededBy.retired);
7023
- }
7024
- /** 一覧・詳細の印。判定は置き換えの逆引き(supersedes.ts)だけが正 */
7025
- function retiredBadge(rec) {
7026
- if (!isRetired(rec)) return null;
7027
- return el("span", { class: "badge retired", text: "置き換え済み" });
7028
- }
7029
- /**
7030
- * ルールの取り下げ(cortex-engine #1094 便 4-2d)。ビルドが relations[retracted_by] から rec.retractedBy
7031
- * (取り下げを決めた決定・無ければキーごと無い)を載せてある。**1 本以上あれば取り下げ済み**。
7032
- * 札・薄く出す・詳細の節は、決定の「置き換えられた」と同じ部品を使う(本文は消さない)
7033
- */
7034
- var RETRACTED_FILTER = "retracted";
7035
- function isRetracted(rec) {
7036
- return !!(rec && rec._kind === "generic" && rec.retractedBy && rec.retractedBy.length);
7037
- }
7038
- function retractedBadge(rec) {
7039
- if (!isRetracted(rec)) return null;
7040
- return el("span", { class: "badge retired", text: "取り下げ" });
7041
- }
7042
- /** 取り下げ済みのルールを薄く出す(一覧のカード) */
7043
- function retractedFadedClass(rec) {
7044
- return isRetracted(rec) ? " is-faded" : "";
7045
- }
7046
6966
  /**
7047
6967
  * 詳細の節「関連の資料」(cortex-engine #1094 F8)。記録を生んだ会話に貼られた資料へのリンク。
7048
6968
  * 根拠(「参照」)とは混ぜない。ビルドが engine と同じ門で検めてあるが、画面でも http(s) だけをリンクにする(二重に見る)。
@@ -7064,21 +6984,6 @@ ${calendarAddUrl.toString()}
7064
6984
  box.appendChild(ul);
7065
6985
  return box;
7066
6986
  }
7067
- /** 詳細の節「取り下げを決めた決定」。取り下げの無い記録では null(要素を作らない) */
7068
- function retractSection(r) {
7069
- if (!isRetracted(r)) return null;
7070
- var box = el("div", { class: "supersede-section" });
7071
- box.appendChild(el("div", { class: "section-label", text: "取り下げを決めた決定" }));
7072
- var ul = el("ul", { class: "supersede-list supersede-by" });
7073
- r.retractedBy.forEach(function (b) {
7074
- var row = supersedeRow(b.id, b.date, false);
7075
- // 決定が実在しない(まだ同期されていない等)ときも、行を空にせず ID を出す
7076
- if (!row.firstChild) row.appendChild(el("span", { class: "supersede-id mono", text: b.id }));
7077
- ul.appendChild(row);
7078
- });
7079
- box.appendChild(ul);
7080
- return box;
7081
- }
7082
6987
  /** 候補の帯(症状)。行の札は「候補」とだけ言い、理由はこの帯 1 行に寄せる(繰り返さない) */
7083
6988
  var SUPERSEDE_CANDIDATE_NOTE = "前の決定は人が直しているため、置き換えは候補です";
7084
6989
  /** 決定 1 件の行。SITE にあれば題名で詳細へのリンク、無ければ ID だけ */
@@ -7143,24 +7048,23 @@ ${calendarAddUrl.toString()}
7143
7048
  }
7144
7049
 
7145
7050
  /* -------------------------------------------------------------------------
7146
- * 論点・固さ・決めた人(記憶 v2・cortex-engine #1094)
7051
+ * 筋・固さ・決めた人(記憶 v2・cortex-engine #1094)
7147
7052
  * -------------------------------------------------------------------------
7148
- * 欄(topic / firmness / decidedBy)は**ビルド側で語彙・形を確かめてある**。欄の無い記録では
7053
+ * 欄(strand / firmness / decidedBy)は**ビルド側で語彙・形を確かめてある**。欄の無い記録では
7149
7054
  * キーごと無いので、画面は有無だけを見る。🔴 **欄の無い記録だけの案件では要素を 1 つも作らない**
7150
7055
  * (絞り込み・固さの札・決めた人の節が出ない=今と同じ DOM)。
7151
- * 「置き換えられた」の判定は isRetired(ビルドが supersedes.ts で組んだ答え)をそのまま使う。
7152
7056
  */
7153
- function hasTopic(rec) {
7154
- return !!(rec && typeof rec.topic === "string" && rec.topic);
7057
+ function hasStrand(rec) {
7058
+ return !!(rec && typeof rec.strand === "string" && rec.strand);
7155
7059
  }
7156
- /** 論点の札の一覧(札を持つ決定が無ければ空) */
7157
- function topicOptions(items) {
7060
+ /** 筋の札の一覧(札を持つ決定が無ければ空) */
7061
+ function strandOptions(items) {
7158
7062
  var seen = {};
7159
7063
  var out = [];
7160
7064
  (items || []).forEach(function (d) {
7161
- if (!hasTopic(d) || Object.prototype.hasOwnProperty.call(seen, d.topic)) return;
7162
- seen[d.topic] = true;
7163
- 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);
7164
7068
  });
7165
7069
  return out.sort(function (a, b) { return a.localeCompare(b, "ja"); });
7166
7070
  }
@@ -7173,9 +7077,9 @@ ${calendarAddUrl.toString()}
7173
7077
  }
7174
7078
  return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
7175
7079
  }
7176
- /** 論点の札(一覧の行)。札が無ければ null */
7177
- function topicBadge(rec) {
7178
- 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;
7179
7083
  }
7180
7084
  var FIRMNESS_CLASS = { "確定": "fixed", "仮": "tentative", "検討中": "open" };
7181
7085
  /** 固さの小札。語彙外は出さない(ビルド側でも捨てている・二重の網) */
@@ -7207,7 +7111,7 @@ ${calendarAddUrl.toString()}
7207
7111
  if (url) return el("a", { class: "chip decided-by-link", href: url, target: "_blank", rel: "noopener", text: who.name });
7208
7112
  return el("span", { class: "chip", text: who.name });
7209
7113
  }
7210
- /** 検索に使う決めた人の表記(decidedBy があればそちら、無ければ deciders) */
7114
+ /** 検索に使う決めた人の表記(decidedBy だけ) */
7211
7115
  function deciderWords(d) {
7212
7116
  if (Array.isArray(d.decidedBy) && d.decidedBy.length) {
7213
7117
  return d.decidedBy.map(function (w) {
@@ -7218,7 +7122,7 @@ ${calendarAddUrl.toString()}
7218
7122
  return w && typeof w.name === "string" ? w.name : "";
7219
7123
  }).join(" ");
7220
7124
  }
7221
- return (d.deciders || []).join(" ");
7125
+ return "";
7222
7126
  }
7223
7127
 
7224
7128
  // 未確認が1件も無い一覧では絞り込みを出さない
@@ -7417,6 +7321,11 @@ ${calendarAddUrl.toString()}
7417
7321
  "先頭の frontmatter(識別カードと設定)は触らないでください。日付・進捗・実績値は書かないでください(変わるものの正本は課題管理ツール等の外部にあります)。",
7418
7322
  "書き込む前に、書いた内容を提示して承認を得てください。",
7419
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
+ }
7420
7329
  var GOLD_SKILL = {
7421
7330
  "Decisions": {
7422
7331
  noun: "決定",
@@ -7431,9 +7340,9 @@ ${calendarAddUrl.toString()}
7431
7340
  target + " を読んでから、" + subject + "を修正してください。",
7432
7341
  "何を直すかは、まずわたしに質問してください。",
7433
7342
  "決定の内容そのものが変わる場合は、この記録を書き換えず、supersedes で新しい記録を作ってください。",
7434
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7343
+ goldStatusLine(),
7435
7344
  "書き込む前に、変更内容を提示して承認を得てください。",
7436
- ].join("\\n");
7345
+ ].filter(Boolean).join("\\n");
7437
7346
  },
7438
7347
  },
7439
7348
  "Glossary": {
@@ -7448,9 +7357,9 @@ ${calendarAddUrl.toString()}
7448
7357
  return [
7449
7358
  target + " を読んでから、" + subject + "を修正してください。",
7450
7359
  "何を直すかは、まずわたしに質問してください。",
7451
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7360
+ goldStatusLine(),
7452
7361
  "書き込む前に、変更内容を提示して承認を得てください。",
7453
- ].join("\\n");
7362
+ ].filter(Boolean).join("\\n");
7454
7363
  },
7455
7364
  },
7456
7365
  "Members": {
@@ -7465,9 +7374,9 @@ ${calendarAddUrl.toString()}
7465
7374
  return [
7466
7375
  target + " を読んでから、" + subject + "を修正してください。",
7467
7376
  "何を直すかは、まずわたしに質問してください。",
7468
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7377
+ goldStatusLine(),
7469
7378
  "書き込む前に、変更内容を提示して承認を得てください。",
7470
- ].join("\\n");
7379
+ ].filter(Boolean).join("\\n");
7471
7380
  },
7472
7381
  },
7473
7382
  "Rules": {
@@ -7482,9 +7391,9 @@ ${calendarAddUrl.toString()}
7482
7391
  return [
7483
7392
  target + " を読んでから、" + subject + "を修正してください。",
7484
7393
  "何を直すかは、まずわたしに質問してください。",
7485
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7394
+ goldStatusLine(),
7486
7395
  "書き込む前に、変更内容を提示して承認を得てください。",
7487
- ].join("\\n");
7396
+ ].filter(Boolean).join("\\n");
7488
7397
  },
7489
7398
  },
7490
7399
  };
@@ -8510,7 +8419,7 @@ ${calendarAddUrl.toString()}
8510
8419
  }
8511
8420
  }
8512
8421
 
8513
- var listState = { tab: DEFAULT_TAB, q: "", month: "", status: "", topic: "", page: 1 };
8422
+ var listState = { tab: DEFAULT_TAB, q: "", month: "", status: "", strand: "", page: 1 };
8514
8423
 
8515
8424
  // 一覧のページネーション(描画コスト対策。1ページあたりの件数)
8516
8425
  var PAGE_SIZE = 30;
@@ -8554,6 +8463,33 @@ ${calendarAddUrl.toString()}
8554
8463
  return [meta, title];
8555
8464
  }
8556
8465
 
8466
+ /**
8467
+ * 一覧カードの上の段(左側)に出す、記録に既にある中身(#1094・オーナー決定 10/14)。
8468
+ * 用語=別名(synonyms)・関係者=読み仮名(yomi)と所属(org)。
8469
+ * 無い記録は空の配列を返す(段そのものを作らない)。ID・メールアドレスは出さない。
8470
+ */
8471
+ function cardFacets(rec) {
8472
+ var fm = rec.fm || {};
8473
+ var sec = rec._section;
8474
+ var out = [];
8475
+ function strs(v) {
8476
+ return (Array.isArray(v) ? v : []).map(function (x) { return typeof x === "string" ? x.trim() : ""; }).filter(Boolean);
8477
+ }
8478
+ if (rec.rtype === "term" || sec === "Glossary" || sec === "用語集") {
8479
+ var syn = strs(fm.synonyms);
8480
+ if (syn.length) {
8481
+ var shown = syn.slice(0, 3).join("・") + (syn.length > 3 ? " ほか " + (syn.length - 3) : "");
8482
+ out.push(el("span", { class: "card-facet card-facet-alias", text: "別名 " + shown }));
8483
+ }
8484
+ } else if (isMemberRec(rec)) {
8485
+ var yomi = typeof fm.yomi === "string" ? fm.yomi.trim() : "";
8486
+ var org = typeof fm.org === "string" ? fm.org.trim() : "";
8487
+ if (yomi) out.push(el("span", { class: "card-facet card-facet-yomi", text: yomi }));
8488
+ if (org) out.push(el("span", { class: "card-facet card-facet-org", text: org }));
8489
+ }
8490
+ return out;
8491
+ }
8492
+
8557
8493
  /**
8558
8494
  * 一覧カードの見出し(#1)。普通の a href="?id=..." にして、中クリック・
8559
8495
  * Ctrl/Cmd クリックで新しいタブでも開けるようにする(opsTabLink と同じ型)。
@@ -8631,7 +8567,7 @@ ${calendarAddUrl.toString()}
8631
8567
  text: "決定・用語・レポートを起点に、つながり(根拠・出典・リンク)を1列ずつ辿る表示です。行をクリックすると右に次の列が開きます。",
8632
8568
  },
8633
8569
  "story": {
8634
- text: "このプロジェクトの日々の動きを、日次・週次・月次に分けてまとめた記録です。直したいことや足したいことは、各カードの「GitHub で追記する」から書けます。",
8570
+ text: "このプロジェクトの日々の動きを、日次・週次・月次に分けてまとめた記録です。直したいことや足したいことは、各カードの「GitHubで編集」か「AIで編集」から書けます。",
8635
8571
  },
8636
8572
  "dir:レポート": {
8637
8573
  text: "レポートの生成は終了し、履歴として凍結されています(レポートはSlack配信に一本化されました)。以下は過去に生成されたレコードです。",
@@ -8680,6 +8616,28 @@ ${calendarAddUrl.toString()}
8680
8616
  renderList();
8681
8617
  }
8682
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
+
8683
8641
  // 日ごとのカード(新しい日が上=build が並べた順のまま)。動きのない日は「◯月◯日は動きはありませんでした」の1行
8684
8642
  function renderStoryDaily() {
8685
8643
  var days = SITE.story || [];
@@ -8692,9 +8650,10 @@ ${calendarAddUrl.toString()}
8692
8650
  days.forEach(function (d) {
8693
8651
  // 動きのない日は薄い 1 行(日付+文言。畳んだ行は「9/10〜9/18」)
8694
8652
  if (d.quiet) {
8695
- list.appendChild(el("div", { class: "story-quiet" }, [
8653
+ list.appendChild(el("div", { class: "story-quiet" + (d.failed ? " story-quiet-failed" : "") }, [
8696
8654
  el("span", { class: "story-quiet-date", text: d.heading || d.date }),
8697
- el("span", { text: d.pending ? " はまだ書けていません" : " は動きはありませんでした" }),
8655
+ // 夜の更新が成功した日は「動きはありませんでした」・成功していない日は失敗として出す(畳んだ行は「この間」)
8656
+ el("span", { text: d.failed ? (d.fromDate ? " この間の更新に失敗しています" : " この日の更新に失敗しています") : " は動きはありませんでした" }),
8698
8657
  ]));
8699
8658
  return;
8700
8659
  }
@@ -8702,18 +8661,17 @@ ${calendarAddUrl.toString()}
8702
8661
  el("h3", { class: "story-card-heading", text: d.heading || d.date }),
8703
8662
  d.bodyHtml ? el("div", { class: "body", html: d.bodyHtml }) : null,
8704
8663
  // その日のファイルを GitHub で開く(表示の文字にファイル名を出さない)。URL が無い案件は出さない
8705
- 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),
8706
8665
  ]));
8707
8666
  });
8708
8667
  app.appendChild(list);
8709
8668
  }
8710
8669
 
8711
8670
  // 週・月のあらすじカード(局面・流れ・人の追記・GitHub のリンク)。見出し・局面は build が作った文字列(heading/phase)をそのまま使う
8712
- function storyDigestCard(entry, phaseLabel) {
8713
- var human = entry.humanHtml ? el("div", { class: "story-digest-human" }, [
8714
- el("h4", { text: "人の追記" }),
8715
- el("div", { class: "body", html: entry.humanHtml }),
8716
- ]) : 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;
8717
8675
  return el("section", { class: "story-card" }, [
8718
8676
  el("h3", { class: "story-card-heading", text: entry.heading }),
8719
8677
  entry.phase ? el("p", { class: "story-phase" }, [
@@ -8722,7 +8680,7 @@ ${calendarAddUrl.toString()}
8722
8680
  ]) : null,
8723
8681
  entry.flowHtml ? el("div", { class: "body", html: entry.flowHtml }) : null,
8724
8682
  human,
8725
- 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),
8726
8684
  ]);
8727
8685
  }
8728
8686
 
@@ -8771,14 +8729,14 @@ ${calendarAddUrl.toString()}
8771
8729
  for (var wk = curMonday; !have[wk] && wk >= earliestMonday; wk = storyPrevWeekKey(wk)) {
8772
8730
  list.appendChild(el("section", { class: "story-card" }, [
8773
8731
  el("h3", { class: "story-card-heading", text: storyWeekLabel(wk) }),
8774
- el("p", { class: "story-empty", text: "週が閉じて 2 日後の夜に作ります" }),
8732
+ el("p", { class: "story-empty", text: "週の終わりの日の夜に作ります" }),
8775
8733
  ]));
8776
8734
  }
8777
8735
  }
8778
8736
  if (!weeks.length && !list.children.length) {
8779
- list.appendChild(el("p", { class: "story-empty", text: "あらすじはまだありません(週が閉じて 2 日後の夜に作ります)" }));
8737
+ list.appendChild(el("p", { class: "story-empty", text: "あらすじはまだありません(週の終わりの日の夜に作ります)" }));
8780
8738
  } else {
8781
- weeks.forEach(function (w) { list.appendChild(storyDigestCard(w, "この週の局面")); });
8739
+ weeks.forEach(function (w) { list.appendChild(storyDigestCard(w, "この週の局面", "week")); });
8782
8740
  }
8783
8741
  app.appendChild(list);
8784
8742
  }
@@ -8797,11 +8755,11 @@ ${calendarAddUrl.toString()}
8797
8755
  for (var mo = curMonth; !have[mo] && mo >= earliestMonth; mo = storyPrevMonthKey(mo)) {
8798
8756
  list.appendChild(el("section", { class: "story-card" }, [
8799
8757
  el("h3", { class: "story-card-heading", text: monthLabel(mo) }),
8800
- el("p", { class: "story-empty", text: "月が閉じて 3 日後の夜に作ります" }),
8758
+ el("p", { class: "story-empty", text: "月の終わりの日の夜に作ります" }),
8801
8759
  ]));
8802
8760
  }
8803
8761
  }
8804
- months.forEach(function (m) { list.appendChild(storyDigestCard(m, "この月の局面")); });
8762
+ months.forEach(function (m) { list.appendChild(storyDigestCard(m, "この月の局面", "month")); });
8805
8763
  app.appendChild(list);
8806
8764
  }
8807
8765
 
@@ -16942,7 +16900,7 @@ ${calendarAddUrl.toString()}
16942
16900
  * ## なぜ makeModal を使わないのか(一番大事)
16943
16901
  *
16944
16902
  * **makeModal は開いているモーダルを畳む**(existing.__close(true))。
16945
- * ところが確認が要る5か所は**すべて能力モーダルの中にいる**——
16903
+ * ところが確認が要る場所(confirmDanger の呼び出し 3 か所)は**すべて能力モーダルの中にいる**——
16946
16904
  * openCapabilityModal の items.forEach(m.modal.appendChild(n)) は
16947
16905
  * **ノードの移動**なので、利用者が「追加」を押した時点でフォームはモーダルの子。
16948
16906
  * makeModal で確認を開くと**親ごと消え、フォームが無くなる**。
@@ -19677,12 +19635,12 @@ ${calendarAddUrl.toString()}
19677
19635
  if (statusOptsD.length) {
19678
19636
  filters.appendChild(buildSelect("すべての状態", statusOptsD, listState.status, function (v) { listState.status = v; listState.page = 1; drawCards(); }, statusLabel));
19679
19637
  }
19680
- // 論点の札(#1094)。札を持つ決定が 1 件も無い案件では出さない
19681
- var topicOpts = topicOptions(visibleRecords(SITE.decisions));
19682
- if (topicOpts.length) {
19683
- var topicSel = buildSelect("すべての論点", topicOpts, listState.topic, function (v) { listState.topic = v; listState.page = 1; drawCards(); });
19684
- topicSel.classList.add("topic-filter");
19685
- 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);
19686
19644
  }
19687
19645
  app.appendChild(filters);
19688
19646
 
@@ -19707,7 +19665,7 @@ ${calendarAddUrl.toString()}
19707
19665
  }
19708
19666
 
19709
19667
  /**
19710
- * 今の絞り込み(検索語・期間・状態・論点)を当てた決定の一覧(並びは
19668
+ * 今の絞り込み(検索語・期間・状態・筋)を当てた決定の一覧(並びは
19711
19669
  * SITE.decisions の順=新しい順のまま)。drawCards と、詳細の「前へ/次へ」
19712
19670
  * (#2)の両方がここを通る——一覧の並びと前後移動の並びがずれないように、口を1つにする。
19713
19671
  */
@@ -19718,21 +19676,21 @@ ${calendarAddUrl.toString()}
19718
19676
  var out = all.filter(function (d) {
19719
19677
  if (listState.month && d.date.slice(0, 7) !== listState.month) return false;
19720
19678
  if (!matchesStatusFilter(d)) return false;
19721
- if (!matchesTopicFilter(d)) return false;
19679
+ if (!matchesStrandFilter(d)) return false;
19722
19680
  if (q) {
19723
19681
  var hay = (d.title + " " + d.summary + " " + d.searchText + " " + deciderWords(d)).toLowerCase();
19724
19682
  if (hay.indexOf(q) === -1) return false;
19725
19683
  }
19726
19684
  return true;
19727
19685
  });
19728
- // 同じ論点の中は新しい順(決定日の降順 → ID の降順)
19729
- if (listState.topic) out.sort(newestDecisionFirst);
19686
+ // 同じ筋の中は新しい順(決定日の降順 → ID の降順)
19687
+ if (listState.strand) out.sort(newestDecisionFirst);
19730
19688
  return out;
19731
19689
  }
19732
- /** 論点の絞り込み(#1094)。選んでいなければ全件、選んだら同じ札の決定だけ */
19733
- function matchesTopicFilter(d) {
19734
- if (!listState.topic) return true;
19735
- 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;
19736
19694
  }
19737
19695
 
19738
19696
  function drawCards() {
@@ -19756,11 +19714,9 @@ ${calendarAddUrl.toString()}
19756
19714
  pg.slice.forEach(function (d) {
19757
19715
  var head = cardHead(d, [
19758
19716
  draftBadge(d),
19759
- retiredBadge(d),
19760
- latestBadge(d),
19761
19717
  el("span", { class: "mono", text: d.date || "----" }),
19762
19718
  firmnessBadge(d),
19763
- topicBadge(d),
19719
+ strandBadge(d),
19764
19720
  ], d.deleted ? " is-deleted" : "");
19765
19721
  // 消したレコードは一覧でも取り消し線(次のビルドまで一覧には残る)
19766
19722
  var card = el("div", { class: "card", title: d.id, "data-record-id": d.id }, head.concat([
@@ -19815,11 +19771,9 @@ ${calendarAddUrl.toString()}
19815
19771
  pg.slice.forEach(function (r) {
19816
19772
  var head = cardHead(r, [
19817
19773
  draftBadge(r),
19818
- retractedBadge(r),
19819
- latestBadge(r),
19820
19774
  r.date ? el("span", { class: "mono", text: r.date }) : null,
19821
- ], r.deleted ? " is-deleted" : "");
19822
- var card = el("div", { class: "card" + retractedFadedClass(r), title: r.id, "data-record-id": r.id }, head.concat([
19775
+ ].concat(cardFacets(r)), r.deleted ? " is-deleted" : "");
19776
+ var card = el("div", { class: "card", title: r.id, "data-record-id": r.id }, head.concat([
19823
19777
  r.summary ? el("p", { class: "card-summary", text: r.summary }) : null,
19824
19778
  ]));
19825
19779
  card.addEventListener("click", function () { go(r.id); });
@@ -20233,10 +20187,6 @@ ${calendarAddUrl.toString()}
20233
20187
  // 出し分けはサーバの DELETABLE_SECTIONS と同じ4区画。ここは「押せないボタンを
20234
20188
  // 出さない」ためのもので、**守りはサーバ側**(promote と同じ関係)。
20235
20189
  var DELETABLE_PATH = /^Cortex\\/(Decisions|Glossary|Members|Rules)\\/records\\/[^/]+\\.md$/;
20236
- // 削除で除外リストにも載る区画(サーバの DELETABLE_SECTIONS で値が null でない区画の写し)。
20237
- // Decisions は cortex-engine #551 Q7 で足した——消した下書きの決定の題名が README の「除外決定」に載り、
20238
- // 夜間の AI は同じ題の決定を二度と作らない(engine が「除外決定」を読むようになった)
20239
- var DELETE_EXCLUDES = { Decisions: true, Glossary: true, Members: true, Rules: true };
20240
20190
  function deletableRecordPath(rec) {
20241
20191
  if (!SITE.intake) return "";
20242
20192
  var p = repoPathOf(rec);
@@ -20245,31 +20195,6 @@ ${calendarAddUrl.toString()}
20245
20195
  var base = p.slice(p.lastIndexOf("/") + 1).toLowerCase();
20246
20196
  return base === "readme.md" || base === "template.md" ? "" : p;
20247
20197
  }
20248
- /** 削除で除外リストに載る区画なら、その区画の表示名。載らない区画(今は無い)は空文字 */
20249
- function deleteExclusionLabel(p) {
20250
- var m = /^Cortex\\/([^/]+)\\//.exec(p);
20251
- var dir = m ? m[1] : "";
20252
- return Object.prototype.hasOwnProperty.call(DELETE_EXCLUDES, dir) ? dirLabel(dir) : "";
20253
- }
20254
- /**
20255
- * 確認の文面。**何が起きるかを具体に書く**(消えるだけなのか、除外リストにも載るのか)。
20256
- *
20257
- * **人の手のある記録だけ、先頭の問いの行を替える**(cortex-engine #1094 段 4 問い 2・オーナーの
20258
- * 言葉のまま)。どの記録も消せるので、人が直した記録を消すときに一言だけ添える。問いを 2 か所に
20259
- * 分けない(症状の帯と問いの行を別々に足さない)。人の手はビルドが決める rec.humanTouched
20260
- * (status が人の値か、確認の帳簿に確認の行がある)。題名・除外の一覧の行は今のまま。
20261
- */
20262
- function deleteConfirmLines(rec, path) {
20263
- var lines = [rec.humanTouched === true ? "この記録は人が直しています。消しますか?" : "このレコードを削除しますか?", rec.title];
20264
- var label = deleteExclusionLabel(path);
20265
- if (label) {
20266
- // 🔴 **区画の呼び名をここに入れない。** 表示名を「関係者」に改めた一方、実際に書かれる
20267
- // 節の見出しは「## 除外メンバー」のまま(engine が実行時にその綴りで照合しており、改名
20268
- // すると削除した人が翌晩に全員復活する)。食い違う名前を出すより、節の名前を言わない
20269
- lines.push("削除すると、夜間のAIが同じ内容を再登録しないよう、除外の一覧にも追記されます。");
20270
- }
20271
- return lines;
20272
- }
20273
20198
  async function sendDeleteRecord(rec, path, msg, btn, onOk) {
20274
20199
  var intake = SITE.intake;
20275
20200
  if (!intake) return;
@@ -20371,8 +20296,9 @@ ${calendarAddUrl.toString()}
20371
20296
  *
20372
20297
  * **どの記録にも出す**(cortex-engine #1094 段 4 問い 2・2026-10-04 のオーナー決定)。8/28 の裁定
20373
20298
  * 「人間の承認が挟まったものは削除の選択肢を出さない」は置き換えた——画面を見る人には裏の
20374
- * 履歴が見えず、見た目の違いが無いのにボタンの有無が分かれるのは分からないため。人の手のある
20375
- * 記録は確認の文面(deleteConfirmLines)で一言添える。intake も status では断らない。
20299
+ * 履歴が見えず、見た目の違いが無いのにボタンの有無が分かれるのは分からないため。人の手のある記録にも
20300
+ * 同じ口を出す。確認は挟まない([spec:common.screen-delete-no-confirm]・git の履歴から戻せる。1 回押すと
20301
+ * op=delete-record が 1 回送られる)。intake も status では断らない。
20376
20302
  *
20377
20303
  * 呼び出し側は2つ:
20378
20304
  * - draftNote …… 未確認の記録。「確認済みにする」と並べて警告帯の中に置く
@@ -20382,13 +20308,12 @@ ${calendarAddUrl.toString()}
20382
20308
  var path = deletableRecordPath(rec);
20383
20309
  if (!path) return null;
20384
20310
  // **語尾の「…」は 2026-08-29 のオーナーFBで外した。** 二択の相方(「確認済みにする」)と
20385
- // 語の形が揃わず、片方だけが下書きのように見えていた。押した先に確認モーダルが必ず出ることは
20386
- // 語尾ではなく操作そのもの(confirmDanger を await する下の行)で担保している
20311
+ // 語の形が揃わず、片方だけが下書きのように見えていた。**確認は挟まない**
20312
+ // ([spec:common.screen-delete-no-confirm]・git の履歴から戻せる)
20387
20313
  var btn = el("button", { class: "record-delete-btn", type: "button", text: "削除する" });
20388
20314
  var msg = el("div", { class: "record-delete-msg" });
20389
20315
  btn.addEventListener("click", async function () {
20390
- // **確認を await する。** 落とすと Promise が truthy で確認なしに消える
20391
- if (!(await confirmDanger(deleteConfirmLines(rec, path), { okLabel: "削除する", returnTo: btn }))) return;
20316
+ // [spec:common.screen-delete-no-confirm] 確認モーダルは挟まず、押したらそのまま 1 回送る
20392
20317
  await sendDeleteRecord(rec, path, msg, btn, function () { markRecordDeleted(rec); markPageStale(); });
20393
20318
  });
20394
20319
  return { btn: btn, msg: msg };
@@ -20408,15 +20333,11 @@ ${calendarAddUrl.toString()}
20408
20333
  editRow.appendChild(del.btn);
20409
20334
  return del.msg; // 結果を出す行は操作列の下(呼び出し側が最後に並べる)
20410
20335
  }
20411
- /** 詳細ページの末尾(本文・参照の後)に、つながっている ID・その後の記録・AIの変更履歴・frontmatter を並べる */
20336
+ /** 詳細ページの末尾(本文・参照の後)に、つながっている ID・AIの変更履歴・frontmatter を並べる */
20412
20337
  function appendRecordFooter(rec) {
20413
20338
  // 「つながっている ID」は本文の後・「更新履歴」の前(関係者の記録だけ・#686)
20414
20339
  var linked = buildLinkedIds(rec);
20415
20340
  if (linked) app.appendChild(linked);
20416
- // 決定の「その後の記録」(担当者の答えの 1 行)も同じ席——**本文と参照を読んでから、その後を見る順**。
20417
- // 決定以外の記録・答えが無い決定は rec.followupHuman を持たないので null(要素を作らない)
20418
- var fu = followupSection(rec);
20419
- if (fu) app.appendChild(fu);
20420
20341
  var history = changeLogSection(rec);
20421
20342
  if (history) app.appendChild(history);
20422
20343
  var fmp = renderFmPanel(rec.fm);
@@ -20652,8 +20573,6 @@ ${calendarAddUrl.toString()}
20652
20573
 
20653
20574
  var metaR = el("div", { class: "detail-meta", title: r.id, "data-record-id": r.id }, [
20654
20575
  draftBadge(r),
20655
- retractedBadge(r),
20656
- latestBadge(r),
20657
20576
  r.date ? el("span", { class: "mono", text: r.date }) : null,
20658
20577
  r.summary ? el("span", { text: r.summary }) : null,
20659
20578
  ]);
@@ -20672,14 +20591,10 @@ ${calendarAddUrl.toString()}
20672
20591
  app.appendChild(genBody);
20673
20592
  loadBody(r, genBody);
20674
20593
 
20675
- // 関連の資料(#1094 F8)。本文の後・取り下げの節の前。ルール・用語にしか載らない
20594
+ // 関連の資料(#1094 F8)。本文の後。ルール・用語にしか載らない
20676
20595
  var relm2 = relatedMaterialsSection(r);
20677
20596
  if (relm2) app.appendChild(relm2);
20678
20597
 
20679
- // 取り下げ(便 4-2d)。本文の後・「その後の記録」の前。取り下げの無い記録では何も作らない
20680
- var retr = retractSection(r);
20681
- if (retr) app.appendChild(retr);
20682
-
20683
20598
  appendRecordFooter(r);
20684
20599
  }
20685
20600
 
@@ -20713,7 +20628,6 @@ ${calendarAddUrl.toString()}
20713
20628
  derived_from: { color: "#0d9488", label: "生成元", kind: "gold" },
20714
20629
  relates_to: { color: "#94a3b8", label: "関連", kind: "gold" },
20715
20630
  supersedes: { color: "#dc2626", label: "置換", kind: "gold" },
20716
- retracted_by: { color: "#dc2626", label: "取り下げ", kind: "gold", onlyWhenPresent: true },
20717
20631
  reference: { color: "#d1d5db", label: "参照", kind: "evidence" },
20718
20632
  source: { color: "#d1d5db", label: "出典", kind: "evidence" },
20719
20633
  link: { color: "#e2e8f0", label: "リンク", kind: "evidence" },
@@ -21338,7 +21252,7 @@ ${calendarAddUrl.toString()}
21338
21252
 
21339
21253
  var EDGE_DARK = {
21340
21254
  based_on: "rgba(125,165,255,0.85)", derived_from: "rgba(94,234,212,0.75)",
21341
- 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)",
21342
21256
  reference: "rgba(180,196,230,0.32)", source: "rgba(180,196,230,0.32)", link: "rgba(180,196,230,0.22)",
21343
21257
  about: "rgba(196,181,253,0.22)",
21344
21258
  decided_by: "rgba(244,114,182,0.75)",
@@ -21594,8 +21508,6 @@ ${calendarAddUrl.toString()}
21594
21508
 
21595
21509
  var meta = el("div", { class: "detail-meta" }, [
21596
21510
  draftBadge(d),
21597
- retiredBadge(d),
21598
- latestBadge(d),
21599
21511
  el("span", { class: "mono", text: d.date || "----" }),
21600
21512
  firmnessBadge(d),
21601
21513
  ]);
@@ -21614,22 +21526,17 @@ ${calendarAddUrl.toString()}
21614
21526
  app.appendChild(el("div", { class: "summary-box", text: d.summary }));
21615
21527
  }
21616
21528
 
21617
- // 論点(#1094)。札の無い決定では何も作らない
21618
- if (hasTopic(d)) {
21619
- app.appendChild(el("div", { class: "section-label", text: "論点" }));
21620
- 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 })]));
21621
21533
  }
21622
21534
 
21623
- // 決めた人(#1094)。decided_by に読めた人がいればそちらを出し、いなければ(欄が無い・空・全部崩れ)今どおり deciders
21535
+ // 決めた人(#1094)。decided_by に読めた人がいれば出す(旧い deciders は読まない)
21624
21536
  var whoChips = Array.isArray(d.decidedBy) ? d.decidedBy.map(decidedByChip).filter(Boolean) : [];
21625
21537
  if (whoChips.length) {
21626
21538
  app.appendChild(el("div", { class: "section-label", text: "決めた人" }));
21627
21539
  app.appendChild(el("div", { class: "deciders decided-by" }, whoChips));
21628
- } else if (d.deciders && d.deciders.length) {
21629
- app.appendChild(el("div", { class: "section-label", text: "決定者" }));
21630
- app.appendChild(el("div", { class: "deciders" }, d.deciders.map(function (p) {
21631
- return el("span", { class: "chip", text: p });
21632
- })));
21633
21540
  }
21634
21541
 
21635
21542
  app.appendChild(el("div", { class: "section-label", text: "内容" }));
@@ -21676,7 +21583,7 @@ ${calendarAddUrl.toString()}
21676
21583
  // レコード情報(frontmatter)のパネルが英語の語のまま出さないためだけ(凡例の REL_LABEL には足さない)
21677
21584
  var REL_LABEL = {
21678
21585
  based_on: "根拠", derived_from: "由来", relates_to: "関連",
21679
- supersedes: "置換", superseded_by: "置換先", retracted_by: "取り下げ", reference: "参照", source: "出典", link: "リンク",
21586
+ supersedes: "置換", superseded_by: "置換先", reference: "参照", source: "出典", link: "リンク",
21680
21587
  about: "話題",
21681
21588
  decided_by: "決めた人",
21682
21589
  };
@@ -21691,7 +21598,7 @@ ${calendarAddUrl.toString()}
21691
21598
  (adjDir[e.from] = adjDir[e.from] || []).push({ id: e.to, rel: e.rel, dir: "out" });
21692
21599
  (adjDir[e.to] = adjDir[e.to] || []).push({ id: e.from, rel: e.rel, dir: "in" });
21693
21600
  });
21694
- 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"];
21695
21602
 
21696
21603
  function recordText(rec) {
21697
21604
  if (!rec) return "";