@takagaki/cortex-decisions-viewer 0.12.116 → 0.12.118
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/build.js +49 -32
- package/dist/minify.js +29 -0
- package/dist/rederivation.js +8 -120
- package/dist/render.js +153 -502
- package/package.json +2 -1
package/dist/build.js
CHANGED
|
@@ -41,7 +41,8 @@ exports.sanitizeBody = sanitizeBody;
|
|
|
41
41
|
exports.findProjectIcon = findProjectIcon;
|
|
42
42
|
exports.readFleetSources = readFleetSources;
|
|
43
43
|
exports.attachRederived = attachRederived;
|
|
44
|
-
exports.
|
|
44
|
+
exports.humanTouchedOf = humanTouchedOf;
|
|
45
|
+
exports.attachHumanTouched = attachHumanTouched;
|
|
45
46
|
exports.rawFrontmatterDate = rawFrontmatterDate;
|
|
46
47
|
exports.attachSupersedes = attachSupersedes;
|
|
47
48
|
exports.readGoldProposals = readGoldProposals;
|
|
@@ -110,6 +111,8 @@ function takeProposals(filePath) {
|
|
|
110
111
|
const external_id_1 = require("./external-id");
|
|
111
112
|
const home_project_1 = require("./home-project");
|
|
112
113
|
const supersedes_1 = require("./supersedes");
|
|
114
|
+
const confirmed_1 = require("./confirmed");
|
|
115
|
+
const minify_1 = require("./minify");
|
|
113
116
|
const render_1 = require("./render");
|
|
114
117
|
/**
|
|
115
118
|
* この画面を作ったパッケージの版。**package.json を唯一の出どころにする。**
|
|
@@ -784,29 +787,37 @@ readBlobs = repo_1.readBlobsAt) {
|
|
|
784
787
|
return (0, rederivation_1.orderByActivity)(records, pathOf, statusOf, ctx.ledgers, nowIso);
|
|
785
788
|
}
|
|
786
789
|
/**
|
|
787
|
-
*
|
|
790
|
+
* 記録に人の手があるか(cortex-engine #1094 段 4・削除の確認の文面を替える材料)。
|
|
788
791
|
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
+
* 次のどちらかで真:
|
|
793
|
+
* 1. status が人の値(口の `humanOwned`・区画の語彙。旧い記録の「確認済み」)
|
|
794
|
+
* 2. 確認の帳簿(`.cortex/gold-confirmation.json`)にその path の `confirmed` の行がある(消した行を除く)
|
|
792
795
|
*
|
|
793
|
-
*
|
|
796
|
+
* 🔴 **ビルドの git は使わない**(確定版 0 章 7)。cortex-bot の夜のコミットを人と数え、浅い clone では
|
|
797
|
+
* 全部が人になるため。engine の人の手の表がビューアに届く段 5 で差し替える。
|
|
798
|
+
* 取りこぼしの代償は「確認の一言が出ない」だけ(消せる範囲は変わらない)。
|
|
799
|
+
*
|
|
800
|
+
* @param p リポジトリルート相対の path(`Cortex/<区画>/records/…`)。帳簿の鍵は NFC なので NFC でも引く
|
|
801
|
+
* @param status その記録の `rstatus`(`String()` 済み)
|
|
794
802
|
*/
|
|
795
|
-
function
|
|
803
|
+
function humanTouchedOf(p, status, confirmation) {
|
|
804
|
+
if ((0, confirmed_1.humanOwned)(p, status))
|
|
805
|
+
return true;
|
|
806
|
+
const row = confirmation.get(p) ?? confirmation.get(p.normalize("NFC"));
|
|
807
|
+
return !!row && row.deleted !== true;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* 区画の記録に人の手の印(`humanTouched: true`)を載せる。**人の手が無い記録にはキーごと付けない**
|
|
811
|
+
* (今の SiteData の形を保つ)。path は `repoRoot` 起点で作る(帳簿の鍵はリポジトリルート相対)。
|
|
812
|
+
* 置き換えの逆引き(`attachSupersedes`)より前に呼ぶ。
|
|
813
|
+
*/
|
|
814
|
+
function attachHumanTouched(records, recordsDir, repoRoot, confirmation) {
|
|
796
815
|
const recordsRel = path.relative(repoRoot, recordsDir).split(path.sep).join("/");
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
const row = ledger.get(p);
|
|
802
|
-
if (!row)
|
|
803
|
-
continue;
|
|
804
|
-
matched.add(p);
|
|
805
|
-
const shown = (0, rederivation_1.shownFollowupOf)(row);
|
|
806
|
-
if (shown)
|
|
807
|
-
d.followup = shown;
|
|
816
|
+
for (const r of records) {
|
|
817
|
+
const p = recordsRel ? `${recordsRel}/${r.fileName}` : r.fileName;
|
|
818
|
+
if (humanTouchedOf(p, r.rstatus, confirmation))
|
|
819
|
+
r.humanTouched = true;
|
|
808
820
|
}
|
|
809
|
-
return [...ledger.keys()].filter((k) => !matched.has(k.normalize("NFC")));
|
|
810
821
|
}
|
|
811
822
|
/**
|
|
812
823
|
* 決定に置き換えの逆引き(置き換え先・置き換えた決定)を載せる(cortex-engine #699 F3・A-1')。
|
|
@@ -2465,19 +2476,10 @@ async function build(opts) {
|
|
|
2465
2476
|
if (rd !== undefined)
|
|
2466
2477
|
rawDates.set(rec, rd);
|
|
2467
2478
|
}
|
|
2479
|
+
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)。**置き換えより前に・repoRoot で**
|
|
2480
|
+
attachHumanTouched(decisions, dirAbs, repoRoot, ledgers.confirmation);
|
|
2468
2481
|
// 置き換えの逆引き(#699 F3)。**置き換えの無い案件では 1 件も付かない**
|
|
2469
2482
|
attachSupersedes(decisions, (d) => rawDates.get(d) ?? d.fm.date);
|
|
2470
|
-
// 決定の「その後」(#705)。**帳簿を持たない案件では 1 件も付かず、絞り込みの印も立たない**
|
|
2471
|
-
// (`decisionFollowup` はキーごと無い=今までと 1 バイトも同じ画面)
|
|
2472
|
-
const followupLedger = await (0, rederivation_1.readDecisionFollowup)(repoRoot);
|
|
2473
|
-
if (followupLedger) {
|
|
2474
|
-
const unmatchedFollowup = attachDecisionFollowup(decisions, dirAbs, repoRoot, followupLedger);
|
|
2475
|
-
// **突き合わなかった行を 1 行残す**(path が 1 文字違うだけで画面から静かに消えるので)
|
|
2476
|
-
if (unmatchedFollowup.length) {
|
|
2477
|
-
console.warn(`gold-decision-followup.json: 決定に突き合わない行が ${unmatchedFollowup.length} 件ありました(表示しません): ` +
|
|
2478
|
-
unmatchedFollowup.slice(0, 3).join(", ") + (unmatchedFollowup.length > 3 ? " ほか" : ""));
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
2483
|
let home = null;
|
|
2482
2484
|
let homeGrounding;
|
|
2483
2485
|
let homeUpdatedAt;
|
|
@@ -2517,6 +2519,8 @@ async function build(opts) {
|
|
|
2517
2519
|
continue;
|
|
2518
2520
|
const recordsDir = path.join(knowledgeRoot, e.name, "records");
|
|
2519
2521
|
const records = await loadGenericRecords(recordsDir, exclude, repo.baseUrl, repo.branch);
|
|
2522
|
+
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)
|
|
2523
|
+
attachHumanTouched(records, recordsDir, repoRoot, ledgers.confirmation);
|
|
2520
2524
|
// 「人が確認した版から変わりました」の帯と、用語集の並び(#665 便 12b)。
|
|
2521
2525
|
// **帳簿を持たない案件では 1 件も付かず、並びもそのまま**(下の attachRederived)
|
|
2522
2526
|
const rederived = await attachRederived(records, recordsDir, rederive, opts.generatedAt);
|
|
@@ -2574,6 +2578,17 @@ async function build(opts) {
|
|
|
2574
2578
|
console.warn(`gold-proposals.json: レコードに突き合わない提案が ${unmatched.length} 件ありました(表示しません): ` +
|
|
2575
2579
|
unmatched.slice(0, 5).join(", ") + (unmatched.length > 5 ? " ほか" : ""));
|
|
2576
2580
|
}
|
|
2581
|
+
// 画面に出さなくなった提案(名寄せ以外・#1094 35d)の件数。**人の操作は足さず、ログに 1 行だけ残す**
|
|
2582
|
+
// (kind が identity でない提案は、記録に載っていても画面のどこにも出ない)
|
|
2583
|
+
let hiddenProposals = 0;
|
|
2584
|
+
for (const [k, list] of PROPOSALS_BY_PATH) {
|
|
2585
|
+
if (!PROPOSAL_PATHS_MATCHED.has(k))
|
|
2586
|
+
continue;
|
|
2587
|
+
hiddenProposals += list.filter((p) => p.kind !== "identity").length;
|
|
2588
|
+
}
|
|
2589
|
+
if (hiddenProposals) {
|
|
2590
|
+
console.warn(`gold-proposals.json: 名寄せ以外の提案が ${hiddenProposals} 件あります(画面には出しません)`);
|
|
2591
|
+
}
|
|
2577
2592
|
const graph = buildGraph(decisions, home, graphSections, targetUrls, repo.baseUrl, evidenceBook);
|
|
2578
2593
|
computeLayout(graph); // 各ノードに x/y を書き込む(クライアントはこれを初期位置に使いウォームアップ省略)
|
|
2579
2594
|
// 点の明るさと大きさ(engine #551)。順位のファイルが読めない案件では 1 点も付かない(今までと同じ画面)
|
|
@@ -2622,7 +2637,6 @@ async function build(opts) {
|
|
|
2622
2637
|
}
|
|
2623
2638
|
: undefined,
|
|
2624
2639
|
// 帳簿を読めた案件だけ true(無い・壊れ・版違いはキーごと出さない)
|
|
2625
|
-
decisionFollowup: followupLedger ? true : undefined,
|
|
2626
2640
|
meetings,
|
|
2627
2641
|
// **URLとトークンが両方そろったときだけ出す。** 片方だけでは貼れるURLを作れないので、
|
|
2628
2642
|
// 手順だけが出て「専用URLが空」という一番混乱する形になる(intake と同じ扱い)
|
|
@@ -2702,7 +2716,10 @@ async function build(opts) {
|
|
|
2702
2716
|
// 配置側(cortex-engine の build-viewer.yml)の責務: aws s3 sync --delete が
|
|
2703
2717
|
// 古いハッシュのファイルを消すこと、index.html に Cache-Control: no-cache を
|
|
2704
2718
|
// 付けること(assets/ は内容ハッシュ名なので長期キャッシュでよい)。
|
|
2705
|
-
|
|
2719
|
+
// 🔴 **配る JS は縮めてから名前を決める**(ハッシュは縮めた後の中身から。コメント由来の実名を配信物に載せない・#731 便 4)。
|
|
2720
|
+
// `viewerAssetSources()` の素の JS は埋め込み形(renderSite)とテストが読むので縮めない
|
|
2721
|
+
const rawAssetSources = (0, render_1.viewerAssetSources)();
|
|
2722
|
+
const assetSources = { css: rawAssetSources.css, js: (0, minify_1.minifyClientJs)(rawAssetSources.js) };
|
|
2706
2723
|
const assets = (0, render_1.viewerAssetNames)(assetSources);
|
|
2707
2724
|
await node_fs_1.promises.mkdir(path.join(outAbs, "assets"), { recursive: true });
|
|
2708
2725
|
await node_fs_1.promises.writeFile(path.join(outAbs, assets.css), assetSources.css, "utf8");
|
package/dist/minify.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MINIFY_OPTIONS = void 0;
|
|
4
|
+
exports.minifyClientJs = minifyClientJs;
|
|
5
|
+
const esbuild_1 = require("esbuild");
|
|
6
|
+
/**
|
|
7
|
+
* 画面の JS(`assets/viewer.<hash>.js`)を配る前に縮める(cortex-engine #731 便 4)。
|
|
8
|
+
*
|
|
9
|
+
* 配る JS はテンプレート文字列として書いた約 15,000 行で、コメントに案件名・社内の事情が入っている。
|
|
10
|
+
* そのまま書き出すと、お客様の組織の画面のソースにも読める形で載る。ここで**コメントと余分な空白を落とす**。
|
|
11
|
+
*
|
|
12
|
+
* 🔴 **空白とコメントだけを落とす(名前の短縮・構文の書き換えはしない)。** `.toString()` で埋め込んだ関数や
|
|
13
|
+
* 名前に頼る所を壊さないため。`charset: "utf8"` は日本語の文言を `\uXXXX` に展開させない(既定の ascii だと
|
|
14
|
+
* 読めず、かえって大きくなる)。`legalComments: "none"` は `/*!` 系も残さない。
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ 番人(`test/shipped-js-minified.test.mjs`)は同じオプションを**わざと直書き**している(ここを再利用すると、縮めを恒等にされても緑になる)。
|
|
17
|
+
* ここを変えたら番人の直書きも同じにすること。
|
|
18
|
+
*
|
|
19
|
+
* 🔴 **失敗しても素のコメント入りで配らない**(例外のまま build を赤にする)。縮めに失敗した画面を黙って配ると、
|
|
20
|
+
* 番人(`test/shipped-js-minified.test.mjs`)の外で実名が載る。
|
|
21
|
+
*/
|
|
22
|
+
exports.MINIFY_OPTIONS = {
|
|
23
|
+
minifyWhitespace: true,
|
|
24
|
+
charset: "utf8",
|
|
25
|
+
legalComments: "none",
|
|
26
|
+
};
|
|
27
|
+
function minifyClientJs(js) {
|
|
28
|
+
return (0, esbuild_1.transformSync)(js, exports.MINIFY_OPTIONS).code;
|
|
29
|
+
}
|
package/dist/rederivation.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.HUMAN_FOLLOWUP_STATES = exports.
|
|
6
|
+
exports.HUMAN_FOLLOWUP_STATES = exports.emptyLedgers = exports.TERM_STRENGTH_FILE = exports.LEDGER_VERSION = void 0;
|
|
7
7
|
exports.isConfirmedStatus = isConfirmedStatus;
|
|
8
8
|
exports.parseLedger = parseLedger;
|
|
9
9
|
exports.readRederivationLedgers = readRederivationLedgers;
|
|
@@ -17,8 +17,6 @@ exports.rederivedContentKey = rederivedContentKey;
|
|
|
17
17
|
exports.rederivedBandOf = rederivedBandOf;
|
|
18
18
|
exports.orderByActivity = orderByActivity;
|
|
19
19
|
exports.followupDateOf = followupDateOf;
|
|
20
|
-
exports.readDecisionFollowup = readDecisionFollowup;
|
|
21
|
-
exports.shownFollowupOf = shownFollowupOf;
|
|
22
20
|
exports.humanFollowupOf = humanFollowupOf;
|
|
23
21
|
/**
|
|
24
22
|
* 再導出の 3 帳簿(+用語の強さの帳簿)を読み、帯「人が確認した版から変わりました」と用語集の並びを作る(#665 便 12b)。
|
|
@@ -76,9 +74,9 @@ const MIN_ELAPSED_DAYS = 0.5;
|
|
|
76
74
|
* (`rec.fm.status`)を渡さない——YAML は真偽値も配列も返すので、札と同じ文字列にならない
|
|
77
75
|
* (口は文字列・null・undefined のほかを投げる)。
|
|
78
76
|
*
|
|
79
|
-
* ⚠️
|
|
80
|
-
* `
|
|
81
|
-
*
|
|
77
|
+
* ⚠️ **「人の手」は別にある。** 削除の確認の文面を替える `rec.humanTouched`(`build.ts` の
|
|
78
|
+
* `humanTouchedOf`)は口の `humanOwned`(区画の語彙)か確認の帳簿の行で、`""` の扱いがここと逆
|
|
79
|
+
* (人の手として**扱う**側は `humanOwned`、機械が触る前の**守り**は `!machineOwned` という割り当て)。
|
|
82
80
|
*/
|
|
83
81
|
function isConfirmedStatus(status, recordPath = null) {
|
|
84
82
|
return !(0, confirmed_1.machineOwned)(recordPath, status);
|
|
@@ -698,41 +696,15 @@ function breakTiesByStrength(records, pathOf, ledgers, nowIso) {
|
|
|
698
696
|
return out;
|
|
699
697
|
}
|
|
700
698
|
/* ---------------------------------------------------------------------------
|
|
701
|
-
*
|
|
699
|
+
* 決定の「その後」(人の答え)
|
|
702
700
|
* ---------------------------------------------------------------------------
|
|
703
701
|
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
* 🔴 **帳簿が無い・壊れている・版が違う案件は「今までと 1 バイトも同じ画面」**(上の 3 帳簿と同じ規律)。
|
|
709
|
-
* 読めないものは `null`(=帳簿を持たない案件と同じ)として続ける。
|
|
710
|
-
*
|
|
711
|
-
* 🔴 **便 3 の `evidence[]` は形が未確定**。知らない verdict・欠けた欄は行ごと捨てる
|
|
712
|
-
* (落ちない・知らないものを画面へ運ばない)。
|
|
713
|
-
*/
|
|
714
|
-
/** 帳簿のファイル名(`.cortex/` の下) */
|
|
715
|
-
exports.DECISION_FOLLOWUP_FILE = "gold-decision-followup.json";
|
|
716
|
-
/**
|
|
717
|
-
* 画面に出す結び付きの状態(engine `decision-followup-run.mjs` の `LINKED_STATES` と同じ 6 語)。
|
|
718
|
-
*
|
|
719
|
-
* 🔴 **`venue_unavailable` / `link_unresolved` / `no_link` / `source_missing` は出さない**
|
|
720
|
-
* (発注書 #705)。「未接続のため」「記録なし」の文を画面に並べない——出来事だけを出す。
|
|
702
|
+
* 画面が読むのは、人が frontmatter に書いた `followup:` の 1 行だけ(#1094 35d)。
|
|
703
|
+
* 夜間の帳簿(`.cortex/gold-decision-followup.json`)は画面に出さない・読まない
|
|
704
|
+
* (PR のマージを完了と数える差 97 を画面から外すため)。
|
|
721
705
|
*/
|
|
722
|
-
exports.FOLLOWUP_SHOWN_STATES = [
|
|
723
|
-
"issue_closed", "pr_merged", "issue_open", "superseded", "same_day", "pr_closed",
|
|
724
|
-
];
|
|
725
|
-
/** 結び付きの種類(`material` は出典の資料で、`source_missing` にしか現れないので載せない) */
|
|
726
|
-
const FOLLOWUP_LINK_KINDS = ["issue", "pr", "gh", "decision"];
|
|
727
|
-
/** 便 3 の verdict のうち画面が知っているもの。**知らない値は行ごと捨てる** */
|
|
728
|
-
exports.FOLLOWUP_EVIDENCE_VERDICTS = ["done", "changed", "review"];
|
|
729
706
|
/** 人が frontmatter に書く `followup.state` の語彙(intake `FOLLOWUP_STATES` と同じ 4 語) */
|
|
730
707
|
exports.HUMAN_FOLLOWUP_STATES = ["confirmed", "done", "dropped", "ignore"];
|
|
731
|
-
/** http(s) の URL だけを通す(`javascript:` などを画面へ運ばない) */
|
|
732
|
-
const httpUrl = (v) => {
|
|
733
|
-
const s = typeof v === "string" ? v.trim() : "";
|
|
734
|
-
return /^https?:\/\//i.test(s) ? s : "";
|
|
735
|
-
};
|
|
736
708
|
/**
|
|
737
709
|
* 日付を `YYYY-MM-DD` に畳む。
|
|
738
710
|
*
|
|
@@ -756,90 +728,6 @@ function followupDateOf(v) {
|
|
|
756
728
|
return "";
|
|
757
729
|
return new Date(ms + 9 * 3600 * 1000).toISOString().slice(0, 10);
|
|
758
730
|
}
|
|
759
|
-
/**
|
|
760
|
-
* 決定の「その後」の帳簿を読む。
|
|
761
|
-
*
|
|
762
|
-
* @returns path → 行。**帳簿が無い・壊れている・版が違うときは `null`**(=帳簿を持たない案件)。
|
|
763
|
-
* 読めたが行が 0 件のときは空の Map(帳簿を持つ案件として扱う=絞り込みの「記録なし」が出うる)
|
|
764
|
-
*/
|
|
765
|
-
async function readDecisionFollowup(repoRoot) {
|
|
766
|
-
let raw;
|
|
767
|
-
try {
|
|
768
|
-
raw = await promises_1.default.readFile(node_path_1.default.join(repoRoot, ".cortex", exports.DECISION_FOLLOWUP_FILE), "utf8");
|
|
769
|
-
}
|
|
770
|
-
catch (e) {
|
|
771
|
-
// 無いのが既定(栓 `decision_followup` を入れた案件だけが持つ)。無いことは警告しない
|
|
772
|
-
if (e?.code !== "ENOENT") {
|
|
773
|
-
console.warn(`${exports.DECISION_FOLLOWUP_FILE} を読めませんでした(その後の記録は出さずに続けます): ${String(e)}`);
|
|
774
|
-
}
|
|
775
|
-
return null;
|
|
776
|
-
}
|
|
777
|
-
const parsed = parseLedger(raw);
|
|
778
|
-
if (!parsed) {
|
|
779
|
-
// 壊れ・版違いは 1 行残す(「夜間がまだ書いていない」と切り分けるため)
|
|
780
|
-
console.warn(`${exports.DECISION_FOLLOWUP_FILE} の形式か version が想定と違います(その後の記録は出さずに続けます)`);
|
|
781
|
-
return null;
|
|
782
|
-
}
|
|
783
|
-
const out = new Map();
|
|
784
|
-
const sections = asRecord(parsed.sections);
|
|
785
|
-
// 🔴 **区画は Decisions だけを見る**(engine の `SECTION`)。他の名前の節が増えても拾わない
|
|
786
|
-
const rows = asRecord(sections?.Decisions);
|
|
787
|
-
if (!rows)
|
|
788
|
-
return out;
|
|
789
|
-
for (const [p, v] of Object.entries(rows)) {
|
|
790
|
-
const row = asRecord(v);
|
|
791
|
-
if (!row)
|
|
792
|
-
continue;
|
|
793
|
-
const links = [];
|
|
794
|
-
if (Array.isArray(row.links)) {
|
|
795
|
-
for (const l of row.links) {
|
|
796
|
-
const link = asRecord(l);
|
|
797
|
-
if (!link)
|
|
798
|
-
continue;
|
|
799
|
-
const kind = typeof link.kind === "string" ? link.kind : "";
|
|
800
|
-
const key = typeof link.key === "string" ? link.key : "";
|
|
801
|
-
const state = typeof link.state === "string" ? link.state : "";
|
|
802
|
-
if (!FOLLOWUP_LINK_KINDS.includes(kind) || !key || !state)
|
|
803
|
-
continue;
|
|
804
|
-
links.push({ kind: kind, key: key, state: state, at: followupDateOf(link.at), url: httpUrl(link.url) });
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
const evidence = [];
|
|
808
|
-
if (Array.isArray(row.evidence)) {
|
|
809
|
-
for (const e of row.evidence) {
|
|
810
|
-
const ev = asRecord(e);
|
|
811
|
-
if (!ev)
|
|
812
|
-
continue;
|
|
813
|
-
const verdict = typeof ev.verdict === "string" ? ev.verdict : "";
|
|
814
|
-
// 🔴 **知らない verdict は捨てる**(便 3 の語彙は未確定。知らない語を画面の文にしない)
|
|
815
|
-
if (!exports.FOLLOWUP_EVIDENCE_VERDICTS.includes(verdict))
|
|
816
|
-
continue;
|
|
817
|
-
evidence.push({
|
|
818
|
-
verdict: verdict,
|
|
819
|
-
quote: typeof ev.quote === "string" ? ev.quote : "",
|
|
820
|
-
url: httpUrl(ev.url),
|
|
821
|
-
// engine の今の根拠行は `{id, venue, quote, verdict, judged_at}`(`occurred_at` を持たない)。
|
|
822
|
-
// 無ければ判定した日で代える——形は便 3 で合わせる(docs/product-decisions.md)
|
|
823
|
-
at: followupDateOf(ev.occurred_at) || followupDateOf(ev.judged_at),
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
out.set(p, { links: links, evidence: evidence });
|
|
828
|
-
}
|
|
829
|
-
return out;
|
|
830
|
-
}
|
|
831
|
-
/**
|
|
832
|
-
* 帳簿の行から、画面に出すぶんだけを残す。**出す結び付きが 1 件も無ければ `null`**
|
|
833
|
-
* (節を作らない・一覧の印も付かない)。
|
|
834
|
-
*/
|
|
835
|
-
function shownFollowupOf(row) {
|
|
836
|
-
if (!row)
|
|
837
|
-
return null;
|
|
838
|
-
const links = row.links.filter((l) => exports.FOLLOWUP_SHOWN_STATES.includes(l.state));
|
|
839
|
-
if (!links.length)
|
|
840
|
-
return null;
|
|
841
|
-
return { links: links, evidence: row.evidence };
|
|
842
|
-
}
|
|
843
731
|
/**
|
|
844
732
|
* frontmatter の `followup:`(人が画面のボタンで書く 1 行)を読む。
|
|
845
733
|
*
|