記事の文章から拾おうとして、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 が止めてくれています。

次に同じことをする人へ

いちばん効いたのは、記事を読むのをやめて配信物を読むことに切り替えた一手です。 遠回りに見えて、結果としては早く終わりました。

この記事のもとになった変更は GIGAyama.github.io #78 です。

アプリの一覧を見る ほかの開発記録