このコミットが含まれているのは:
+45
-8
@@ -35,7 +35,9 @@ Web とワーカーは同一リリース、Rails secret、アプリケーショ
|
||||
- POST `/counts/export/jobs`:要求検証・実行時点の固定・署名付きジョブトークンの発行。
|
||||
- GET `/counts/export/jobs/:token`:状態、実際の処理済みレコード数、判明している総数。
|
||||
- DELETE `/counts/export/jobs/:token`:取消を永続記録。
|
||||
- GET `/counts/export/files/:token`:生成完了後の署名付きファイルトークンによる取得。
|
||||
- POST `/counts/export/jobs/:token/download`:セッション所有者の開始確認要求を登録。
|
||||
- GET `/counts/export/files/:token?job=...&attempt=...`:実 GET の認可・送出開始の確認。
|
||||
- GET `/counts/export/files/:token`:既存クライアント向けの認可付きダウンロード。
|
||||
|
||||
ジョブ・ファイルのトークンは作成元のセッションに紐付く。
|
||||
既存の BAN・CSRF 制御を使用する。フロントは約800ms間隔で状態を取得する。
|
||||
@@ -80,16 +82,22 @@ processed は CSV では実際に生成したデータ行数、JSON のクロス
|
||||
|
||||
通常の Counts 応答では、使用していない全履歴の population_count は計算しない。
|
||||
キーは null、population_count_computed は false とし、0に置き換えない。
|
||||
現在条件の output_count は権限適用前、visible_output_count は権限適用後の
|
||||
通常の集計行数(明細では明細行数)。小計・合計の物理行は含めない。
|
||||
summary は非公開履歴を含む同じ母集団を集計する。非公開の軸はサーバーの CASE 式で
|
||||
単一の予約値へまとめてから GROUP BY し、output_count / visible_output_count はその
|
||||
安全化した通常行数を表す。excluded_count は返さない。details は従来どおり
|
||||
output_count が権限適用前、visible_output_count が適用後の明細行数である。
|
||||
小計・合計の物理行は行数に含めない。
|
||||
CSV の物理行と JSON の pivot_cell には集計レコードを含むため、両者を混同しない。
|
||||
|
||||
除票境界・参照禁止集合は GROUP BY で識別キー単位にまとめる。
|
||||
投稿の参照判定は、全除票履歴を JSON_CONTAINS / FIND_IN_SET で反復照合せず、
|
||||
保存済みスナップショットから参照IDを JSON_TABLE で展開して照合する。
|
||||
権限条件付きの母集団件数は同一 export インスタンス内で再利用する。
|
||||
多段小計は、認可済み母集団の CTE を MySQL の無制限 LIMIT で実体化させ、
|
||||
各枝が同じ認可判定をやり直すことを避ける。計数は COUNT(DISTINCT v.id) のまま。
|
||||
多段小計は、全軸の JOIN へ実際に寄与するレコードを CTE に保持し、各枝で同じ
|
||||
母集合を使う。changed_field には直前版がある実変更だけが寄与する。タグが行軸に
|
||||
ない場合は DISTINCT 投稿版を数える。タグが行軸にある場合は投稿版×タグを数え、
|
||||
全行軸の葉単位から小計・合計を求める。変更項目も行軸ならその寄与も保持する。
|
||||
private のタグ・変更項目をまとめても、内部の寄与は捨てず、ラベルだけを保護する。
|
||||
|
||||
スキーマ上、以下の追加インデックスが候補となる。migration は作成・実行していない。
|
||||
|
||||
@@ -122,6 +130,35 @@ systemd の EnvironmentFile と Web の環境を照合し、directory の owner
|
||||
アクセス制限、容量、期限切れ削除、worker heartbeat と restart を公開前に確認する。
|
||||
この作業では systemctl・worker 起動・本番環境への適用を行っていない。
|
||||
|
||||
リリース保留:非公開グループと複数値・変更項目軸の交差集計、生成ファイルへの秘匿値の
|
||||
非混入、実 GET の middleware/proxy 経由の開始通知は、回帰テストと実環境の確認が必要。
|
||||
テスト・型チェック・build は未実行。
|
||||
これらのコード対策と回帰テストを追加しているが、テスト・型チェック・build は未実行。
|
||||
middleware/proxy 経由の転送は別途実環境で確認する。
|
||||
|
||||
|
||||
## 開始確認の競合と権限
|
||||
|
||||
開始受付は pending、実 GET の単独取得は streaming、最初の Rack yield 後は started。
|
||||
同じ job の重複受付は既存 attempt を返す。streaming への遷移はプロセス間ロックで
|
||||
単独取得し、同一 attempt の二重 GET を拒否する。開始前の attempt は45秒で失効する。
|
||||
Frontend は30秒の独立タイマーで確認を打ち切る。一時的なポーリング通信断は同じ
|
||||
attempt で再取得するが、別の GET は始めない。取消失敗後の再試行は利用者の再操作で行う。
|
||||
|
||||
ファイル・ジョブは owner、署名、期限、現在の権限 revision 及び artifact_policy を
|
||||
検証する。最初の送出前にも現ユーザー・BAN・ファイル権限を再確認する。旧ポリシーの
|
||||
生成物は再利用しない。送出中は各チャンクで取消状態を確認し、例外時はログと failed
|
||||
状態を記録して body を閉じる。コミット後に head で別レスポンスを書かない。
|
||||
|
||||
ResponseBody に to_path を提供せず、sendfile middleware による ACK の迂回を避ける。
|
||||
Last-Modified と X-Accel-Buffering: no を設定するが、プロキシの動作まで保証しない。
|
||||
サーバーの最初の Rack yield は、クライアントの受信開始の厳密な証明ではない。
|
||||
|
||||
非管理者の summary では、公開集計属性は操作日時・異動区分。その他の属性に対する
|
||||
抽出条件・補助タグ検索は拒否する。measures / column_order はマスク後の式だけと
|
||||
比較するため、推測した private ID は一致しない。予約値そのものの条件指定は拒否する。
|
||||
private ID の正誤に応じて許可可否を変えないため、条件の一致探索を避けられる。
|
||||
非公開列を含む列順変更は API の column_values_editable でも不可と通知する。
|
||||
公開列の値を使うソートは引き続き利用できる。
|
||||
明細には元の認可を適用し、抽出条件自体や取得済みの全言語値を表示設定で改変しない。
|
||||
外部タグ履歴の linked_tags は名前しか記録していないため、非公開タグの記録名を含む
|
||||
スナップショットを保守的に非公開とする。名前全体を空白区切りの境界で照合する。
|
||||
区切りが曖昧な旧データでは過剰な秘匿の可能性はあるが、参照 ID がない旧形式から
|
||||
名前の公開可否を楽観的に推定しない。
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
# Counts リリース前確認
|
||||
|
||||
この作業では Git、テスト、lint、typecheck、build、migration、サーバー・worker・
|
||||
systemd の起動、本番適用を行っていない。コードの静的確認とテストコードの編集のみ。
|
||||
以下の実行と結果確認は利用者が行う。未実行の状態は GO としない。
|
||||
|
||||
## 対応箇所
|
||||
|
||||
- 全件集計と安全な軸:counts_axes.rb / counts_table_query.rb / counts_pivot_totals.rb。
|
||||
非公開値は GROUP BY 前に統合。通常セル・ソート用集計・小計は同じ寄与母集合を使う。
|
||||
- 出力:counts_table_export.rb / countsDisplay.ts / CountsSummaryResults.tsx。
|
||||
CSV とコピーは伏字。JSON の非公開座標は予約値のみ。非公開セルはリンクを作らない。
|
||||
- 配布:counts_exports_controller.rb / counts_export_jobs.rb / counts_export_download.rb。
|
||||
owner/job/attempt、単独 GET、期限・現在権限・旧 artifact policy の拒否を確認する。
|
||||
- 表示:summary 行番号を廃止し「行数」を表示。details の行番号・件数は維持。
|
||||
非公開列座標のソート・並び替え可否はサーバーの能力フラグへ従う。
|
||||
- テスト基盤:requestAnimationFrame の同期・時刻0固定を修正。JSDOM の Canvas は
|
||||
計測非対応を返すテスト専用モックを置く。実ブラウザーの計測動作は変更していない。
|
||||
|
||||
## 利用者によるテスト
|
||||
|
||||
backend ディレクトリで提案する対象(未実行):
|
||||
|
||||
```sh
|
||||
bundle exec rspec spec/requests/counts_table_spec.rb spec/requests/counts_download_spec.rb spec/services/counts_pivot_security_spec.rb spec/services/counts_export_spec.rb spec/models/history_access_spec.rb spec/requests/post_locale_filter_identity_spec.rb spec/requests/tag_description_wiki_spec.rb
|
||||
```
|
||||
|
||||
frontend ディレクトリで提案する対象(未実行):
|
||||
|
||||
```sh
|
||||
npm run test:run -- src/lib/counts.test.ts src/lib/api.test.ts src/pages/CountsResourcePage.test.tsx src/pages/help/HelpChangesPage.test.tsx src/components/counts/CountsControls.test.tsx src/components/counts/CountsSummaryResults.test.tsx src/components/counts/CountsExportProgress.test.tsx
|
||||
```
|
||||
|
||||
SSR は frontend/server.ssr.test.mjs が dist/server/entry-server.js を読み込む。
|
||||
ソースの PageHead はサイト名付きの共通タイトルを使用している。古い成果物のまま
|
||||
SSR テストを実行しても現行ソースの検証にならない。利用者が最新成果物を用意してから
|
||||
`npm run test:ssr` を実行する。Codex はビルド・SSR テストとも実行していない。
|
||||
主要テストの後に既存の全テスト群でも回帰の有無を確認する。
|
||||
|
||||
## ブラウザーと本番切替前
|
||||
|
||||
- anonymous / guest / member / admin で同じ期間・公開条件を指定し、通常セル・総計の
|
||||
数値を比較する。安全なグループ数は権限で異なり得る。details は秘匿版を出さない。
|
||||
- 投稿 A,B / A / B,C のタグ行軸は5。タグを行軸から外した合計は distinct 投稿数。
|
||||
changed_field、NULL、複数段小計、ページ境界、CSV / JSON でも値を比較する。
|
||||
- 伏字セル、API 辞書、DOM、コピー、CSV / JSON に非公開の値・ID がないこと。
|
||||
非公開セルのドリルダウンはなく、private 条件の summary は安全な403となること。
|
||||
- 8軸・100列の専用エラー、SQL timeout、worker 不在、認証・権限、取消失敗を確認する。
|
||||
- CSV / JSON とも ready / 100% だけでは閉じず、実 GET の matching attempt が
|
||||
started となってから閉じること。通信遮断・取消・再描画・タイムアウトも確認する。
|
||||
サーバー送出開始はブラウザーの受信完了・保存完了を保証しない。
|
||||
- PC・スマホで独立/共通スクロール、D&D、列幅、セル選択・文字列選択・キャレット、
|
||||
内表 JSON の折返し、ページタイトル、Counts の noindex・先読み禁止を確認する。
|
||||
locale 切替後も対象 ID と集計値は同一で、全言語の登録値を保持すること。
|
||||
- Web と worker の同一リリース・secret・DB・COUNTS_EXPORT_DIRECTORY、所有者、
|
||||
flock / atomic rename、容量、期限切れ掃除、heartbeat、ログ、再起動を照合する。
|
||||
- systemd unit の User / WorkingDirectory / EnvironmentFile / PATH を実環境と照合する。
|
||||
設定適用・サービス起動・本番切替はこの作業では行っていない。
|
||||
- ロール変更・logout・新しい discard 後に、生成済みファイルが再取得できないこと。
|
||||
- ロールバック時も公開ダウンロードを止め、旧生成物を再配布しない。古いコードへ戻すと
|
||||
artifact_policy やマスクの保護を失う可能性があるため、無条件に巻き戻さない。
|
||||
|
||||
P0 の回帰テストと利用者の動作確認が済むまで判定は NO-GO。
|
||||
|
||||
## 静的な対応状況
|
||||
|
||||
| 対象 | 状態 | 根拠 |
|
||||
| --- | --- | --- |
|
||||
| 非公開軸・参照・全件母集団 | 対応済み(静的確認のみ) | HistoryAccess / CountsAxes / CountsTableQuery と回帰コード |
|
||||
| タグ・変更項目・小計 | 対応済み(静的確認のみ) | CountsPivotTotals と全セル・ソートの母集合の統一 |
|
||||
| API / CSV / JSON / コピー / URL | 対応済み(静的確認のみ) | マスク後の値のみを表示・比較し、予約座標の条件化を拒否 |
|
||||
| GET ACK・競合・取消・期限 | 対応済み(静的確認のみ) | サーバー状態遷移、単独 GET、独立タイマー、回帰コード |
|
||||
| P1・既知テストのソース上の問題 | 対応済み(静的確認のみ) | 行番号、行数、エラー、RAF、fixture、title 契約 |
|
||||
| テスト成功・実ブラウザー・本番稼働 | 判定不能 | 実行禁止のため未検証 |
|
||||
|
||||
## 今回の編集ファイル
|
||||
|
||||
すべて Counts 本体に必要な変更。共有箇所の例外は HistoryAccess の参照秘匿と、
|
||||
api.ts の Abort/CSRF 待機・native download の機構であり、全域の安全性にも必要。
|
||||
SQL の速度改善・索引追加は別 Issue とし、今回 migration は追加していない。
|
||||
|
||||
### Backend App
|
||||
|
||||
- backend/app/models/history_access.rb:外部タグの記録名参照と、投稿の記録済み参照版にも
|
||||
同じ可視性判定を適用。旧 artifact policy の生成物を拒否。
|
||||
- backend/app/services/counts_population.rb:軸条件の型・予約値の検証。
|
||||
- backend/app/services/counts_axes.rb:マスク前の内部寄与を計数し、直前版が非公開の場合も
|
||||
changed_field の名前を秘匿。
|
||||
- backend/app/services/counts_table_query.rb:通常セル・ソートの寄与母集合、整数順、
|
||||
条件表示名、公開列座標だけの操作、summary メタデータを整合。
|
||||
- backend/app/services/counts_pivot_totals.rb:全セルに寄与する母集合と、タグ行軸の加算。
|
||||
- backend/app/services/counts_table_export.rb:CSV の予約値を伏字化。
|
||||
- backend/app/services/counts_export_jobs.rb:開始確認の排他・状態遷移・失効と安全なエラーコード。
|
||||
- backend/app/services/counts_export_download.rb:64KiB の Rack body、開始確認、取消・close。
|
||||
- backend/app/controllers/counts_exports_controller.rb:GET 直前・送出直前の再認可と専用エラー。
|
||||
|
||||
### Frontend App
|
||||
|
||||
- frontend/src/lib/api.ts:CSRF 待機中も中断可能にし、iframe の寿命・失敗通知を整理。
|
||||
- frontend/src/lib/counts.ts:マスク予約値と列操作の API 型。
|
||||
- frontend/src/lib/countsDisplay.ts:マスク表示と既知エラーの i18n 解決。
|
||||
- frontend/src/components/counts/CountsExportProgress.tsx:一つのジョブを維持し、matching ACK、
|
||||
独立期限、取消・再描画・通信断を処理。保存完了の成功表示はしない。
|
||||
- frontend/src/components/counts/CountsSummaryResults.tsx:行番号コードの撤去、私的セルの
|
||||
ドリルダウン抑止、公開列のソート維持。
|
||||
- frontend/src/components/counts/CountsSortHeader.tsx:禁止座標のソート抑止と伏字の理由表示。
|
||||
- frontend/src/pages/CountsResourcePage.tsx:専用エラーと、初回失敗後にも再実行できる状態。
|
||||
- frontend/src/locales/ja/counts.json:承認されたエラー文言。
|
||||
- frontend/src/locales/ain-Kana/counts.json:同じキーと未翻訳・日本語 fallback の管理。
|
||||
|
||||
### テスト・テスト専用基盤
|
||||
|
||||
- backend/spec/services/counts_pivot_security_spec.rb(新規):4権限、タグ寄与5、distinct、
|
||||
changed_field、private group、NULL、整数順、ページ、座標探索、JSON/CSV。
|
||||
- backend/spec/requests/counts_download_spec.rb(新規):CSV/JSON の実 GET、HEAD、二重取得、
|
||||
別セッション、失効、取消、ファイル不在、新しい discard。
|
||||
- backend/spec/services/counts_export_spec.rb:owner/job/attempt の ACK と Rack body の失敗。
|
||||
- backend/spec/models/history_access_spec.rb:旧 policy、外部タグ参照、記録済みタグ参照版。
|
||||
- backend/spec/requests/counts_table_spec.rb:専用軸数エラー。
|
||||
- frontend/src/components/counts/CountsExportProgress.test.tsx(新規):matching ACK、StrictMode、
|
||||
再描画、開始受付失敗、通信断、独立期限、取消の競合・再試行、unmount、iframe 失敗。
|
||||
- frontend/src/components/counts/CountsSummaryResults.test.tsx(新規):伏字・理由・コピー・旧行番号。
|
||||
- frontend/src/components/counts/CountsControls.test.tsx:summary 行番号廃止と表示件数選択。
|
||||
- frontend/src/pages/CountsResourcePage.test.tsx:初期エラーからの再実行、サイト名付き title。
|
||||
- frontend/src/lib/api.test.ts:共有 CSRF 待機中の中断、iframe の解放・重複失敗通知。
|
||||
- frontend/src/lib/counts.test.ts:理由別エラーと任意のサーバー文字列を表示しないこと。
|
||||
- frontend/src/test/setup.ts:時刻が進む非同期 RAF と Canvas のテスト専用 fallback。
|
||||
- frontend/server.ssr.test.mjs:共通 title の既存 assertion を維持し canonical と秘匿を補足。
|
||||
|
||||
### 文書
|
||||
|
||||
- docs/counts-exports.md:実装と一致する計数・ACK・権限・運用上の限界。
|
||||
- docs/counts-release-checklist.md:この一覧と利用者の検証・公開判定手順。
|
||||
|
||||
## 既知失敗の静的な確認結果
|
||||
|
||||
- counts_table_spec.rb:TagVersion.names の auto_generated、script_code、aliases があることを
|
||||
確認。新しい投稿タグ fixture にも schema 必須の sections を設定。
|
||||
- post_locale_filter_identity_spec.rb:検索文字列で基準集合を取得した後、tag_filters の
|
||||
応答から references を定義して構造化 URL を作る修正を維持。
|
||||
- tag_description_wiki_spec.rb:first / last とも対象 ID に限定した delete_all を維持。
|
||||
- CountsResourcePage.test.tsx / HelpChangesPage.test.tsx:共有 RAF の同期・時刻0固定を修正。
|
||||
Help の辞書応答は実 getHelpChanges が language を付ける契約も照合済み。
|
||||
- SSR title:現行ソースはサイト名を含む。dist を使うテストの assertion は削除していない。
|
||||
|
||||
上記はソース照合の結果であり、過去の失敗件数が0になったという実行結果ではない。
|
||||
既知の未修正 P0 を残して GO とする判断はしていない。現時点の阻害事項は、ユーザーに
|
||||
よる MySQL・ブラウザー・worker/proxy を含む実検証がまだ行われていないことである。
|
||||
新しいイシューから参照
ユーザーをブロックする