@takagaki/cortex-decisions-viewer 0.12.142 → 0.12.146

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,17 +6984,20 @@ ${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);
6987
+ /**
6988
+ * 詳細の節「参照」(根拠の出典リンク)。決定とルールが同じ出し方(rule.card・出典リンク)。
6989
+ * 参照の無い記録では null(要素を作らない)。リンクは http(s) だけ(ビルドが解決済みでも画面で二重に見る)
6990
+ */
6991
+ function referencesSection(r) {
6992
+ if (!r || !r.references || !r.references.length) return null;
6993
+ var box = el("div", { class: "refs-section" });
6994
+ box.appendChild(el("div", { class: "section-label", text: "参照" }));
6995
+ var ul = el("ul", { class: "refs" });
6996
+ r.references.forEach(function (ref) {
6997
+ var li = el("li");
6998
+ if (ref.url && /^https?:\\/\\//i.test(ref.url)) li.appendChild(el("a", { href: ref.url, target: "_blank", rel: "noopener", text: ref.label }));
6999
+ else li.textContent = ref.label;
7000
+ ul.appendChild(li);
7080
7001
  });
7081
7002
  box.appendChild(ul);
7082
7003
  return box;
@@ -7110,6 +7031,21 @@ ${calendarAddUrl.toString()}
7110
7031
  for (var i = 0; i < by.length; i++) if (by[i].id === d.id) return !by[i].confirmed;
7111
7032
  return false;
7112
7033
  }
7034
+ /**
7035
+ * 一覧のカードの「→ 変更先」(decision.show-superseded)。置き換えられた決定の行に、一番新しい置き換え先の題名を 1 行で添える。
7036
+ * 置き換え先が複数なら「ほか N 件」。置き換えられていない決定では null(行を作らない)。
7037
+ * 札(置き換え済み・最新の生成)は出さない(common.screen-no-state-label)。題名は textContent で入れる
7038
+ */
7039
+ function supersededToLine(d) {
7040
+ var by = (d && d.supersededBy && d.supersededBy.by) || [];
7041
+ if (!by.length) return null;
7042
+ // 画面で削除済みの置き換え先は題名を出さない(一覧から外れた決定を指さない)。見つからなければ ID の文字
7043
+ var shown = by.filter(function (b) { var n = byId[b.id]; return !(n && n.deleted); });
7044
+ var first = shown.length ? shown[0] : by[0];
7045
+ var next = byId[first.id];
7046
+ var name = next && next._kind === "decision" && !next.deleted ? humanTitle(next.title) : first.id;
7047
+ return el("p", { class: "card-superseded-to", text: "→ 変更先: " + name + (by.length > 1 ? " ほか " + (by.length - 1) + " 件" : "") });
7048
+ }
7113
7049
  /** 詳細の節「置き換え先の決定」「置き換えた決定」。どちらも無ければ null(要素を作らない) */
7114
7050
  function supersedeSection(d) {
7115
7051
  var by = (d && d.supersededBy && d.supersededBy.by) || [];
@@ -7145,24 +7081,23 @@ ${calendarAddUrl.toString()}
7145
7081
  }
7146
7082
 
7147
7083
  /* -------------------------------------------------------------------------
7148
- * 論点・固さ・決めた人(記憶 v2・cortex-engine #1094)
7084
+ * 筋・固さ・決めた人(記憶 v2・cortex-engine #1094)
7149
7085
  * -------------------------------------------------------------------------
7150
- * 欄(topic / firmness / decidedBy)は**ビルド側で語彙・形を確かめてある**。欄の無い記録では
7086
+ * 欄(strand / firmness / decidedBy)は**ビルド側で語彙・形を確かめてある**。欄の無い記録では
7151
7087
  * キーごと無いので、画面は有無だけを見る。🔴 **欄の無い記録だけの案件では要素を 1 つも作らない**
7152
7088
  * (絞り込み・固さの札・決めた人の節が出ない=今と同じ DOM)。
7153
- * 「置き換えられた」の判定は isRetired(ビルドが supersedes.ts で組んだ答え)をそのまま使う。
7154
7089
  */
7155
- function hasTopic(rec) {
7156
- return !!(rec && typeof rec.topic === "string" && rec.topic);
7090
+ function hasStrand(rec) {
7091
+ return !!(rec && typeof rec.strand === "string" && rec.strand);
7157
7092
  }
7158
- /** 論点の札の一覧(札を持つ決定が無ければ空) */
7159
- function topicOptions(items) {
7093
+ /** 筋の札の一覧(札を持つ決定が無ければ空) */
7094
+ function strandOptions(items) {
7160
7095
  var seen = {};
7161
7096
  var out = [];
7162
7097
  (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);
7098
+ if (!hasStrand(d) || Object.prototype.hasOwnProperty.call(seen, d.strand)) return;
7099
+ seen[d.strand] = true;
7100
+ out.push(d.strand);
7166
7101
  });
7167
7102
  return out.sort(function (a, b) { return a.localeCompare(b, "ja"); });
7168
7103
  }
@@ -7175,9 +7110,9 @@ ${calendarAddUrl.toString()}
7175
7110
  }
7176
7111
  return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
7177
7112
  }
7178
- /** 論点の札(一覧の行)。札が無ければ null */
7179
- function topicBadge(rec) {
7180
- return hasTopic(rec) ? el("span", { class: "badge topic", title: "論点", text: rec.topic }) : null;
7113
+ /** 筋の札(一覧の行)。札が無ければ null */
7114
+ function strandBadge(rec) {
7115
+ return hasStrand(rec) ? el("span", { class: "badge strand", title: "筋", text: rec.strand }) : null;
7181
7116
  }
7182
7117
  var FIRMNESS_CLASS = { "確定": "fixed", "仮": "tentative", "検討中": "open" };
7183
7118
  /** 固さの小札。語彙外は出さない(ビルド側でも捨てている・二重の網) */
@@ -7209,7 +7144,7 @@ ${calendarAddUrl.toString()}
7209
7144
  if (url) return el("a", { class: "chip decided-by-link", href: url, target: "_blank", rel: "noopener", text: who.name });
7210
7145
  return el("span", { class: "chip", text: who.name });
7211
7146
  }
7212
- /** 検索に使う決めた人の表記(decidedBy があればそちら、無ければ deciders) */
7147
+ /** 検索に使う決めた人の表記(decidedBy だけ) */
7213
7148
  function deciderWords(d) {
7214
7149
  if (Array.isArray(d.decidedBy) && d.decidedBy.length) {
7215
7150
  return d.decidedBy.map(function (w) {
@@ -7220,7 +7155,7 @@ ${calendarAddUrl.toString()}
7220
7155
  return w && typeof w.name === "string" ? w.name : "";
7221
7156
  }).join(" ");
7222
7157
  }
7223
- return (d.deciders || []).join(" ");
7158
+ return "";
7224
7159
  }
7225
7160
 
7226
7161
  // 未確認が1件も無い一覧では絞り込みを出さない
@@ -7419,6 +7354,11 @@ ${calendarAddUrl.toString()}
7419
7354
  "先頭の frontmatter(識別カードと設定)は触らないでください。日付・進捗・実績値は書かないでください(変わるものの正本は課題管理ツール等の外部にあります)。",
7420
7355
  "書き込む前に、書いた内容を提示して承認を得てください。",
7421
7356
  ].join("\\n");
7357
+ // 「AIで編集」の起動文の status の指示。**記憶 v2 の案件には出さない**(common.no-draft-lock・draft/active の印を持たない)。
7358
+ // 非 v2 は今のまま(statusKeepLine と同じ文)。v2 では null を返し、呼び出し側が filter(Boolean) で落とす
7359
+ function goldStatusLine() {
7360
+ return SITE.memoryV2 ? null : "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。";
7361
+ }
7422
7362
  var GOLD_SKILL = {
7423
7363
  "Decisions": {
7424
7364
  noun: "決定",
@@ -7433,9 +7373,9 @@ ${calendarAddUrl.toString()}
7433
7373
  target + " を読んでから、" + subject + "を修正してください。",
7434
7374
  "何を直すかは、まずわたしに質問してください。",
7435
7375
  "決定の内容そのものが変わる場合は、この記録を書き換えず、supersedes で新しい記録を作ってください。",
7436
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7376
+ goldStatusLine(),
7437
7377
  "書き込む前に、変更内容を提示して承認を得てください。",
7438
- ].join("\\n");
7378
+ ].filter(Boolean).join("\\n");
7439
7379
  },
7440
7380
  },
7441
7381
  "Glossary": {
@@ -7450,9 +7390,9 @@ ${calendarAddUrl.toString()}
7450
7390
  return [
7451
7391
  target + " を読んでから、" + subject + "を修正してください。",
7452
7392
  "何を直すかは、まずわたしに質問してください。",
7453
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7393
+ goldStatusLine(),
7454
7394
  "書き込む前に、変更内容を提示して承認を得てください。",
7455
- ].join("\\n");
7395
+ ].filter(Boolean).join("\\n");
7456
7396
  },
7457
7397
  },
7458
7398
  "Members": {
@@ -7467,9 +7407,9 @@ ${calendarAddUrl.toString()}
7467
7407
  return [
7468
7408
  target + " を読んでから、" + subject + "を修正してください。",
7469
7409
  "何を直すかは、まずわたしに質問してください。",
7470
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7410
+ goldStatusLine(),
7471
7411
  "書き込む前に、変更内容を提示して承認を得てください。",
7472
- ].join("\\n");
7412
+ ].filter(Boolean).join("\\n");
7473
7413
  },
7474
7414
  },
7475
7415
  "Rules": {
@@ -7484,9 +7424,9 @@ ${calendarAddUrl.toString()}
7484
7424
  return [
7485
7425
  target + " を読んでから、" + subject + "を修正してください。",
7486
7426
  "何を直すかは、まずわたしに質問してください。",
7487
- "あなた(人間)が内容を確認して編集したので、status が draft なら active に上げてください。",
7427
+ goldStatusLine(),
7488
7428
  "書き込む前に、変更内容を提示して承認を得てください。",
7489
- ].join("\\n");
7429
+ ].filter(Boolean).join("\\n");
7490
7430
  },
7491
7431
  },
7492
7432
  };
@@ -8512,7 +8452,7 @@ ${calendarAddUrl.toString()}
8512
8452
  }
8513
8453
  }
8514
8454
 
8515
- var listState = { tab: DEFAULT_TAB, q: "", month: "", status: "", topic: "", page: 1 };
8455
+ var listState = { tab: DEFAULT_TAB, q: "", month: "", status: "", strand: "", page: 1 };
8516
8456
 
8517
8457
  // 一覧のページネーション(描画コスト対策。1ページあたりの件数)
8518
8458
  var PAGE_SIZE = 30;
@@ -8558,7 +8498,7 @@ ${calendarAddUrl.toString()}
8558
8498
 
8559
8499
  /**
8560
8500
  * 一覧カードの上の段(左側)に出す、記録に既にある中身(#1094・オーナー決定 10/14)。
8561
- * 用語=別名(synonyms)・ルール=いつからか(derived_from の決定の日付)・関係者=読み仮名(yomi)と所属(org)。
8501
+ * 用語=別名(synonyms)・関係者=読み仮名(yomi)と所属(org)。
8562
8502
  * 無い記録は空の配列を返す(段そのものを作らない)。ID・メールアドレスは出さない。
8563
8503
  */
8564
8504
  function cardFacets(rec) {
@@ -8574,19 +8514,6 @@ ${calendarAddUrl.toString()}
8574
8514
  var shown = syn.slice(0, 3).join("・") + (syn.length > 3 ? " ほか " + (syn.length - 3) : "");
8575
8515
  out.push(el("span", { class: "card-facet card-facet-alias", text: "別名 " + shown }));
8576
8516
  }
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
8517
  } else if (isMemberRec(rec)) {
8591
8518
  var yomi = typeof fm.yomi === "string" ? fm.yomi.trim() : "";
8592
8519
  var org = typeof fm.org === "string" ? fm.org.trim() : "";
@@ -8673,7 +8600,7 @@ ${calendarAddUrl.toString()}
8673
8600
  text: "決定・用語・レポートを起点に、つながり(根拠・出典・リンク)を1列ずつ辿る表示です。行をクリックすると右に次の列が開きます。",
8674
8601
  },
8675
8602
  "story": {
8676
- text: "このプロジェクトの日々の動きを、日次・週次・月次に分けてまとめた記録です。直したいことや足したいことは、各カードの「GitHub で追記する」から書けます。",
8603
+ text: "このプロジェクトの日々の動きを、日次・週次・月次に分けてまとめた記録です。直したいことや足したいことは、各カードの「GitHubで編集」か「AIで編集」から書けます。",
8677
8604
  },
8678
8605
  "dir:レポート": {
8679
8606
  text: "レポートの生成は終了し、履歴として凍結されています(レポートはSlack配信に一本化されました)。以下は過去に生成されたレコードです。",
@@ -8722,6 +8649,28 @@ ${calendarAddUrl.toString()}
8722
8649
  renderList();
8723
8650
  }
8724
8651
 
8652
+ // ストーリーの日・週・月のカードの直し口(仕様 7-5)。「AIで編集」と「GitHubで編集」を並べる。人の追記の節は置かない。
8653
+ // 🔴 AI の起動文に入れるパスは、build が日付の形(YYYY-MM-DD・YYYY-MM)だけ通した鍵から作る(aiFenceScrub も通す)。frontmatter の date・relations は触らせない
8654
+ var STORY_DAYS_BASE = "Cortex/Story/Days/";
8655
+ var STORY_WEEKS_BASE = "Cortex/Story/Weeks/";
8656
+ var STORY_MONTHS_BASE = "Cortex/Story/Months/";
8657
+ function storyEditPrompt(path) {
8658
+ return [
8659
+ aiFenceScrub(path) + " を読んでから、このストーリーのページを直してください。",
8660
+ "何を直すか、足したいことは何かを、まずわたしに質問してください。",
8661
+ "先頭の frontmatter(date・relations)は触らないでください。機械が付けた印のコメントも消さないでください。",
8662
+ "このページの外の記録(決定・用語・関係者・ルール)は書き換えないでください。",
8663
+ "書き込む前に、変更内容を提示して承認を得てください。",
8664
+ ].join("\\n") + AI_COMMON;
8665
+ }
8666
+ function storyEditRow(path, editUrl) {
8667
+ var row = el("div", { class: "detail-actions-row story-card-actions" }, [
8668
+ aiLink("ai-edit-btn", storyEditPrompt(path), "AIで編集"),
8669
+ ]);
8670
+ if (editUrl) row.appendChild(el("a", { class: "edit-btn", href: editUrl, target: "_blank", rel: "noopener", text: "GitHubで編集" }));
8671
+ return row;
8672
+ }
8673
+
8725
8674
  // 日ごとのカード(新しい日が上=build が並べた順のまま)。動きのない日は「◯月◯日は動きはありませんでした」の1行
8726
8675
  function renderStoryDaily() {
8727
8676
  var days = SITE.story || [];
@@ -8734,9 +8683,10 @@ ${calendarAddUrl.toString()}
8734
8683
  days.forEach(function (d) {
8735
8684
  // 動きのない日は薄い 1 行(日付+文言。畳んだ行は「9/10〜9/18」)
8736
8685
  if (d.quiet) {
8737
- list.appendChild(el("div", { class: "story-quiet" }, [
8686
+ list.appendChild(el("div", { class: "story-quiet" + (d.failed ? " story-quiet-failed" : "") }, [
8738
8687
  el("span", { class: "story-quiet-date", text: d.heading || d.date }),
8739
- el("span", { text: d.pending ? " はまだ書けていません" : " は動きはありませんでした" }),
8688
+ // 夜の更新が成功した日は「動きはありませんでした」・成功していない日は失敗として出す(畳んだ行は「この間」)
8689
+ el("span", { text: d.failed ? (d.fromDate ? " この間の更新に失敗しています" : " この日の更新に失敗しています") : " は動きはありませんでした" }),
8740
8690
  ]));
8741
8691
  return;
8742
8692
  }
@@ -8744,18 +8694,17 @@ ${calendarAddUrl.toString()}
8744
8694
  el("h3", { class: "story-card-heading", text: d.heading || d.date }),
8745
8695
  d.bodyHtml ? el("div", { class: "body", html: d.bodyHtml }) : null,
8746
8696
  // その日のファイルを GitHub で開く(表示の文字にファイル名を出さない)。URL が無い案件は出さない
8747
- d.editUrl ? el("a", { class: "story-card-edit", href: d.editUrl, target: "_blank", rel: "noopener", text: "GitHub で追記する" }) : null,
8697
+ storyEditRow(STORY_DAYS_BASE + d.date.slice(0, 7) + "/" + d.date + ".md", d.editUrl),
8748
8698
  ]));
8749
8699
  });
8750
8700
  app.appendChild(list);
8751
8701
  }
8752
8702
 
8753
8703
  // 週・月のあらすじカード(局面・流れ・人の追記・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;
8704
+ function storyDigestCard(entry, phaseLabel, kind) {
8705
+ // 「人の追記」の節は置かない。古いファイルに節が残っていても、見出しと枠は出さず中身だけ本文の続きに出す
8706
+ var human = entry.humanHtml ? el("div", { class: "body", html: entry.humanHtml }) : null;
8707
+ var base = kind === "month" ? STORY_MONTHS_BASE : STORY_WEEKS_BASE;
8759
8708
  return el("section", { class: "story-card" }, [
8760
8709
  el("h3", { class: "story-card-heading", text: entry.heading }),
8761
8710
  entry.phase ? el("p", { class: "story-phase" }, [
@@ -8764,7 +8713,7 @@ ${calendarAddUrl.toString()}
8764
8713
  ]) : null,
8765
8714
  entry.flowHtml ? el("div", { class: "body", html: entry.flowHtml }) : null,
8766
8715
  human,
8767
- entry.editUrl ? el("a", { class: "story-card-edit", href: entry.editUrl, target: "_blank", rel: "noopener", text: "GitHub で追記する" }) : null,
8716
+ storyEditRow(base + entry.key + ".md", entry.editUrl),
8768
8717
  ]);
8769
8718
  }
8770
8719
 
@@ -8813,14 +8762,14 @@ ${calendarAddUrl.toString()}
8813
8762
  for (var wk = curMonday; !have[wk] && wk >= earliestMonday; wk = storyPrevWeekKey(wk)) {
8814
8763
  list.appendChild(el("section", { class: "story-card" }, [
8815
8764
  el("h3", { class: "story-card-heading", text: storyWeekLabel(wk) }),
8816
- el("p", { class: "story-empty", text: "週が閉じて 2 日後の夜に作ります" }),
8765
+ el("p", { class: "story-empty", text: "週の終わりの日の夜に作ります" }),
8817
8766
  ]));
8818
8767
  }
8819
8768
  }
8820
8769
  if (!weeks.length && !list.children.length) {
8821
- list.appendChild(el("p", { class: "story-empty", text: "あらすじはまだありません(週が閉じて 2 日後の夜に作ります)" }));
8770
+ list.appendChild(el("p", { class: "story-empty", text: "あらすじはまだありません(週の終わりの日の夜に作ります)" }));
8822
8771
  } else {
8823
- weeks.forEach(function (w) { list.appendChild(storyDigestCard(w, "この週の局面")); });
8772
+ weeks.forEach(function (w) { list.appendChild(storyDigestCard(w, "この週の局面", "week")); });
8824
8773
  }
8825
8774
  app.appendChild(list);
8826
8775
  }
@@ -8839,11 +8788,11 @@ ${calendarAddUrl.toString()}
8839
8788
  for (var mo = curMonth; !have[mo] && mo >= earliestMonth; mo = storyPrevMonthKey(mo)) {
8840
8789
  list.appendChild(el("section", { class: "story-card" }, [
8841
8790
  el("h3", { class: "story-card-heading", text: monthLabel(mo) }),
8842
- el("p", { class: "story-empty", text: "月が閉じて 3 日後の夜に作ります" }),
8791
+ el("p", { class: "story-empty", text: "月の終わりの日の夜に作ります" }),
8843
8792
  ]));
8844
8793
  }
8845
8794
  }
8846
- months.forEach(function (m) { list.appendChild(storyDigestCard(m, "この月の局面")); });
8795
+ months.forEach(function (m) { list.appendChild(storyDigestCard(m, "この月の局面", "month")); });
8847
8796
  app.appendChild(list);
8848
8797
  }
8849
8798
 
@@ -16984,7 +16933,7 @@ ${calendarAddUrl.toString()}
16984
16933
  * ## なぜ makeModal を使わないのか(一番大事)
16985
16934
  *
16986
16935
  * **makeModal は開いているモーダルを畳む**(existing.__close(true))。
16987
- * ところが確認が要る5か所は**すべて能力モーダルの中にいる**——
16936
+ * ところが確認が要る場所(confirmDanger の呼び出し 3 か所)は**すべて能力モーダルの中にいる**——
16988
16937
  * openCapabilityModal の items.forEach(m.modal.appendChild(n)) は
16989
16938
  * **ノードの移動**なので、利用者が「追加」を押した時点でフォームはモーダルの子。
16990
16939
  * makeModal で確認を開くと**親ごと消え、フォームが無くなる**。
@@ -19719,12 +19668,12 @@ ${calendarAddUrl.toString()}
19719
19668
  if (statusOptsD.length) {
19720
19669
  filters.appendChild(buildSelect("すべての状態", statusOptsD, listState.status, function (v) { listState.status = v; listState.page = 1; drawCards(); }, statusLabel));
19721
19670
  }
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);
19671
+ // 筋の札(#1094)。札を持つ決定が 1 件も無い案件では出さない
19672
+ var strandOpts = strandOptions(visibleRecords(SITE.decisions));
19673
+ if (strandOpts.length) {
19674
+ var strandSel = buildSelect("すべての筋", strandOpts, listState.strand, function (v) { listState.strand = v; listState.page = 1; drawCards(); });
19675
+ strandSel.classList.add("strand-filter");
19676
+ filters.appendChild(strandSel);
19728
19677
  }
19729
19678
  app.appendChild(filters);
19730
19679
 
@@ -19749,7 +19698,7 @@ ${calendarAddUrl.toString()}
19749
19698
  }
19750
19699
 
19751
19700
  /**
19752
- * 今の絞り込み(検索語・期間・状態・論点)を当てた決定の一覧(並びは
19701
+ * 今の絞り込み(検索語・期間・状態・筋)を当てた決定の一覧(並びは
19753
19702
  * SITE.decisions の順=新しい順のまま)。drawCards と、詳細の「前へ/次へ」
19754
19703
  * (#2)の両方がここを通る——一覧の並びと前後移動の並びがずれないように、口を1つにする。
19755
19704
  */
@@ -19760,21 +19709,21 @@ ${calendarAddUrl.toString()}
19760
19709
  var out = all.filter(function (d) {
19761
19710
  if (listState.month && d.date.slice(0, 7) !== listState.month) return false;
19762
19711
  if (!matchesStatusFilter(d)) return false;
19763
- if (!matchesTopicFilter(d)) return false;
19712
+ if (!matchesStrandFilter(d)) return false;
19764
19713
  if (q) {
19765
19714
  var hay = (d.title + " " + d.summary + " " + d.searchText + " " + deciderWords(d)).toLowerCase();
19766
19715
  if (hay.indexOf(q) === -1) return false;
19767
19716
  }
19768
19717
  return true;
19769
19718
  });
19770
- // 同じ論点の中は新しい順(決定日の降順 → ID の降順)
19771
- if (listState.topic) out.sort(newestDecisionFirst);
19719
+ // 同じ筋の中は新しい順(決定日の降順 → ID の降順)
19720
+ if (listState.strand) out.sort(newestDecisionFirst);
19772
19721
  return out;
19773
19722
  }
19774
- /** 論点の絞り込み(#1094)。選んでいなければ全件、選んだら同じ札の決定だけ */
19775
- function matchesTopicFilter(d) {
19776
- if (!listState.topic) return true;
19777
- return hasTopic(d) && d.topic === listState.topic;
19723
+ /** 筋の絞り込み(#1094)。選んでいなければ全件、選んだら同じ札の決定だけ */
19724
+ function matchesStrandFilter(d) {
19725
+ if (!listState.strand) return true;
19726
+ return hasStrand(d) && d.strand === listState.strand;
19778
19727
  }
19779
19728
 
19780
19729
  function drawCards() {
@@ -19798,15 +19747,14 @@ ${calendarAddUrl.toString()}
19798
19747
  pg.slice.forEach(function (d) {
19799
19748
  var head = cardHead(d, [
19800
19749
  draftBadge(d),
19801
- retiredBadge(d),
19802
- latestBadge(d),
19803
19750
  el("span", { class: "mono", text: d.date || "----" }),
19804
19751
  firmnessBadge(d),
19805
- topicBadge(d),
19752
+ strandBadge(d),
19806
19753
  ], d.deleted ? " is-deleted" : "");
19807
19754
  // 消したレコードは一覧でも取り消し線(次のビルドまで一覧には残る)
19808
19755
  var card = el("div", { class: "card", title: d.id, "data-record-id": d.id }, head.concat([
19809
19756
  d.summary ? el("p", { class: "card-summary", text: d.summary }) : null,
19757
+ supersededToLine(d),
19810
19758
  ]));
19811
19759
  card.addEventListener("click", function () { go(d.id); });
19812
19760
  wrap.appendChild(card);
@@ -19857,11 +19805,9 @@ ${calendarAddUrl.toString()}
19857
19805
  pg.slice.forEach(function (r) {
19858
19806
  var head = cardHead(r, [
19859
19807
  draftBadge(r),
19860
- retractedBadge(r),
19861
- latestBadge(r),
19862
19808
  r.date ? el("span", { class: "mono", text: r.date }) : null,
19863
19809
  ].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([
19810
+ var card = el("div", { class: "card", title: r.id, "data-record-id": r.id }, head.concat([
19865
19811
  r.summary ? el("p", { class: "card-summary", text: r.summary }) : null,
19866
19812
  ]));
19867
19813
  card.addEventListener("click", function () { go(r.id); });
@@ -20275,10 +20221,6 @@ ${calendarAddUrl.toString()}
20275
20221
  // 出し分けはサーバの DELETABLE_SECTIONS と同じ4区画。ここは「押せないボタンを
20276
20222
  // 出さない」ためのもので、**守りはサーバ側**(promote と同じ関係)。
20277
20223
  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
20224
  function deletableRecordPath(rec) {
20283
20225
  if (!SITE.intake) return "";
20284
20226
  var p = repoPathOf(rec);
@@ -20287,31 +20229,6 @@ ${calendarAddUrl.toString()}
20287
20229
  var base = p.slice(p.lastIndexOf("/") + 1).toLowerCase();
20288
20230
  return base === "readme.md" || base === "template.md" ? "" : p;
20289
20231
  }
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
20232
  async function sendDeleteRecord(rec, path, msg, btn, onOk) {
20316
20233
  var intake = SITE.intake;
20317
20234
  if (!intake) return;
@@ -20413,8 +20330,9 @@ ${calendarAddUrl.toString()}
20413
20330
  *
20414
20331
  * **どの記録にも出す**(cortex-engine #1094 段 4 問い 2・2026-10-04 のオーナー決定)。8/28 の裁定
20415
20332
  * 「人間の承認が挟まったものは削除の選択肢を出さない」は置き換えた——画面を見る人には裏の
20416
- * 履歴が見えず、見た目の違いが無いのにボタンの有無が分かれるのは分からないため。人の手のある
20417
- * 記録は確認の文面(deleteConfirmLines)で一言添える。intake も status では断らない。
20333
+ * 履歴が見えず、見た目の違いが無いのにボタンの有無が分かれるのは分からないため。人の手のある記録にも
20334
+ * 同じ口を出す。確認は挟まない([spec:common.screen-delete-no-confirm]・git の履歴から戻せる。1 回押すと
20335
+ * op=delete-record が 1 回送られる)。intake も status では断らない。
20418
20336
  *
20419
20337
  * 呼び出し側は2つ:
20420
20338
  * - draftNote …… 未確認の記録。「確認済みにする」と並べて警告帯の中に置く
@@ -20424,13 +20342,12 @@ ${calendarAddUrl.toString()}
20424
20342
  var path = deletableRecordPath(rec);
20425
20343
  if (!path) return null;
20426
20344
  // **語尾の「…」は 2026-08-29 のオーナーFBで外した。** 二択の相方(「確認済みにする」)と
20427
- // 語の形が揃わず、片方だけが下書きのように見えていた。押した先に確認モーダルが必ず出ることは
20428
- // 語尾ではなく操作そのもの(confirmDanger を await する下の行)で担保している
20345
+ // 語の形が揃わず、片方だけが下書きのように見えていた。**確認は挟まない**
20346
+ // ([spec:common.screen-delete-no-confirm]・git の履歴から戻せる)
20429
20347
  var btn = el("button", { class: "record-delete-btn", type: "button", text: "削除する" });
20430
20348
  var msg = el("div", { class: "record-delete-msg" });
20431
20349
  btn.addEventListener("click", async function () {
20432
- // **確認を await する。** 落とすと Promise が truthy で確認なしに消える
20433
- if (!(await confirmDanger(deleteConfirmLines(rec, path), { okLabel: "削除する", returnTo: btn }))) return;
20350
+ // [spec:common.screen-delete-no-confirm] 確認モーダルは挟まず、押したらそのまま 1 回送る
20434
20351
  await sendDeleteRecord(rec, path, msg, btn, function () { markRecordDeleted(rec); markPageStale(); });
20435
20352
  });
20436
20353
  return { btn: btn, msg: msg };
@@ -20450,15 +20367,11 @@ ${calendarAddUrl.toString()}
20450
20367
  editRow.appendChild(del.btn);
20451
20368
  return del.msg; // 結果を出す行は操作列の下(呼び出し側が最後に並べる)
20452
20369
  }
20453
- /** 詳細ページの末尾(本文・参照の後)に、つながっている ID・その後の記録・AIの変更履歴・frontmatter を並べる */
20370
+ /** 詳細ページの末尾(本文・参照の後)に、つながっている ID・AIの変更履歴・frontmatter を並べる */
20454
20371
  function appendRecordFooter(rec) {
20455
20372
  // 「つながっている ID」は本文の後・「更新履歴」の前(関係者の記録だけ・#686)
20456
20373
  var linked = buildLinkedIds(rec);
20457
20374
  if (linked) app.appendChild(linked);
20458
- // 決定の「その後の記録」(担当者の答えの 1 行)も同じ席——**本文と参照を読んでから、その後を見る順**。
20459
- // 決定以外の記録・答えが無い決定は rec.followupHuman を持たないので null(要素を作らない)
20460
- var fu = followupSection(rec);
20461
- if (fu) app.appendChild(fu);
20462
20375
  var history = changeLogSection(rec);
20463
20376
  if (history) app.appendChild(history);
20464
20377
  var fmp = renderFmPanel(rec.fm);
@@ -20694,8 +20607,6 @@ ${calendarAddUrl.toString()}
20694
20607
 
20695
20608
  var metaR = el("div", { class: "detail-meta", title: r.id, "data-record-id": r.id }, [
20696
20609
  draftBadge(r),
20697
- retractedBadge(r),
20698
- latestBadge(r),
20699
20610
  r.date ? el("span", { class: "mono", text: r.date }) : null,
20700
20611
  r.summary ? el("span", { text: r.summary }) : null,
20701
20612
  ]);
@@ -20714,14 +20625,14 @@ ${calendarAddUrl.toString()}
20714
20625
  app.appendChild(genBody);
20715
20626
  loadBody(r, genBody);
20716
20627
 
20717
- // 関連の資料(#1094 F8)。本文の後・取り下げの節の前。ルール・用語にしか載らない
20628
+ // 参照(rule.card)。ルールだけ。決定の詳細と同じ「参照」の節(ビルドが解決した出典リンク)
20629
+ var refs2 = referencesSection(r);
20630
+ if (refs2) app.appendChild(refs2);
20631
+
20632
+ // 関連の資料(#1094 F8)。本文の後。ルール・用語にしか載らない
20718
20633
  var relm2 = relatedMaterialsSection(r);
20719
20634
  if (relm2) app.appendChild(relm2);
20720
20635
 
20721
- // 取り下げ(便 4-2d)。本文の後・「その後の記録」の前。取り下げの無い記録では何も作らない
20722
- var retr = retractSection(r);
20723
- if (retr) app.appendChild(retr);
20724
-
20725
20636
  appendRecordFooter(r);
20726
20637
  }
20727
20638
 
@@ -20755,7 +20666,6 @@ ${calendarAddUrl.toString()}
20755
20666
  derived_from: { color: "#0d9488", label: "生成元", kind: "gold" },
20756
20667
  relates_to: { color: "#94a3b8", label: "関連", kind: "gold" },
20757
20668
  supersedes: { color: "#dc2626", label: "置換", kind: "gold" },
20758
- retracted_by: { color: "#dc2626", label: "取り下げ", kind: "gold", onlyWhenPresent: true },
20759
20669
  reference: { color: "#d1d5db", label: "参照", kind: "evidence" },
20760
20670
  source: { color: "#d1d5db", label: "出典", kind: "evidence" },
20761
20671
  link: { color: "#e2e8f0", label: "リンク", kind: "evidence" },
@@ -21380,7 +21290,7 @@ ${calendarAddUrl.toString()}
21380
21290
 
21381
21291
  var EDGE_DARK = {
21382
21292
  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)",
21293
+ relates_to: "rgba(148,163,184,0.6)", supersedes: "rgba(248,113,113,0.9)",
21384
21294
  reference: "rgba(180,196,230,0.32)", source: "rgba(180,196,230,0.32)", link: "rgba(180,196,230,0.22)",
21385
21295
  about: "rgba(196,181,253,0.22)",
21386
21296
  decided_by: "rgba(244,114,182,0.75)",
@@ -21636,8 +21546,6 @@ ${calendarAddUrl.toString()}
21636
21546
 
21637
21547
  var meta = el("div", { class: "detail-meta" }, [
21638
21548
  draftBadge(d),
21639
- retiredBadge(d),
21640
- latestBadge(d),
21641
21549
  el("span", { class: "mono", text: d.date || "----" }),
21642
21550
  firmnessBadge(d),
21643
21551
  ]);
@@ -21656,22 +21564,17 @@ ${calendarAddUrl.toString()}
21656
21564
  app.appendChild(el("div", { class: "summary-box", text: d.summary }));
21657
21565
  }
21658
21566
 
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 })]));
21567
+ // 筋(#1094)。札の無い決定では何も作らない
21568
+ if (hasStrand(d)) {
21569
+ app.appendChild(el("div", { class: "section-label", text: "筋" }));
21570
+ app.appendChild(el("div", { class: "decision-strand" }, [el("span", { class: "chip", text: d.strand })]));
21663
21571
  }
21664
21572
 
21665
- // 決めた人(#1094)。decided_by に読めた人がいればそちらを出し、いなければ(欄が無い・空・全部崩れ)今どおり deciders
21573
+ // 決めた人(#1094)。decided_by に読めた人がいれば出す(旧い deciders は読まない)
21666
21574
  var whoChips = Array.isArray(d.decidedBy) ? d.decidedBy.map(decidedByChip).filter(Boolean) : [];
21667
21575
  if (whoChips.length) {
21668
21576
  app.appendChild(el("div", { class: "section-label", text: "決めた人" }));
21669
21577
  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
21578
  }
21676
21579
 
21677
21580
  app.appendChild(el("div", { class: "section-label", text: "内容" }));
@@ -21679,17 +21582,8 @@ ${calendarAddUrl.toString()}
21679
21582
  app.appendChild(decBody);
21680
21583
  loadBody(d, decBody);
21681
21584
 
21682
- if (d.references && d.references.length) {
21683
- app.appendChild(el("div", { class: "section-label", text: "参照" }));
21684
- var ul = el("ul", { class: "refs" });
21685
- d.references.forEach(function (r) {
21686
- var li = el("li");
21687
- if (r.url) li.appendChild(el("a", { href: r.url, target: "_blank", rel: "noopener", text: r.label }));
21688
- else li.textContent = r.label;
21689
- ul.appendChild(li);
21690
- });
21691
- app.appendChild(ul);
21692
- }
21585
+ var refsBox = referencesSection(d);
21586
+ if (refsBox) app.appendChild(refsBox);
21693
21587
 
21694
21588
  // 関連の資料(#1094 F8)。「参照」(根拠)の後・置き換えの前。根拠と混ぜない
21695
21589
  var relm = relatedMaterialsSection(d);
@@ -21718,7 +21612,7 @@ ${calendarAddUrl.toString()}
21718
21612
  // レコード情報(frontmatter)のパネルが英語の語のまま出さないためだけ(凡例の REL_LABEL には足さない)
21719
21613
  var REL_LABEL = {
21720
21614
  based_on: "根拠", derived_from: "由来", relates_to: "関連",
21721
- supersedes: "置換", superseded_by: "置換先", retracted_by: "取り下げ", reference: "参照", source: "出典", link: "リンク",
21615
+ supersedes: "置換", superseded_by: "置換先", reference: "参照", source: "出典", link: "リンク",
21722
21616
  about: "話題",
21723
21617
  decided_by: "決めた人",
21724
21618
  };
@@ -21733,7 +21627,7 @@ ${calendarAddUrl.toString()}
21733
21627
  (adjDir[e.from] = adjDir[e.from] || []).push({ id: e.to, rel: e.rel, dir: "out" });
21734
21628
  (adjDir[e.to] = adjDir[e.to] || []).push({ id: e.from, rel: e.rel, dir: "in" });
21735
21629
  });
21736
- var REL_ORDER = ["supersedes", "retracted_by", "based_on", "derived_from", "relates_to", "decided_by", "source", "reference", "link", "about"];
21630
+ var REL_ORDER = ["supersedes", "based_on", "derived_from", "relates_to", "decided_by", "source", "reference", "link", "about"];
21737
21631
 
21738
21632
  function recordText(rec) {
21739
21633
  if (!rec) return "";