記事の文章から拾おうとして、31 本のうち 22 本で何も取れなかった
何をしようとしたか
giga-school.com の紹介記事は 31 本あります。そのうち 29 本が、校内のフィルタリングの話を 書いていました。「このアドレスを許可してください」という案内です。
ただし、それぞれの記事の中だけでした。一覧はどこにもありません。
先生が情報担当に申請を出すには、38 本の記事を開いて拾い集めることになります。しかも アプリごとに要るものが違う。書体だけのもの、Google のログインが要るもの、端末どうしを つなぐもの。集め落とすと、許可は通ったのにアプリが開かない、という形になります。
これを 1 枚にまとめ、印刷して情報担当に渡せる形にしたいと思いました。 作りはじめる前に数えたところ、フィルタリングに触れている記事は 29 本。 一覧のあるページは 0 枚でした。
出したプロンプト
材料はもう記事の中にあると思っていたので、はじめはこう出しました。リポジトリを 読ませたあとです。
31 本の紹介記事から、フィルタリングで許可が要るアドレスを拾って、
アプリごとの一覧ページを作って。
これで作ったものは使えませんでした。理由は次の節に書きます。
作り直すときに出したのがこれです。
記事の文章からは拾わないで。アプリが実際に読み込んでいるものを見て。
配られるファイルの中の script src、link rel=stylesheet、img の src、
CSS の url()、fetch、それから CSP の宣言も見る。
これは効きました。書いてあることではなく、動いているものを見る。今回いちばん 再利用できる言い回しはここだと思います。
もうひとつ、途中で足したのがこれです。
a href は数えないで。遷移であってブラウザは取りに行かない。
og:image と canonical も、SNS のクローラ向けなので数えない。
数え方の線引きは、頼まなければ勝手には引かれません。何を数えないかを言うほうが、 何を数えるかを言うより効きました。
効かなかったものも書いておきます。途中でこう出しています。
アプリごとに、フィルタリングで許可が要るアドレスを調べて一覧にして。
これだと調べ方が指定されていないので、また記事の文章を読みに行きました。 「調べて」は、どこを見るかを決めていない頼み方です。見る場所を先に決めて渡すと、 同じ作業でも結果が変わりました。
もうひとつ、最後に出したのがこれです。
一覧はページに直接書かないで。data/apps.json から組み立てて、
ずれていたら検査で落ちるようにして。
手で書いた一覧はアプリが増えたときに古くなります。データから組み立てておくと、 書き忘れが検査で止まります。
うまくいかなかったこと
最初のプロンプトで作った一覧は、31 本のうち 22 本から何も取れていませんでした。 拾えたのは 9 本だけです。
kana-master fonts.googleapis.com, fonts.gstatic.com, gigayama.github.io
keisan-block keisan-block.giga-school.com
qalc 0.peerjs.com, stun.l.google.com, us-0.turn.peerjs.com
(残り 22 本は空)
記事の書き方は本ごとに違います。文章から拾う方法では取りこぼす。しかも記事は 毎朝アプリ側の Markdown から組み直されるので、言い回しが変わると翌日から中身がずれます。 拾えたはずのものが黙って消える。これがいちばん困る壊れ方でした。
そこで、配信されるファイルを直接読む方法に変えました。ここで 2 回外しました。
ひとつめ。ファイル名をホスト名として数えていました。
jidosha-zukan app.js, car-art.js, car3d.css, cars-data.js, index.css,
kansatsu.js, kansatsu3d.js, parts-data.js, ...
app.js が [a-z0-9.-]+\.[a-z]{2,} を満たしてしまいます。拡張子を除く条件を足して直しました。
ふたつめが今回いちばんの見落としです。道徳ノートの一覧に www.google.com が出てきました。 おかしいと思って中を見ると、これでした。
UrlFetchApp.fetch("https://www.google.com");
Google Apps Script の疎通確認でした。このコードが動くのは Google のサーバーの中です。 教室の端末からは出て行かないので、校内のフィルタリングには関係しません。これを載せると、 先生に要らないアドレスまで申請させることになります。.gs を走査の対象から外しました。
逆に足りなかったものもあります。まなびクエストは Google Apps Script で動いていますが、 script.google.com が出てきませんでした。iframe の行き先を実行時に決めているので、 配られるファイルの中に文字列として存在しません。走査だけでは足りず、CSP の宣言も 見ることにしました。それでも出ないアプリが 1 本残ったので、そこは手で足しています。
新しく知ったこと
書いてあることと、動いていることは別物でした。29 本の記事が親切に書いていたので、 そこから拾えば済むと思い込みます。実際には 22 本で何も取れず、しかも拾えた 9 本も 記事の言い回し次第で明日には変わる。
一次情報がどこにあるかを先に決める。今回なら、配られるファイルと CSP です。
証拠は 2 つ以上そろえないと片方に落ちます。走査だけだと GAS のアプリが抜け、 CSP だけだと実行時に組み立てる通信が抜けた。どちらか片方で足りると思ったのが 間違いで、両方見てはじめて全部そろいます。
「サーバー側で動く」と「端末から出て行く」は違う。UrlFetchApp で 1 回外しています。 外部への通信を数えるときは、誰の環境から出て行くのかを毎回確かめる必要があります。 学校のフィルタリングに関係するのは、端末から出て行くものだけです。
数える対象を決めるときは、何を数えないかを先に言うほうが早く決まりました。 a href を数えない、og:image を数えない、.gs を見ない。数える側の条件は いくらでも広げられますが、除く側の条件は理由とセットでしか書けません。 理由が言えないものは、そもそも境界が決まっていないということでした。
もうひとつ、生成した一覧を手で確かめる方法も変わりました。38 本を目で見ても、 足りないものには気づけません。載っているものが正しいかは見て分かりますが、 載っていないものは画面に出ないからです。データから組み立てて検査で突き合わせる 形にしたのは、この見えなさへの対処でもありました。
できあがったもの
38 本ぶんの一覧ができました。外部が一切要らないアプリが 5 本、いちばん多いのは書体で 30 本、ただしこれは塞いでも動きます。アドレスの種類は 23 でした。
検査を 5 つ足しています。とくに「説明の書かれていないアドレスが無い」は、知らない アドレスを黙って一覧に載せないためのものです。アドレスが増えたのに説明を書き忘れると、 先生は用途の分からない申請を出すことになります。
横に流れる表には tabindex="0" と role="region" を付けました。付けないと キーボードだけで使う人が表の中を動かせません。これは axe が止めてくれています。
次に同じことをする人へ
- 文章から拾う仕組みは作らない。書き方が変わると黙って壊れる
- 外部への通信を数えるときは、サーバー側で動くものを外す。GAS の
UrlFetchAppが典型 - 走査と宣言(CSP)の両方を見る。片方では必ず落ちる
- ファイル名がホスト名の形に当たる。
app.jsは[a-z0-9.-]+\.[a-z]{2,}を満たす - 一覧を人手で書かない。データから組み立てて、ずれを検査で止める
- 「調べて」と頼まない。どこを見るかを先に決めて渡す
- 横に流れる表には
tabindex="0"を付ける。無いとキーボードで中を動かせない
いちばん効いたのは、記事を読むのをやめて配信物を読むことに切り替えた一手です。 遠回りに見えて、結果としては早く終わりました。
この記事のもとになった変更は GIGAyama.github.io #78 です。