@takagaki/cortex-decisions-viewer 0.12.68 → 0.12.70
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 +472 -54
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -17,6 +17,9 @@ exports.sanitizeRegisteredNow = sanitizeRegisteredNow;
|
|
|
17
17
|
exports.sanitizeIngestCounts = sanitizeIngestCounts;
|
|
18
18
|
exports.sanitizeIngestFailures = sanitizeIngestFailures;
|
|
19
19
|
exports.sanitizeStateNow = sanitizeStateNow;
|
|
20
|
+
exports.devExcludedSkip = devExcludedSkip;
|
|
21
|
+
exports.devExcludedRefs = devExcludedRefs;
|
|
22
|
+
exports.devExcludedLabel = devExcludedLabel;
|
|
20
23
|
exports.overlayStateOnFleet = overlayStateOnFleet;
|
|
21
24
|
exports.chatRowsToAdd = chatRowsToAdd;
|
|
22
25
|
exports.gchatRowsToAdd = gchatRowsToAdd;
|
|
@@ -68,6 +71,8 @@ exports.liveRowVerdict = liveRowVerdict;
|
|
|
68
71
|
exports.liveRegistryOf = liveRegistryOf;
|
|
69
72
|
exports.liveToolKey = liveToolKey;
|
|
70
73
|
exports.liveToolItems = liveToolItems;
|
|
74
|
+
exports.capabilityPipeRe = capabilityPipeRe;
|
|
75
|
+
exports.capabilityWarnSource = capabilityWarnSource;
|
|
71
76
|
exports.renderConnectionMap = renderConnectionMap;
|
|
72
77
|
const node_crypto_1 = require("node:crypto");
|
|
73
78
|
const google_chat_guide_images_1 = require("./google-chat-guide-images");
|
|
@@ -249,13 +254,20 @@ const CAP_STATE_TEXT = {
|
|
|
249
254
|
};
|
|
250
255
|
/** 状態の印。CAP_STATE_TEXT の前に付ける(マップは付けない——⚠️バッジと二重になる) */
|
|
251
256
|
const CAP_STATE_MARK = { ok: "● ", idle: "⦿ ", warn: "⚠️ ", off: "" };
|
|
257
|
+
/**
|
|
258
|
+
* 接続マップに並べる能力と、その絵文字。
|
|
259
|
+
*
|
|
260
|
+
* 🔴 **能力→パイプラインの対応表をここに持たない(#654)。** かつて `pipe:` の欄が
|
|
261
|
+
* あったが誰も読んでおらず(死んだ写し)、正本は `capabilityPipeRe` 1 本。
|
|
262
|
+
* 写しを置くと、次に触る人が「表はここにもある」と読んで 2 枚目を育てる。
|
|
263
|
+
*/
|
|
252
264
|
const CM_CAPS = [
|
|
253
|
-
{ cap: "課題管理", icon: "📋"
|
|
254
|
-
{ cap: "会議", icon: "🎙"
|
|
255
|
-
{ cap: "共有資料", icon: "📁"
|
|
256
|
-
{ cap: "デザイン", icon: "🎨"
|
|
257
|
-
{ cap: "チャット", icon: "💬"
|
|
258
|
-
{ cap: "開発", icon: "🐙"
|
|
265
|
+
{ cap: "課題管理", icon: "📋" },
|
|
266
|
+
{ cap: "会議", icon: "🎙" },
|
|
267
|
+
{ cap: "共有資料", icon: "📁" },
|
|
268
|
+
{ cap: "デザイン", icon: "🎨" },
|
|
269
|
+
{ cap: "チャット", icon: "💬" },
|
|
270
|
+
{ cap: "開発", icon: "🐙" },
|
|
259
271
|
];
|
|
260
272
|
/**
|
|
261
273
|
* ツールid→表示名(接続マップのノードラベル用)。
|
|
@@ -554,8 +566,9 @@ const TOOL_KIND_ICONS = {
|
|
|
554
566
|
"google-meet": "🎥",
|
|
555
567
|
};
|
|
556
568
|
/**
|
|
557
|
-
* 状態の表示語と色。**
|
|
558
|
-
*
|
|
569
|
+
* 状態の表示語と色。**5 語+「登録状況を確認中です」しか出さない**(読み取り中/
|
|
570
|
+
* 接続OK(読み取りの対象外)/承認待ち/停止中/未確認、そして登録簿にしか無く
|
|
571
|
+
* まだ測っていない行の「確認中」・#581 / #640)。
|
|
559
572
|
*
|
|
560
573
|
* 色は既存の `ds-gate-*` を流用する——同じ画面で「緑=読めている・橙=人の操作待ち・
|
|
561
574
|
* 灰=分からない」の意味を 2 通りに増やさない。
|
|
@@ -568,6 +581,13 @@ const TOOL_KIND_ICONS = {
|
|
|
568
581
|
function toolStateLabel(state) {
|
|
569
582
|
if (state === "reading")
|
|
570
583
|
return { text: "読み取り中", cls: "ds-gate-ok" };
|
|
584
|
+
// 届いてはいるが、Gold の材料にしていない(#640・engine #399)。**「読み取り中」と
|
|
585
|
+
// 言わない**——読みに行かないと決めた接続先なので、言えば画面が嘘をつく。
|
|
586
|
+
// **警告色にもしない**(`ds-gate-ok` のまま)——直すものが無い中立の事実で、橙にすると
|
|
587
|
+
// 直しに行かせる。状態名を `"excluded"` にしないのは、`liveToolItems` の中で
|
|
588
|
+
// `match.excluded`(登録簿の devExcluded =「停止中」)が別の意味で使われているため
|
|
589
|
+
if (state === "ok_not_ingested")
|
|
590
|
+
return { text: "接続OK(読み取りの対象外)", cls: "ds-gate-ok" };
|
|
571
591
|
if (state === "waiting")
|
|
572
592
|
return { text: "承認待ち", cls: "ds-gate-warn" };
|
|
573
593
|
// 止めているものは警告色にしない(直す必要が無いので、橙にすると直しに行かせてしまう)
|
|
@@ -656,11 +676,13 @@ function regRowOfToolItem(item) {
|
|
|
656
676
|
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
657
677
|
*/
|
|
658
678
|
function toolsFoldSummary(states) {
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
|
|
679
|
+
// 表示の順は状態の語と同じ(読み取り中→接続OK(読み取りの対象外)→承認待ち→停止中→
|
|
680
|
+
// 未確認→登録状況を確認中です)。🔴 **新しい語をここへ足し忘れると、下の `order.indexOf`
|
|
681
|
+
// が `unknown` へ倒すので、畳んだ 1 行だけが「未確認」と言う**(開くと違う語が出る・#640)
|
|
682
|
+
var order = ["reading", "ok_not_ingested", "waiting", "stopped", "unknown", "pending"];
|
|
683
|
+
var count = { reading: 0, ok_not_ingested: 0, waiting: 0, stopped: 0, unknown: 0, pending: 0 };
|
|
662
684
|
(states || []).forEach(function (s) {
|
|
663
|
-
// ⚠
|
|
685
|
+
// ⚠ 5 語のどれかに当たるかは **order で見る**(素のオブジェクトの添字だと
|
|
664
686
|
// "constructor" のような語が継承プロパティに当たって、知らない語が素通りする)
|
|
665
687
|
var k = String(s == null ? "" : s);
|
|
666
688
|
count[order.indexOf(k) < 0 ? "unknown" : k] += 1;
|
|
@@ -1172,6 +1194,145 @@ function sanitizeStateNow(v) {
|
|
|
1172
1194
|
}
|
|
1173
1195
|
return out.length ? out : null;
|
|
1174
1196
|
}
|
|
1197
|
+
/**
|
|
1198
|
+
* その行が「接続はできるが、Gold の材料にしていない」**中立**の事実か(#640・engine #399)。
|
|
1199
|
+
*
|
|
1200
|
+
* 夜間の Gold 昇格は、性質が「作業物」で取得ごと省いたソースにも到達性を 1 回書く
|
|
1201
|
+
* (engine #399・PR #405)。同じ ref に 2 行が並ぶ:
|
|
1202
|
+
*
|
|
1203
|
+
* ```
|
|
1204
|
+
* SK: dev##<owner>/<repo>#reachable status: ok by: gold
|
|
1205
|
+
* SK: dev##<owner>/<repo>#ingested status: skipped by: gold
|
|
1206
|
+
* detail: 性質が作業物のため Gold の材料にしません
|
|
1207
|
+
* ```
|
|
1208
|
+
*
|
|
1209
|
+
* 🔴 **「鍵が無くて取り込みを始めていない」`skipped` と混ぜない(#225)。** どちらも同じ語だが、
|
|
1210
|
+
* 利用者が取るべき行動が正反対で、こちらは**何もしなくてよい**——警告(橙)に落とすと、
|
|
1211
|
+
* GitHub を登録した全案件が「直すものがある」と言われる(engine #399 実装レビュー🟡3)。
|
|
1212
|
+
* 見分ける材料は書き手(`by: "gold"`)で、理由文は engine が `by` の綴りを変えた日の保険。
|
|
1213
|
+
*
|
|
1214
|
+
* 🔴 **cap=`dev` で門を掛けるのが、「開発以外は 1 バイトも変わらない」の実体。**
|
|
1215
|
+
* 課題管理・デザインの `skipped`(=鍵未登録)はこの関数に一度も当たらない。他の能力にも
|
|
1216
|
+
* 「読まないと決めた」が生まれたら、そのときに cap を足す(先回りして広げない——
|
|
1217
|
+
* 広げた先の `skipped` が鍵未登録かどうかを、ここでは確かめられない)。
|
|
1218
|
+
*
|
|
1219
|
+
* ⚠ **チャットには同じ穴が残っている(この便では直さない・実装レビュー🟡8)。** engine の
|
|
1220
|
+
* 門(`external-sources.sh`)は GitHub 専用ではなく、`nature: 作業物` を宣言した Slack
|
|
1221
|
+
* チャンネル / Google Chat スペースにも `chat##…#ingested: skipped` を書く。ここは
|
|
1222
|
+
* `cap !== "dev"` で弾くので、その接続先の Home は #640 以前と**まったく同じ嘘**
|
|
1223
|
+
* (「読み取り中」)を言う。広げるときは、チャットの `skipped` に鍵未登録の書き手が
|
|
1224
|
+
* いないことを先に確かめる。
|
|
1225
|
+
*
|
|
1226
|
+
* ⚠ **`goldState: "excluded"`(行の「読み取り停止中」)とも別物。** あちらは人が
|
|
1227
|
+
* `dev-sources.json` の exclude に書いて止めたもので、こちらはソースの性質で門が省いたもの。
|
|
1228
|
+
*
|
|
1229
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す。
|
|
1230
|
+
* 正規表現も持たない——文字列の一致だけで足りる)。
|
|
1231
|
+
*/
|
|
1232
|
+
function devExcludedSkip(row) {
|
|
1233
|
+
if (!row || row.cap !== "dev" || row.question !== "ingested")
|
|
1234
|
+
return false;
|
|
1235
|
+
if (row.status !== "skipped")
|
|
1236
|
+
return false;
|
|
1237
|
+
// 🔴 **書き手と理由の AND(片方だけで中立と決めない)。** engine の `neutral` の印は
|
|
1238
|
+
// ストアの属性にならない(`connection-state-writer.mjs` の `historyArgs` は履歴を飛ばす
|
|
1239
|
+
// だけ)ので、画面が中立と言える材料はこの 2 つしかない。`by: "gold"` だけで倒すと、
|
|
1240
|
+
// 夜間が**本物の** `skipped` を dev に書き始めた日に、⚠️ にしたい行が黙って
|
|
1241
|
+
// 「接続OK」に化ける(倒れる向きが問題を隠す側になる・設計レビュー🔴3)。
|
|
1242
|
+
// 理由文の印は engine の 2 文(`性質が作業物のため…` / `ソースの性質により…`)に共通で、
|
|
1243
|
+
// 正本は `infra/lambda/shared/adapters.mjs` の `INGEST_NEUTRAL_DETAIL_MARK`
|
|
1244
|
+
// (写しのずれは `state-vocab-parity.test.mjs` が見張る)
|
|
1245
|
+
if (row.by !== "gold")
|
|
1246
|
+
return false;
|
|
1247
|
+
var d = typeof row.detail === "string" ? row.detail : "";
|
|
1248
|
+
return d.indexOf("材料にしません") >= 0;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* 「いま材料にしていない」開発の接続先(#640)。**鍵は ref の生値**(`overlayStateOnFleet` の
|
|
1252
|
+
* `dev` の鍵と同じ畳み方——揃えないと、行に札が出ないのに Home だけ出る食い違いになる)。
|
|
1253
|
+
*
|
|
1254
|
+
* 🔴 **同じ接続先の「届くか」のほうが新しければ、その中立は古い事実として捨てる。**
|
|
1255
|
+
* 接続状態の行に TTL は無く、engine が中立の行を書くのは**門で省いた晩だけ**
|
|
1256
|
+
* (`connection-state-write-gold.mjs` の `gatedIngestedRow`)。登録簿で性質を「会話」に
|
|
1257
|
+
* 直すと、engine は翌晩から**行を書かないだけ**で、`ingested: ok` に上書きはしない。
|
|
1258
|
+
* 鮮度を見ないと、**言われたとおりに直した人の画面が永久に変わらない**——
|
|
1259
|
+
* 「登録簿で性質を『会話』にしてください」と出し続ける(設計レビュー🔴2)。
|
|
1260
|
+
*
|
|
1261
|
+
* 🔴 **比べる相手は「その晩の Gold 昇格が回った時刻」(`by: "gold"` の行の最新の `at`)。**
|
|
1262
|
+
* 同じ ref の「届くか」と比べてはいけない——接続状態の SK は `cap#workspace#ref#question`
|
|
1263
|
+
* で **`reachable` は 1 本しかなく**、「接続を確認」(`by: "button"`)がその 1 本を
|
|
1264
|
+
* 上書きする。比べると次の 2 つが**どちらも**起きる(実装レビュー🔴1):
|
|
1265
|
+
*
|
|
1266
|
+
* - ボタンの行も比べる … 押した瞬間に `at` が今になり、**押しただけで札が消える**
|
|
1267
|
+
* (押した人には「確認したら読まれるようになった」と読める)
|
|
1268
|
+
* - 夜間の行だけ比べる … 押すと夜間の行が**消える**ので比べる相手を失い、
|
|
1269
|
+
* 性質を直して消えたはずの札が**押しただけで復活する**
|
|
1270
|
+
*
|
|
1271
|
+
* 夜間の Gold 昇格は 1 回の run の全部の行に**同じ `at`** を書く(engine の
|
|
1272
|
+
* `connection-state-write-gold.mjs` は `at` を run で 1 つだけ作る)。だから
|
|
1273
|
+
* **書き手が `gold` の行の最新の `at`**=その案件で夜間が最後に回った時刻で、これは
|
|
1274
|
+
* ボタンが 1 本上書きしても残る(他の接続先・他の問いの行が持っている)。
|
|
1275
|
+
* 中立の行自身も `by: "gold"` なので、**厳密に新しいときだけ**捨てれば同じ晩の組は残る。
|
|
1276
|
+
*
|
|
1277
|
+
* ⚠ **残る穴**: その案件の `by: "gold"` の行が**この 1 本だけ**(接続先が 1 つで、
|
|
1278
|
+
* その `reachable` をボタンが上書きした)ときは比べる相手が無く、古い札が次の夜まで残る。
|
|
1279
|
+
* 塞ぐのは engine 側(門を通らなくなった先の `ingested` の行を消す/`ok` を書く)で、
|
|
1280
|
+
* 決定ログ `20260916-640.md` の「覆し方」に書いてある。
|
|
1281
|
+
*
|
|
1282
|
+
* 時刻はミリ秒ありの ISO に正規化済み(サーバの `normalizeAt`)なので辞書順で比べられる。
|
|
1283
|
+
*
|
|
1284
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
1285
|
+
*/
|
|
1286
|
+
function devExcludedRefs(rows) {
|
|
1287
|
+
var out = {};
|
|
1288
|
+
// その案件で夜間の Gold 昇格が最後に回った時刻。**能力も問いも問わず集める**
|
|
1289
|
+
// ——1 回の run は全部の行に同じ `at` を書くので、ボタンが 1 本上書きしても
|
|
1290
|
+
// 他の行が同じ時刻を持っている(上の項)
|
|
1291
|
+
var lastGoldAt = "";
|
|
1292
|
+
var list = Array.isArray(rows) ? rows : [];
|
|
1293
|
+
var i, r, k;
|
|
1294
|
+
for (i = 0; i < list.length; i++) {
|
|
1295
|
+
r = list[i];
|
|
1296
|
+
if (!r)
|
|
1297
|
+
continue;
|
|
1298
|
+
if (r.by === "gold" && String(r.at) > lastGoldAt)
|
|
1299
|
+
lastGoldAt = String(r.at);
|
|
1300
|
+
if (r.cap !== "dev")
|
|
1301
|
+
continue;
|
|
1302
|
+
k = String(r.ref == null ? "" : r.ref);
|
|
1303
|
+
if (!k)
|
|
1304
|
+
continue;
|
|
1305
|
+
if (devExcludedSkip(r) && (!out[k] || String(r.at) > String(out[k].at)))
|
|
1306
|
+
out[k] = r;
|
|
1307
|
+
}
|
|
1308
|
+
for (k in out) {
|
|
1309
|
+
if (!Object.prototype.hasOwnProperty.call(out, k))
|
|
1310
|
+
continue;
|
|
1311
|
+
// **厳密に新しいときだけ捨てる。** 同じ晩の組(`at` が同値)を落とさないため
|
|
1312
|
+
if (lastGoldAt > String(out[k].at))
|
|
1313
|
+
delete out[k];
|
|
1314
|
+
}
|
|
1315
|
+
return out;
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* 中立の行の理由文から、画面に出す短語を作る(#640)。
|
|
1319
|
+
*
|
|
1320
|
+
* 🔴 **engine が名指しを避けた性質を、画面が断定しない。** engine は性質が語彙
|
|
1321
|
+
* (会話/作業物/参照資料)に載っているときだけ名指しし、載っていなければ
|
|
1322
|
+
* 「ソースの性質により Gold の材料にしません」と書く(`gatedIngestedRow`)。
|
|
1323
|
+
* viewer に性質の語彙の写しは持たない——持つと 4 枚目の写しになり、engine が
|
|
1324
|
+
* 門に掛ける性質を増やした日に黙ってずれる(engine 設計レビュー🟡6 と同じ罠)。
|
|
1325
|
+
* **理由文が名指ししている語をそのまま括弧に入れる**のが、写しを増やさない唯一の形。
|
|
1326
|
+
*
|
|
1327
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
1328
|
+
*/
|
|
1329
|
+
function devExcludedLabel(detail) {
|
|
1330
|
+
var d = typeof detail === "string" ? detail : "";
|
|
1331
|
+
var at = d.indexOf("性質が");
|
|
1332
|
+
var to = d.indexOf("のため");
|
|
1333
|
+
var nature = at === 0 && to > 3 ? d.slice(3, to) : "";
|
|
1334
|
+
return nature ? "読み取りの対象外(" + nature + ")" : "読み取りの対象外";
|
|
1335
|
+
}
|
|
1175
1336
|
/**
|
|
1176
1337
|
* ストアの「届くか」を行に重ねる。**まとめ表の時刻とは比べない。**
|
|
1177
1338
|
* fleet-status.json は chat / dev の gate・needed を焼き込まない(観測の一本化・工程1。
|
|
@@ -1212,12 +1373,23 @@ function sanitizeStateNow(v) {
|
|
|
1212
1373
|
* 画面に届かない(fleet-status.json には焼き込まれないので、ライブが届かない案件では出ない
|
|
1213
1374
|
* ——それは意図。古いスナップショットの理由を出すより、出さないほうが嘘にならない)。
|
|
1214
1375
|
* needed と同じく、上書きするときは空でも必ず載せる
|
|
1376
|
+
*
|
|
1377
|
+
* **開発の行だけ、`ingested` の中立の行も載せる(#640)。** 「接続できる」と「Gold の
|
|
1378
|
+
* 材料にしている」は別の状態で、`reachable: ok` だけを載せると、読みに行かないと決めた
|
|
1379
|
+
* リポジトリが画面で「読み取り中」になる(engine #399 の申し送り)。載せる欄は
|
|
1380
|
+
* `ingestExcluded`(併記の札を出すか)と `ingestExcludedDetail`(語の括弧に入れる性質)。
|
|
1381
|
+
* 🔴 **`goldState: "excluded"`(人が `dev-sources.json` の exclude で止めた)と別物。**
|
|
1215
1382
|
*/
|
|
1216
1383
|
function overlayStateOnFleet(view, rows) {
|
|
1217
1384
|
const v = view || {};
|
|
1218
1385
|
if (!rows || !rows.length || !Array.isArray(v.externalSources))
|
|
1219
1386
|
return v;
|
|
1220
1387
|
const byKey = {};
|
|
1388
|
+
// 「接続できる」と「Gold の材料にしている」は別の状態(#640)。**鮮度の門は
|
|
1389
|
+
// `devExcludedRefs` 1 本**(タイル・Home と同じ規則を 2 枚にしない)。拾う対象は
|
|
1390
|
+
// この下が捨てている行(`question !== "reachable"`)だけなので、チャット・
|
|
1391
|
+
// Google Chat の経路は 1 バイトも変わらない
|
|
1392
|
+
const excludedByRef = devExcludedRefs(rows);
|
|
1221
1393
|
for (const r of rows) {
|
|
1222
1394
|
if (r.question !== "reachable")
|
|
1223
1395
|
continue;
|
|
@@ -1233,16 +1405,28 @@ function overlayStateOnFleet(view, rows) {
|
|
|
1233
1405
|
if (!s || !s.ref)
|
|
1234
1406
|
return s;
|
|
1235
1407
|
let hit = null;
|
|
1408
|
+
let ex = null;
|
|
1236
1409
|
if (s.type === "slack")
|
|
1237
1410
|
hit = byKey["chat\t" + String(s.workspace || "") + "\t" + String(s.ref)];
|
|
1238
1411
|
else if (s.type === "google-chat")
|
|
1239
1412
|
hit = byKey["google-chat\t" + String(s.ref)];
|
|
1240
|
-
else if (String(s.type || "").indexOf("github") === 0)
|
|
1413
|
+
else if (String(s.type || "").indexOf("github") === 0) {
|
|
1241
1414
|
hit = byKey["dev\t" + String(s.ref)];
|
|
1242
|
-
|
|
1243
|
-
|
|
1415
|
+
// ⚠ 鍵は ref の生値(1 つ上の `dev` の鍵と同じ畳み方)。**`liveRowVerdict` だけは
|
|
1416
|
+
// 両側を小文字に畳む**ので、大小が揺れた repo では Home にだけ札が出る食い違いが
|
|
1417
|
+
// 作れる(#566 の宿題と同根・この便では直さず申し送り)
|
|
1418
|
+
ex = excludedByRef[String(s.ref)] || null;
|
|
1419
|
+
}
|
|
1420
|
+
// **到達性の行が無い夜でも、併記だけは出す。** engine は 2 行を同じ晩に書くが、
|
|
1421
|
+
// 片方しか届かない窓を「何も言わない」に倒すと、画面が知っている事実を捨てる
|
|
1422
|
+
if (!hit) {
|
|
1423
|
+
if (!ex)
|
|
1424
|
+
return s;
|
|
1425
|
+
changed = true;
|
|
1426
|
+
return Object.assign({}, s, { ingestExcluded: true, ingestExcludedDetail: String(ex.detail || "") });
|
|
1427
|
+
}
|
|
1244
1428
|
changed = true;
|
|
1245
|
-
return Object.assign({}, s, {
|
|
1429
|
+
return Object.assign({}, s, ex ? { ingestExcluded: true, ingestExcludedDetail: String(ex.detail || "") } : {}, {
|
|
1246
1430
|
gate: hit.status,
|
|
1247
1431
|
gateAt: hit.at,
|
|
1248
1432
|
gateBy: hit.by,
|
|
@@ -2507,7 +2691,12 @@ const TILE_CAPS = {
|
|
|
2507
2691
|
// `cap: "google-chat"` の行は夜間の Gold 昇格が書く(#153 PR-E で結線済み)ので、
|
|
2508
2692
|
// 夜間が一度走れば規則2/3(⚠️ / 接続OK)まで進む。走る前は規則4(実績なし→中立)
|
|
2509
2693
|
"チャット-google-chat": { id: "google-chat", question: "reachable", noFact: "登録済み(接続は未確認です)", keyLabel: "", refKeyed: true },
|
|
2510
|
-
|
|
2694
|
+
// 🔴 **`alsoBad: ["ingested"]` は `devExcludedSkip` の篩と一対で足した(#640)。** 夜間が
|
|
2695
|
+
// 「接続はできるが Gold の材料にしていない」を `ingested: skipped` で書くようになった
|
|
2696
|
+
// (engine #399)ので、`reachable` だけを見ていると画面が「読み取り中」と嘘をつく。
|
|
2697
|
+
// ただし `BAD_STATE_STATUSES.ingested` は `skipped` を**悪い**と数えるので、篩を外すと
|
|
2698
|
+
// **GitHub を登録した全案件のタイルが ⚠️「取り込みを飛ばしました」**になる
|
|
2699
|
+
"開発": { id: "dev", question: "reachable", noFact: "登録済み(接続は未確認です)", keyLabel: "", alsoBad: ["ingested"], refKeyed: true },
|
|
2511
2700
|
};
|
|
2512
2701
|
/**
|
|
2513
2702
|
* 登録したばかりで、まだ実測の行が1件も届いていない接続先があるときの語(#523 決定6)。
|
|
@@ -2901,6 +3090,11 @@ function deriveCapTile(cap, ctx) {
|
|
|
2901
3090
|
var skipped = 0;
|
|
2902
3091
|
var noToken = 0;
|
|
2903
3092
|
var unreachable = 0;
|
|
3093
|
+
// 「接続はできるが Gold の材料にしていない」接続先(#640)。**警告には数えない。**
|
|
3094
|
+
// 鮮度の門(古い中立を捨てる)は `devExcludedRefs` が持つ——ここに書き写すと、
|
|
3095
|
+
// 行・Home・タイルで「いつ古いと見なすか」が割れる
|
|
3096
|
+
var excludedRefs = meta.id === "dev" ? devExcludedRefs(rows) : {};
|
|
3097
|
+
var excluded = 0;
|
|
2904
3098
|
var okSeen = false;
|
|
2905
3099
|
// 部分失敗の内訳の合計(#634)。**能力の全接続先を足す**——タイルは能力ぜんたいを 1 語で言う
|
|
2906
3100
|
var sumOk = 0;
|
|
@@ -2917,6 +3111,15 @@ function deriveCapTile(cap, ctx) {
|
|
|
2917
3111
|
// 出続ける(engine #314 の症状の候補3)。**篩い方の正本は stateRefKey 1箇所**
|
|
2918
3112
|
if (refs && meta.refKeyed && !refs[stateRefKey(meta.id, r.ref, r.workspace)])
|
|
2919
3113
|
continue;
|
|
3114
|
+
// 🔴 **中立の事実を、悪い語の表に掛ける前に抜く(#640)。** `BAD_STATE_STATUSES.ingested`
|
|
3115
|
+
// は `skipped` を悪いと数える(鍵が無くて始めていない、の意味)ので、ここを外すと
|
|
3116
|
+
// **GitHub を登録した全案件のタイルが ⚠️ になる**(engine #399 実装レビュー🟡3)。
|
|
3117
|
+
// 数えるのは**鮮度の門を通った分だけ**——性質を「会話」に直した接続先の古い行は
|
|
3118
|
+
// ここで黙って落とす(⚠️ にもしない。直すものが無い過去の事実なので)。
|
|
3119
|
+
// 件数は規則3 の見出しへ回す。「読まないと決めた」を黙って消すと、画面が
|
|
3120
|
+
// 「全部読んでいます」と読める(#523「常に真実を表示する」)
|
|
3121
|
+
if (devExcludedSkip(r))
|
|
3122
|
+
continue;
|
|
2920
3123
|
// **一度でも成功していれば実績あり。** `lastOkAt` を見るのは、いま失敗している行でも
|
|
2921
3124
|
// 「繋がったことがある」のは事実だから(規則2が先に立つので表示は⚠️のまま)。
|
|
2922
3125
|
// **実績は `question`(その能力が「実際に動いた」と言える問い)の側だけで数える**
|
|
@@ -2958,6 +3161,16 @@ function deriveCapTile(cap, ctx) {
|
|
|
2958
3161
|
else
|
|
2959
3162
|
unreachable++;
|
|
2960
3163
|
}
|
|
3164
|
+
// 「材料にしていない」は**接続先ごとに 1 件**(#640)。行を数えると、同じ ref の古い行が
|
|
3165
|
+
// 残っている案件で件数が水増しされる。孤児の篩(#523 決定2)はここにも掛ける
|
|
3166
|
+
// ——外した repo の中立の行が「読み取りの対象外が 3 件」に数え続けられないように
|
|
3167
|
+
for (var ek in excludedRefs) {
|
|
3168
|
+
if (!Object.prototype.hasOwnProperty.call(excludedRefs, ek))
|
|
3169
|
+
continue;
|
|
3170
|
+
if (refs && meta.refKeyed && !refs[stateRefKey(meta.id, ek)])
|
|
3171
|
+
continue;
|
|
3172
|
+
excluded++;
|
|
3173
|
+
}
|
|
2961
3174
|
// ---- 規則2: 実測が悪い → 警告 ----
|
|
2962
3175
|
//
|
|
2963
3176
|
// **失敗を先に言う。** 「鍵が無くて飛ばした」より「鍵はあるのに取れなかった」ほうが
|
|
@@ -2986,6 +3199,12 @@ function deriveCapTile(cap, ctx) {
|
|
|
2986
3199
|
if (okSeen && sumFailed > 0) {
|
|
2987
3200
|
return { rule: 3, state: "ok", text: "接続OK(" + sumOk + " 件取り込み・" + sumFailed + " 件失敗)", keyMissing: false };
|
|
2988
3201
|
}
|
|
3202
|
+
// **読みに行かないと決めた接続先は、件数で言う(#640)。** 「接続OK」の一言で丸めると
|
|
3203
|
+
// 「決定・用語の材料になっている」と読めるし、⚠️ に落とすと直すものが無いのに直しに
|
|
3204
|
+
// 行かせる。**帯は症状だけ**——性質を変える手順は行の補足が 1 行だけ持つ
|
|
3205
|
+
if (okSeen && excluded > 0) {
|
|
3206
|
+
return { rule: 3, state: "ok", text: "接続OK(読み取りの対象外が " + excluded + " 件)", keyMissing: false };
|
|
3207
|
+
}
|
|
2989
3208
|
if (okSeen)
|
|
2990
3209
|
return { rule: 3, state: "ok", text: "接続OK", keyMissing: false };
|
|
2991
3210
|
// ---- 規則4: 実績なし → 中立 ----
|
|
@@ -3333,12 +3552,28 @@ function liveToolItems(tools, registered, rows) {
|
|
|
3333
3552
|
}
|
|
3334
3553
|
return "reachable";
|
|
3335
3554
|
};
|
|
3555
|
+
// 「いま材料にしていない」接続先(#640)。**ループの外で 1 回だけ作る**
|
|
3556
|
+
//(行ごとに作り直すと、行数 × 項目数の走査になる)
|
|
3557
|
+
var excludedRefs = devExcludedRefs(rows);
|
|
3336
3558
|
var stateOf = function (regKey, regRow, fallback) {
|
|
3337
3559
|
var v = liveRowVerdict(regKey, regRow, rows, questionOf(regKey));
|
|
3338
3560
|
if (!v)
|
|
3339
3561
|
return fallback;
|
|
3340
|
-
if (v.status === "ok")
|
|
3562
|
+
if (v.status === "ok") {
|
|
3563
|
+
// 「接続できる」と「Gold の材料にしている」を別に出す(#640・engine #399)。
|
|
3564
|
+
// **届いていない行には出さない**(`v.status === "ok"` の中だけ)——「アクセス不可」の
|
|
3565
|
+
// ほうが直す一手を持っているので、そちらを勝たせる(帯は症状)。
|
|
3566
|
+
// 判定は `devExcludedSkip` 1 本(タイル・操作タブの行と共有)、行の突き合わせは
|
|
3567
|
+
// `liveRowVerdict` 1 本(鍵の畳み方・複数行の勝ち方を 2 枚にしない・R10)
|
|
3568
|
+
// 鮮度の門も 1 本(`devExcludedRefs`)を通す——性質を「会話」に直した接続先の
|
|
3569
|
+
// 古い行で、Home だけが「読み取りの対象外」と言い続けないように
|
|
3570
|
+
if (regKey === "dev") {
|
|
3571
|
+
var iv = liveRowVerdict(regKey, regRow, rows, "ingested");
|
|
3572
|
+
if (iv && devExcludedSkip(iv.row) && excludedRefs[String(iv.row.ref)])
|
|
3573
|
+
return "ok_not_ingested";
|
|
3574
|
+
}
|
|
3341
3575
|
return "reading";
|
|
3576
|
+
}
|
|
3342
3577
|
if (v.status === "bad")
|
|
3343
3578
|
return "waiting";
|
|
3344
3579
|
return "unknown";
|
|
@@ -3479,17 +3714,78 @@ function liveToolItems(tools, registered, rows) {
|
|
|
3479
3714
|
}
|
|
3480
3715
|
return out;
|
|
3481
3716
|
}
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3717
|
+
/**
|
|
3718
|
+
* その能力を同期するワークフローの id を当てる正規表現(持たない能力は `null`)。
|
|
3719
|
+
*
|
|
3720
|
+
* 🔴 **能力→パイプラインの対応表はここが唯一の持ち主。** 呼び出し側に渡させると、
|
|
3721
|
+
* クライアント側(この関数を `.toString()` で受け取る側)が同じ表を書き写すことになり、
|
|
3722
|
+
* 書き忘れると warn 判定が丸ごと死ぬ——実データで、東京ヴェルディの課題管理が
|
|
3723
|
+
* マップは⚠️・タイルは「接続OK」になった。**この関数が読むものは、この関数が持つ。**
|
|
3724
|
+
*
|
|
3725
|
+
* 🔴 **この表を読む先は 2 つある(#654 設計レビュー🔴3)。** `capabilityWarnSource`
|
|
3726
|
+
* (直近の run が `failure`)と、`capabilityState` の `pipeSkipped`
|
|
3727
|
+
* (`applicable === false`=空振りした run の時刻を「繋がっている証拠」にしない)。
|
|
3728
|
+
* **warn 側だけ 1 本にして `pipeSkipped` に写しを残さないこと**——残すと、表を直した回に
|
|
3729
|
+
* 「⚠️ は消えたが『接続OK/未接続』だけ別物」という割れ方をする。
|
|
3730
|
+
*
|
|
3731
|
+
* 🔴 **表は関数の中に literal で置く(モジュール直下の `const` にしない)。** export した
|
|
3732
|
+
* 瞬間に tsc が `exports.X` へ書き換え、`.toString()` で客先へ渡った関数が
|
|
3733
|
+
* ブラウザで未定義を参照する——ライブ取得が丸ごと落ちて画面が静的表示に戻る
|
|
3734
|
+
* (`ingestFacts` の項と同じ穴)。
|
|
3735
|
+
*
|
|
3736
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
3737
|
+
*/
|
|
3738
|
+
function capabilityPipeRe(cap) {
|
|
3487
3739
|
var PIPE = {
|
|
3488
3740
|
"課題管理": /sync-backlog/,
|
|
3489
3741
|
"会議": /ingest-minutes/,
|
|
3490
3742
|
"共有資料": /sync-materials/,
|
|
3491
3743
|
"デザイン": /sync-designs|update-design-notes/,
|
|
3492
3744
|
};
|
|
3745
|
+
return PIPE[cap] || null;
|
|
3746
|
+
}
|
|
3747
|
+
/**
|
|
3748
|
+
* その能力の⚠️が、**どの材料から立ったか**(#654)。`null` なら warn の材料が無い。
|
|
3749
|
+
*
|
|
3750
|
+
* - `"live"` … ライブ参照の行(`externalSources` の gate)。チャット・開発・その他。
|
|
3751
|
+
* `stateCtx()` が接続状態ストアを**重ねたあとの行**なので、まとめ表由来でも
|
|
3752
|
+
* **その晩の観測**まで追いついている
|
|
3753
|
+
* - `"pipeline"` … まとめ表の `pipelines`(ワークフローの run の結論)。課題管理・会議・
|
|
3754
|
+
* 共有資料・デザイン。**ビルド時に焼かれ、ライブで取り直されない**
|
|
3755
|
+
* (`stateCtx()` が上書きを当てるのは `externalSources` だけ)ので、一度赤くなると
|
|
3756
|
+
* **次のビルドまで赤いまま**になる
|
|
3757
|
+
*
|
|
3758
|
+
* 🔴 **この 2 つを混ぜないために切り出してある(#654)。** タイルには「導出(接続状態
|
|
3759
|
+
* ストア)が warn を降格しない」という門があるが、**焼いた `pipelines` の赤にまで
|
|
3760
|
+
* その門を効かせると、ストアが「たった今 取り込めた」と言っている能力に
|
|
3761
|
+
* 「⚠️ 同期が失敗しています」と出る**——gift-stvv が 2026-09-17 に踏んだ形で、
|
|
3762
|
+
* 同じページのモーダルと接続マップは「接続OK」と言っていた
|
|
3763
|
+
* (`ops-ui-controls-policy.md` R10「状態の出どころが複数あるときは、新しい方に揃える」)。
|
|
3764
|
+
*
|
|
3765
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す。
|
|
3766
|
+
* 引くのは `capabilityPipeRe` / `sourceMatchesAdapter` / `sourceNeedsAttention` / `CAP_OTHER`
|
|
3767
|
+
* の 4 つだけで、どれも関数宣言か `var`——**流し込む順は効かない**)。
|
|
3768
|
+
*/
|
|
3769
|
+
function capabilityWarnSource(cap, ctx, adapter) {
|
|
3770
|
+
// **ライブ参照かどうかは能力名で決める。** 行の有無で決めると、行が 0 件の回に
|
|
3771
|
+
// 「パイプライン由来」へ倒れる——チャット・開発には対応するパイプラインが無いので
|
|
3772
|
+
// 答えは同じ null だが、**判定の意味が変わる**(この関数の答えは門の可否に使われる)
|
|
3773
|
+
var isLive = cap === "チャット" || cap === "開発" || cap === CAP_OTHER;
|
|
3774
|
+
if (isLive) {
|
|
3775
|
+
// **アダプタが指定されたら、その行だけで数える(#153)。** チャットが2アダプタに
|
|
3776
|
+
// なったので、Slack のタイルの warn 判定に Google Chat の gate 落ちが混ざると、
|
|
3777
|
+
// 直す場所が違う方を指す。絞り方の正本は sourceMatchesAdapter
|
|
3778
|
+
return (ctx.externals || []).filter(function (s) { return sourceMatchesAdapter(s.type, cap, adapter); })
|
|
3779
|
+
.some(function (s) { return sourceNeedsAttention(s); }) ? "live" : null;
|
|
3780
|
+
}
|
|
3781
|
+
var re = capabilityPipeRe(cap);
|
|
3782
|
+
return (ctx.pipes || []).some(function (p) {
|
|
3783
|
+
return re != null && re.test(p.id) && p.applicable !== false && p.lastConclusion === "failure";
|
|
3784
|
+
}) ? "pipeline" : null;
|
|
3785
|
+
}
|
|
3786
|
+
function capabilityState(cap, ctx, adapter) {
|
|
3787
|
+
// **能力→パイプラインの対応は capabilityPipeRe が持つ(#654)。** ここに写しを
|
|
3788
|
+
// 作らない——写しがずれると「マップは⚠️・タイルは接続OK」が復活する
|
|
3493
3789
|
// **ライブ参照かどうかは、能力名ではなく渡された行から決める。** 名前で決めていたとき、
|
|
3494
3790
|
// 未知の種別を寄せた「その他」は行を2件持っているのに「未使用」と言い切っていた
|
|
3495
3791
|
// (読み手は未使用を信じて押さないので、行が消えるより悪い)
|
|
@@ -3499,7 +3795,10 @@ function capabilityState(cap, ctx, adapter) {
|
|
|
3499
3795
|
const liveExts = ctx.externals.filter(function (s) { return sourceMatchesAdapter(s.type, cap, adapter); });
|
|
3500
3796
|
const isLive = cap === "チャット" || cap === "開発" || cap === CAP_OTHER;
|
|
3501
3797
|
const internal = ctx.internals.filter(function (s) { return s.kind === cap; })[0];
|
|
3502
|
-
|
|
3798
|
+
// 🔴 **空振りした run(applicable: false)を篩うのにも同じ表を引く(#654 設計レビュー🔴3)。**
|
|
3799
|
+
const pipeRe = capabilityPipeRe(cap);
|
|
3800
|
+
// ⚠️ の材料と、その出どころ(#654)。**warn の判定はこの 1 本だけを通す**
|
|
3801
|
+
const warnSrc = capabilityWarnSource(cap, ctx, adapter);
|
|
3503
3802
|
// ---- #125②: 導出(capabilities)があるならそれが状態の正本 ----
|
|
3504
3803
|
//
|
|
3505
3804
|
// **ここが唯一の分岐点。** 導出の有無で描き分けるのはこの1箇所に閉じ、
|
|
@@ -3528,13 +3827,7 @@ function capabilityState(cap, ctx, adapter) {
|
|
|
3528
3827
|
if (derived === "broken")
|
|
3529
3828
|
return "warn";
|
|
3530
3829
|
if (derived === "on") {
|
|
3531
|
-
return
|
|
3532
|
-
? liveExts.some(function (s) { return sourceNeedsAttention(s); })
|
|
3533
|
-
: ctx.pipes.some(function (p) {
|
|
3534
|
-
return pipeRe != null && pipeRe.test(p.id) && p.applicable !== false && p.lastConclusion === "failure";
|
|
3535
|
-
}))
|
|
3536
|
-
? "warn"
|
|
3537
|
-
: "ok";
|
|
3830
|
+
return warnSrc ? "warn" : "ok";
|
|
3538
3831
|
}
|
|
3539
3832
|
// unset / empty / 未知の値。**未知を ok にも off にも寄せない**——どちらも嘘になる。
|
|
3540
3833
|
// 「まだ繋がっていない」側に倒すのが安全(繋がっていないのに線を引かない)。
|
|
@@ -3548,7 +3841,7 @@ function capabilityState(cap, ctx, adapter) {
|
|
|
3548
3841
|
// 状態が unset(engine がこのアダプタをまだ知らない移行期間)だからと黙らせると、
|
|
3549
3842
|
// 同じ行から描く接続マップだけが⚠️になり、「マップが⚠️・直下は静か」という
|
|
3550
3843
|
// 既知の最悪事故の変形が移行期間のデフォルトになる
|
|
3551
|
-
if (
|
|
3844
|
+
if (warnSrc === "live")
|
|
3552
3845
|
return "warn";
|
|
3553
3846
|
return "idle";
|
|
3554
3847
|
}
|
|
@@ -3577,14 +3870,8 @@ function capabilityState(cap, ctx, adapter) {
|
|
|
3577
3870
|
(isLive && liveExts.length > 0);
|
|
3578
3871
|
const off = (internal != null && internal.enabled === false) || !used;
|
|
3579
3872
|
// 問題あり: ライブ参照はgate≠okが1件以上、同期ソースは対応パイプラインの直近runがfailure
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
? liveExts.some(function (s) {
|
|
3583
|
-
return sourceNeedsAttention(s);
|
|
3584
|
-
})
|
|
3585
|
-
: ctx.pipes.some(function (p) {
|
|
3586
|
-
return (pipeRe != null && pipeRe.test(p.id) && p.applicable !== false && p.lastConclusion === "failure");
|
|
3587
|
-
}));
|
|
3873
|
+
//(判定の実体は capabilityWarnSource 1 本・#654)
|
|
3874
|
+
const warn = !off && !!warnSrc;
|
|
3588
3875
|
// 「実際に繋がっている」の証拠は共通で次のどれか:
|
|
3589
3876
|
// - 一度でも同期が走った(lastSync)
|
|
3590
3877
|
// - 正本のURLが導出できる(url。設定ファイルが実在して初めて出る)
|
|
@@ -3744,7 +4031,11 @@ function renderConnectionMap(site) {
|
|
|
3744
4031
|
const sub = `<text class="cm-sync" x="${cx}" y="67" text-anchor="middle"` +
|
|
3745
4032
|
(statusTs ? ` data-ts="${escapeHtml(statusTs)}"` : "") +
|
|
3746
4033
|
`>${escapeHtml(statusText)}</text>`;
|
|
3747
|
-
|
|
4034
|
+
// 🔴 **6ノードに常時焼いて、表示だけを切り替える(線と同じ形・#654)。** warn の
|
|
4035
|
+
// ノードにだけ焼いていたときは、`applyStateToConnMap` が当て直せず
|
|
4036
|
+
// **「緑のノードに⚠️が付いたまま」**が残った——ライブで接続OKに直っても、
|
|
4037
|
+
// ビルド時に赤かった能力は次のビルドまで⚠️を出し続ける(#654 の症状の片割れ)
|
|
4038
|
+
const badge = `<text class="cm-badge${warn ? "" : " is-hidden"}" x="${cx + 62}" y="24" text-anchor="middle">⚠️</text>`;
|
|
3748
4039
|
// クリックでページ内の該当詳細カード(アンカー)へスクロールする
|
|
3749
4040
|
const anchor = `ds-${c.cap}`;
|
|
3750
4041
|
nodes.push(`<g class="cm-node ${state}" data-target="${anchor}" tabindex="0" role="link" aria-label="${escapeHtml(c.cap)}の詳細へ">` +
|
|
@@ -4743,6 +5034,7 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
4743
5034
|
.cm-sync { font-size: 10.5px; fill: var(--muted); font-variant-numeric: tabular-nums; }
|
|
4744
5035
|
.cm-node.cm-off .cm-sync { fill: #9ca3af; }
|
|
4745
5036
|
.cm-badge { font-size: 13px; }
|
|
5037
|
+
.cm-badge.is-hidden { display: none; }
|
|
4746
5038
|
/* 「入ってこない」ときに自分で確かめる口。一覧の直前に置く */
|
|
4747
5039
|
.ds-syncnow { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: 0 0 .6rem; }
|
|
4748
5040
|
.ds-syncnow-label { font-size: .82rem; color: var(--muted); }
|
|
@@ -4837,7 +5129,7 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
4837
5129
|
.ds-check-label, .ds-check-action, .ds-check-detail,
|
|
4838
5130
|
.ds-pipe-label, .ds-pipe-todo,
|
|
4839
5131
|
.ds-empty, .sec-how, .modal-desc, .ds-toggle-msg,
|
|
4840
|
-
.ds-drive-note, .ds-inactive-note, .ds-gate-help,
|
|
5132
|
+
.ds-drive-note, .ds-inactive-note, .ds-gate-help, .ds-not-ingested-note,
|
|
4841
5133
|
/* 案件カレンダーの行(#428)。**カレンダー ID は空白の無い長い連なり**で、
|
|
4842
5134
|
失敗の理由(detail)も長さが読めない。ここを外すと会議のモーダルが横に溢れる */
|
|
4843
5135
|
.mt-cal-banner, .mt-cal-note, .mt-cal-warn, .mt-cal-primary, .mt-cal-sub, .mt-cal-id .rt-copy-text,
|
|
@@ -4886,6 +5178,13 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
4886
5178
|
トグルを撤去したいま、読み取られていないことを示すのはこのバッジだけ。
|
|
4887
5179
|
**判断のバッジなので、由来や組織のバッジより強く出す** */
|
|
4888
5180
|
.badge.ds-excluded { background: #f3f4f6; color: #4b5563; border: 1px solid #d1d5db; }
|
|
5181
|
+
/* 「接続はできるが Gold の材料にしていない」印(#640)。**「読み取り停止中」と同じ灰色**
|
|
5182
|
+
——どちらも「いまこの接続先がどう扱われているか」の印で、直すものが無い中立の事実。
|
|
5183
|
+
橙(警告)にすると、直しようのないものを直しに行かせる */
|
|
5184
|
+
.badge.ds-not-ingested { background: #f3f4f6; color: #4b5563; border: 1px solid #d1d5db; }
|
|
5185
|
+
/* その理由と、変えたいときの一手(1 行だけ)。**行の補足(.ds-gate-help)と同じ見た目**だが、
|
|
5186
|
+
「接続を確認」で隠される棚には置かない(押しても変わらない事実のため) */
|
|
5187
|
+
.ds-not-ingested-note { font-size: 12px; color: #6b7280; line-height: 1.6; margin: 4px 0 0; flex: 1 1 100%; }
|
|
4889
5188
|
/* 登録の由来(#118)。**薄く出す**——読み取りの可否や Gold 対象かより弱い情報で、
|
|
4890
5189
|
ここが目立つと「除外」「未宣言」の判断のバッジと同じ強さに見えてしまう */
|
|
4891
5190
|
/* どの Slack ワークスペースのチャンネルか(#104)。**由来のバッジと同じ強さにする**——
|
|
@@ -5406,6 +5705,13 @@ ${capabilityDisplayState.toString()}
|
|
|
5406
5705
|
${pending_ops_1.backlogTargetOf.toString()}
|
|
5407
5706
|
${issuesRefOf.toString()}
|
|
5408
5707
|
${sourceNeedsAttention.toString()}
|
|
5708
|
+
// 能力→パイプラインの対応表(#654)と、⚠️ の出どころ。**並びは読みやすさのためで、
|
|
5709
|
+
// 依存の順ではない**——関数宣言はこの IIFE の中で巻き上がる(実装レビュー🟡4 で実測)。
|
|
5710
|
+
// 🔴 **効くのは「対応表をモジュール直下の const にしない」のほう**——そこへ出して
|
|
5711
|
+
// export すると、tsc が参照を書き換えて、流し込んだ関数がブラウザで未定義を見る
|
|
5712
|
+
//(番人は state-vocab-parity / ingest-partial-failure の「素の JS だけを渡す」検査)
|
|
5713
|
+
${capabilityPipeRe.toString()}
|
|
5714
|
+
${capabilityWarnSource.toString()}
|
|
5409
5715
|
${capabilityState.toString()}
|
|
5410
5716
|
// ライブ確認の見切り(#256)。**書き写さない**——テストが固定している値と
|
|
5411
5717
|
// 画面が使う値が割れると、「10秒で戻る」検査が通ったまま実機では戻らなくなる
|
|
@@ -5494,6 +5800,12 @@ var INGEST_TILE_ROWS = ${JSON.stringify(INGEST_TILE_ROWS)};
|
|
|
5494
5800
|
${sanitizeIngestCounts.toString()}
|
|
5495
5801
|
${sanitizeIngestFailures.toString()}
|
|
5496
5802
|
${sanitizeStateNow.toString()}
|
|
5803
|
+
// 「接続はできるが Gold の材料にしていない」中立の行(#640)。🔴 **overlayStateOnFleet /
|
|
5804
|
+
// deriveCapTile / liveToolItems / 行の併記が全部この 1 本を引く。** 落とすと 4 か所が
|
|
5805
|
+
// 未定義を参照して、ライブ取得が丸ごと落ちる(画面が静的表示に戻る)
|
|
5806
|
+
${devExcludedSkip.toString()}
|
|
5807
|
+
${devExcludedRefs.toString()}
|
|
5808
|
+
${devExcludedLabel.toString()}
|
|
5497
5809
|
${overlayStateOnFleet.toString()}
|
|
5498
5810
|
// Home の「使用ツール」(#275)。**判定と表示語の実体はビルド時の定義**——
|
|
5499
5811
|
// 画面側に書き写すと、状態の言い換えが 2 枚になって片方だけ直る。
|
|
@@ -8684,10 +8996,20 @@ ${calendarAddUrl.toString()}
|
|
|
8684
8996
|
// Issues と Discussions は同じ接続先(同じ dev 行)なので、理由・補足は1本目だけが
|
|
8685
8997
|
// 持つ(#346)。同じ長文が2行に並ぶと一覧が案内で埋まる
|
|
8686
8998
|
var seenRef = {};
|
|
8999
|
+
// 「材料にしていない」の 1 行は、**この組織で実際に出した行があってから**畳む(#640)。
|
|
9000
|
+
// 🔴 「seenRef」 を写経して「1 本目かどうか」でフラグを立てると、1 本目が
|
|
9001
|
+
// 併記を持たない行だったときにフラグだけ消費され、**その組織のどの行にも
|
|
9002
|
+
// 補足が出ない**(設計レビュー🟡5)。**出した行だけを数える**
|
|
9003
|
+
var shownExcluded = false;
|
|
8687
9004
|
var cards = g.items.map(function (x) {
|
|
8688
9005
|
var again = !!(x.ref && seenRef[x.ref]);
|
|
8689
9006
|
if (x.ref) seenRef[x.ref] = 1;
|
|
8690
|
-
|
|
9007
|
+
// 🔴 **フラグを立てるのは、その行が実際に補足を出すときだけ。** 出さない行
|
|
9008
|
+
//(同じ ref の 2 本目・「読み取り停止中」)でフラグを消費すると、**その組織の
|
|
9009
|
+
// どの行にも補足が出ない**(設計レビュー🟡5 と同じ罠。条件は 「extSourceCard」 と揃える)
|
|
9010
|
+
var quietExcluded = shownExcluded;
|
|
9011
|
+
if (!again && x && x.ingestExcluded === true && x.goldState !== "excluded") shownExcluded = true;
|
|
9012
|
+
return extSourceCard(x, DS_TYPE[x.type] || { icon: "🔗", label: x.type || "その他" }, { quietHelp: again, quietExcluded: quietExcluded });
|
|
8691
9013
|
});
|
|
8692
9014
|
if (g.state === "warn") {
|
|
8693
9015
|
out.push(orgNoteBox(githubNotConnectedNodes(g), cards));
|
|
@@ -9663,15 +9985,23 @@ ${calendarAddUrl.toString()}
|
|
|
9663
9985
|
/**
|
|
9664
9986
|
* 登録したばかりで、まだ実測の行が1件も届いていない接続先があるか(#523 決定6)。
|
|
9665
9987
|
*
|
|
9666
|
-
* **対象は取り込む4
|
|
9988
|
+
* **対象は取り込む4能力だけ**(実績の問いが 「ingested」 の能力=規則4の文言が
|
|
9667
9989
|
* 「まだ取り込みがありません」の系)。チャット・開発の規則4は既に
|
|
9668
9990
|
* 「接続は未確認です」と言っており、待っていることが読める。
|
|
9669
9991
|
*
|
|
9992
|
+
* 🔴 **判定に 「alsoBad」 の有無を使わない(#640)。** かつては「取り込む4能力は
|
|
9993
|
+
* alsoBad を持つ」という**偶然の一致**を代用していたが、あちらは
|
|
9994
|
+
* 「実績の問いとは別に、悪ければ⚠️にする問い」を並べる欄で、意味が違う。
|
|
9995
|
+
* 開発に 「alsoBad: ["ingested"]」 を足した瞬間、**GitHub を登録した直後15分の
|
|
9996
|
+
* 開発タイルが「登録済み(接続は未確認です)」から「確認しています…」に黙って変わる**
|
|
9997
|
+
* ——今日の 7 能力では 「question === "ingested"」 と同値なので、表示は 1 バイトも
|
|
9998
|
+
* 変わらないまま、意図(規則4の文言の系)をそのまま述語にする。
|
|
9999
|
+
*
|
|
9670
10000
|
* 上限は 「UNSETTLED_TTL_MS」(15分)。過ぎたら中立文に戻る——**待てば出ると言い続けない**。
|
|
9671
10001
|
*/
|
|
9672
10002
|
function capConfirming(derCap) {
|
|
9673
10003
|
var meta = TILE_CAPS[derCap];
|
|
9674
|
-
if (!meta ||
|
|
10004
|
+
if (!meta || meta.question !== "ingested") return false;
|
|
9675
10005
|
var ops = pendingOpsNow();
|
|
9676
10006
|
var now = Date.now();
|
|
9677
10007
|
for (var i = 0; i < ops.length; i++) {
|
|
@@ -10945,7 +11275,8 @@ ${calendarAddUrl.toString()}
|
|
|
10945
11275
|
// **unset を idle に短絡しない(#153)。** 短絡すると gate 異常(読めていない行)の
|
|
10946
11276
|
// warn 判定を一度も通らず、接続マップだけが⚠️になる。アダプタごとの状態の解決
|
|
10947
11277
|
//(adapters[] / 旧データの代表値の扱い)は capabilityState 自身が持つ
|
|
10948
|
-
var
|
|
11278
|
+
var stCtx = stateCtx();
|
|
11279
|
+
var st = capabilityState(cap, stCtx, adapter);
|
|
10949
11280
|
// 🔴 **状態の正本は「登録・実測からの導出」(0.12.0・#231 / #235 / #227)。**
|
|
10950
11281
|
// 設定が済んでいること(capabilities が on)と、実際に動いていることは別。
|
|
10951
11282
|
// 設定だけを見て「● 接続OK」と出すと、**画面が動いていないものを動いていると言う**
|
|
@@ -10966,8 +11297,17 @@ ${calendarAddUrl.toString()}
|
|
|
10966
11297
|
// 残る**——夜間がまだ一度も走っていない案件・ストアが読めなかった回。そこで
|
|
10967
11298
|
// fleet の行から出た warn を導出(規則4=idle)が上書きすると
|
|
10968
11299
|
// 「接続グラフは⚠️・タイルは静か」——この仕組みが殺したはずの食い違いが再発する
|
|
10969
|
-
|
|
10970
|
-
|
|
11300
|
+
//
|
|
11301
|
+
// 🔴 **ただし門が効くのは「ライブの行」から立った warn だけ(#654)。** まとめ表の
|
|
11302
|
+
// pipelines(ワークフローの run の結論)は**ビルド時に焼かれ、ライブで取り直されない**
|
|
11303
|
+
// ——stateCtx が接続状態ストアを重ねるのは externalSources だけなので、一度赤く
|
|
11304
|
+
// なると次のビルドまで赤いまま。そこに門を効かせると、**ストアが「たった今 取り込めた」と
|
|
11305
|
+
// 言っている能力のタイルだけが「⚠️ 同期が失敗しています」**になる(gift-stvv・
|
|
11306
|
+
// 2026-09-17。同じページのモーダルと接続マップは「接続OK」と言っていた)。
|
|
11307
|
+
// 出どころの判定は capabilityWarnSource 1 本——ここに写しを作らない
|
|
11308
|
+
var liveWarn = st === "warn" && capabilityWarnSource(cap, stCtx, adapter) === "live";
|
|
11309
|
+
if (derive && !(liveWarn && derive.state !== "warn")) st = derive.state;
|
|
11310
|
+
else if (derive) derive = null;
|
|
10971
11311
|
// **ロゴはタイルの左に独立して置く。** 名前の行に入れると名前の高さに
|
|
10972
11312
|
// 縛られて小さくなる。ロゴで能力を見分けられるのが一覧の主な用途
|
|
10973
11313
|
var logo = ADAPTER_ICONS[adapter];
|
|
@@ -10999,7 +11339,12 @@ ${calendarAddUrl.toString()}
|
|
|
10999
11339
|
// (意図的に止めた・設定が壊れている)で導出が止まった回にストアの ok で「接続OK」と
|
|
11000
11340
|
// 言うと、表 5 の優先順位(OFF・設定に異常が導出より先)を裏切る(実装レビュー🟡2)
|
|
11001
11341
|
var pendNow = pend && (derived == null || derived === "on" || derived === "unset") ? pendingTileVerdict(cap, adapter) : null;
|
|
11002
|
-
|
|
11342
|
+
// **判定の写しを 2 つにしないため liveWarn に寄せてある(#654)。** ここは
|
|
11343
|
+
// 実際には st === "warn" と等価——pendNow が立つのは derived が unset で導出を
|
|
11344
|
+
// 止めた経路だけで、その経路の warn はライブの行からしか立たない(実装レビュー🟡3)。
|
|
11345
|
+
// **「焼いた pipelines がここを通る」という経路は無い**ので、そう読んで条件を
|
|
11346
|
+
// いじらないこと
|
|
11347
|
+
if (pendNow && liveWarn && pendNow.cls === "ds-gate-ok") pendNow = null;
|
|
11003
11348
|
// 🔴 **初回のライブ確認が答えるまで、状態を断言しない(#256・設計v2 の5)。**
|
|
11004
11349
|
// この2行目は焼いた capabilities 由来の状態を先に言っていたので、図と同じ瞬き
|
|
11005
11350
|
// (旧状態を見せて1〜2秒後に訂正)をタイルでも起こしていた。**兄弟機能の同型の
|
|
@@ -14283,6 +14628,31 @@ ${calendarAddUrl.toString()}
|
|
|
14283
14628
|
title: "このリポジトリは読み取り対象から除外されています(開発の登録ファイル dev-sources.json の exclude)。この画面からは戻せません。",
|
|
14284
14629
|
}));
|
|
14285
14630
|
}
|
|
14631
|
+
// 「接続できる」と「Gold の材料にしている」を別の状態として併記する(#640・engine #399)。
|
|
14632
|
+
//
|
|
14633
|
+
// **常に出す(gate の値で隠さない)。** 届かないことと材料にしていないことは別の事実で、
|
|
14634
|
+
// 片方を隠すと「アクセス不可を直せば読まれる」と誤読させる(#523・オーナー決定
|
|
14635
|
+
// 「操作タブは常に真実を表示する」)。
|
|
14636
|
+
//
|
|
14637
|
+
// 🔴 **「ds-gate」 ではなく 「badge」 で出す。** 行の「判定のバッジは 1 つ」を
|
|
14638
|
+
// 「connection-probe.test.mjs」 が見張っており、「probeSection」 も 「gateEl」 の参照 1 本で
|
|
14639
|
+
// 置き換える設計なので、「.ds-gate」 を 2 つにすると「押した結果がどちらを差し替えたか」が
|
|
14640
|
+
// 構造的に決まらなくなる。**「読み取り停止中」(人が止めた)と同じ棚**に並べるのが正しい
|
|
14641
|
+
// ——どちらも「判定」ではなく「この接続先がいまどう扱われているか」の印。
|
|
14642
|
+
//
|
|
14643
|
+
// 🔴 **警告色にしない。** 直すものが無い中立の事実で、橙にすると直しに行かせる。
|
|
14644
|
+
// 語は短く(長文を入れると行が折り返す)——性質の変え方は下の補足 1 行が持つ
|
|
14645
|
+
// 🔴 **「読み取り停止中」の行には出さない(実装レビュー🟡4)。** 人が exclude で止めた
|
|
14646
|
+
// 行は engine が観測しなくなる= 2 行とも書き直されないので、古い中立の行が永久に残る。
|
|
14647
|
+
// しかも止めてある以上、性質を「会話」にしても読まれない——**効かない一手**を案内する
|
|
14648
|
+
// ことになる。灰色の札が 2 つ並ぶのも「繰り返さない」に反する
|
|
14649
|
+
if (s.ingestExcluded === true && s.goldState !== "excluded") {
|
|
14650
|
+
badges.appendChild(el("span", {
|
|
14651
|
+
class: "badge ds-not-ingested",
|
|
14652
|
+
text: devExcludedLabel(s.ingestExcludedDetail),
|
|
14653
|
+
title: "接続はできています。この登録は Gold(決定・用語・メンバー・ルール)の材料にしていません。",
|
|
14654
|
+
}));
|
|
14655
|
+
}
|
|
14286
14656
|
if (s.notify === true) badges.appendChild(notifyBadge());
|
|
14287
14657
|
// **どのワークスペースのチャンネルかを、必ず行に出す(#104・2026-08-20 に社内も)。**
|
|
14288
14658
|
//
|
|
@@ -14480,6 +14850,28 @@ ${calendarAddUrl.toString()}
|
|
|
14480
14850
|
if (reason) card.appendChild(neededNode(reason, "ds-gate-help ds-gate-reason"));
|
|
14481
14851
|
}
|
|
14482
14852
|
}
|
|
14853
|
+
// 「材料にしていない」の理由と、変えたいときの一手(#640)。**1 行だけ。**
|
|
14854
|
+
//
|
|
14855
|
+
// 🔴 **「ds-gate-help」 を付けない。** あちらは「接続を確認」を押した瞬間に
|
|
14856
|
+
// 「probeSection」 がまとめて隠す札で、押した人がいちばん誤読しやすい瞬間
|
|
14857
|
+
//(「確認したから読まれるようになった」)に、この 1 行だけが消える。
|
|
14858
|
+
// 押しても変わらない事実なので、隠される棚に置かない(幅の扱いは CSS で揃える)。
|
|
14859
|
+
//
|
|
14860
|
+
// 🔴 **その組織のグループで最初の 1 行にだけ出す(「opts.quietExcluded」)。** GitHub の
|
|
14861
|
+
// 既定は「作業物」なので、全行に出すと一覧が案内で埋まる(#356・オーナー却下の原則)。
|
|
14862
|
+
// 同じリポジトリの 2 本目(Discussions)にも出さない(「opts.quietHelp」 と同じ理由)
|
|
14863
|
+
if (s.ingestExcluded === true && s.goldState !== "excluded" && !(opts && (opts.quietHelp || opts.quietExcluded))) {
|
|
14864
|
+
// 🔴 **性質を直書きしない(実装レビュー🟡2)。** すぐ上の札は理由文が名指しした語だけを
|
|
14865
|
+
// 括弧に入れているのに、ここで「作業物」と書くと、engine が名指しを避けた回に
|
|
14866
|
+
// **同じ行が 2 つのことを言う**(札は「読み取りの対象外」・補足は「作業物」)。
|
|
14867
|
+
// 名指しできた回だけ性質を言い、できなかった回は事実だけを言う
|
|
14868
|
+
var exNature = devExcludedLabel(s.ingestExcludedDetail).replace(/^読み取りの対象外(?/, "").replace(/)$/, "");
|
|
14869
|
+
card.appendChild(el("p", {
|
|
14870
|
+
class: "ds-not-ingested-note",
|
|
14871
|
+
text: (exNature ? "この登録は「" + exNature + "」なので、" : "この登録は、")
|
|
14872
|
+
+ "決定・用語・メンバー・ルールの材料にしていません。議論の場として読ませるなら、登録簿で性質を「会話」にしてください",
|
|
14873
|
+
}));
|
|
14874
|
+
}
|
|
14483
14875
|
// 「接続を確認」(2026-08-19)。**押せる人を絞らない**——読むだけで設定を変えないので、
|
|
14484
14876
|
// 気づいた人がその場で確かめられるほうがよい(オーナー判断)。書き込みになる
|
|
14485
14877
|
// 「表示名を更新する」は、押した結果の中から別のボタンとして出る(probeSection)。
|
|
@@ -15637,6 +16029,28 @@ ${calendarAddUrl.toString()}
|
|
|
15637
16029
|
if (capConfigState(cap)) { restoreBakedConnMap(cap); continue; }
|
|
15638
16030
|
var d = capDerivation(cap);
|
|
15639
16031
|
if (!d) { restoreBakedConnMap(cap); continue; } // 規則5: 材料が無い → 焼いた図のまま
|
|
16032
|
+
// 🔴 **図にもタイルと同じ門を効かせる(#654 実装レビュー🔴1)。** ライブの行から
|
|
16033
|
+
// 立った warn(ストアがまだ測っていない接続先の gate)は導出が降格しない
|
|
16034
|
+
//(#153)。タイルだけが門を持っていると「タイルは⚠️・図は無言」——R10 が
|
|
16035
|
+
// 殺したはずの食い違いの鏡像になる。門の材料はタイルと同じ 1 本
|
|
16036
|
+
//(capabilityWarnSource)で、焼いた pipelines の赤はここでも効かない
|
|
16037
|
+
var mapCtx = stateCtx();
|
|
16038
|
+
var mapLiveWarn = capabilityState(cap, mapCtx) === "warn" &&
|
|
16039
|
+
capabilityWarnSource(cap, mapCtx) === "live" && d.state !== "warn";
|
|
16040
|
+
if (mapLiveWarn) {
|
|
16041
|
+
// 焼いた表示(3行目の語)へ戻してから、状態だけ warn に固定する
|
|
16042
|
+
// ——図は幅が 148px しかなく、行と同じ語はタイルが持つ
|
|
16043
|
+
restoreBakedConnMap(cap);
|
|
16044
|
+
var wNode = wrap.querySelector('[data-target="ds-' + cap + '"]');
|
|
16045
|
+
if (wNode) {
|
|
16046
|
+
wNode.setAttribute("class", "cm-node cm-warn");
|
|
16047
|
+
var wBadge = wNode.querySelector(".cm-badge");
|
|
16048
|
+
if (wBadge) wBadge.setAttribute("class", "cm-badge");
|
|
16049
|
+
}
|
|
16050
|
+
var wLink = wrap.querySelector('.cm-link[data-cm-cap="' + cap + '"]');
|
|
16051
|
+
if (wLink) wLink.setAttribute("class", "cm-link cm-warn");
|
|
16052
|
+
continue;
|
|
16053
|
+
}
|
|
15640
16054
|
var node = wrap.querySelector('[data-target="ds-' + cap + '"]');
|
|
15641
16055
|
if (!node) continue;
|
|
15642
16056
|
node.setAttribute("class", "cm-node cm-" + d.state);
|
|
@@ -15656,6 +16070,11 @@ ${calendarAddUrl.toString()}
|
|
|
15656
16070
|
link.setAttribute("class", "cm-link cm-" + d.state
|
|
15657
16071
|
+ (d.state === "ok" || d.state === "warn" ? "" : " is-hidden"));
|
|
15658
16072
|
}
|
|
16073
|
+
// 🔴 **⚠️バッジも当て直す(#654)。** 当て直さないと、ビルド時に赤かった能力は
|
|
16074
|
+
// ライブで接続OKに直っても⚠️を出し続ける(「緑のノードに⚠️」)。線と同じ形で
|
|
16075
|
+
// 常時焼いてあるので、ここは表示の切り替えだけ
|
|
16076
|
+
var badge = node.querySelector(".cm-badge");
|
|
16077
|
+
if (badge) badge.setAttribute("class", "cm-badge" + (d.state === "warn" ? "" : " is-hidden"));
|
|
15659
16078
|
// 確定したので退避は要らない(設計v3)。**残すと、あとの取得が失敗したときに
|
|
15660
16079
|
// 確定済みの表示へ焼いた値が上書きされる**——訂正した嘘が戻ってくる
|
|
15661
16080
|
forgetBakedConnMap(node, link);
|
|
@@ -15678,11 +16097,10 @@ ${calendarAddUrl.toString()}
|
|
|
15678
16097
|
* derived が null / "on")。OFF・異常・未設置の語は設定そのものの話で、ライブが
|
|
15679
16098
|
* 届いても変わらない——確認中にしたら、応答が来ても戻す相手がいなくなる。
|
|
15680
16099
|
*
|
|
15681
|
-
* ⚠ **⚠️バッジ(cm-badge)は触らない。**
|
|
15682
|
-
*
|
|
15683
|
-
*
|
|
15684
|
-
*
|
|
15685
|
-
* 6ノードに常時バッジを焼いて表示を切り替える形(線と同じ)にする別便が要る。
|
|
16100
|
+
* ⚠ **⚠️バッジ(cm-badge)は触らない。** 確認中の間だけ隠すと、応答で warn が
|
|
16101
|
+
* 確定したときに**失敗が図から消えたまま**になる——「cm-warn を隠さない」の逆を
|
|
16102
|
+
* こちらの都合で作る。**応答が届いたあとは applyStateToConnMap が当て直す**
|
|
16103
|
+
* (#654 でバッジを 6 ノードに常時焼き、線と同じ「表示の切り替え」にした)。
|
|
15686
16104
|
*/
|
|
15687
16105
|
function showConfirmingConnMap() {
|
|
15688
16106
|
var wrap = app.querySelector(".conn-map");
|
package/package.json
CHANGED