CodexでAstro改修をLunaとAstraに任せて比較―小さな改修に高性能モデルは必要なのか?

CodexのGPT-5.6 LunaとGPT-6 Astraへ実際のAstro改修を任せ、TOP、404、リンク切れ検出、画像最適化で時間・差分・検証範囲・利用枠を比較。4回目はAstraを思考量「軽」まで下げましたが、5時間枠を使い切り比較タスクを完走できませんでした。

執筆:ゆまラボ運営者

公開:更新:
CodexでAstro改修をLunaとAstraに任せて比較―小さな改修に高性能モデルは必要なのか?

Codexでモデルを切り替えられるようになると、どこから高性能モデルを使うべきかが気になる。

大きなリファクタリングなら高性能モデルを選ぶ理由は分かりやすい。一方で、実際の開発では数ファイルだけを触る小さな改修も多い。そのたびに上位モデルを使う必要があるのかは、ベンチマークだけでは判断しにくい。

そこで、ゆまラボのAstroプロジェクトに実際に必要になった改修を、CodexのGPT-5.6 LunaとGPT-6 Astraへ任せて記録している。初回と2回目はモデル以外の条件をそろえ、3回目ではAstraの思考量を意図的に下げた。

比較したのは回答文のうまさではない。

  • 実装が終わるまでの時間
  • 実際に実行したコマンド
  • 調査や検証の手順
  • 変更したファイルと差分
  • ビルド失敗ややり直し
  • 最終的な画面とHTML
  • CodexとWorkで共有している5時間・週間利用枠の変化

を記録した。

初回はTOPページの「新着記事」を「新着・更新記事」へ変更し、2回目はカスタム404ページを作った。3回目は、記事やページから存在しない内部URLへリンクしている場合に、npm run buildで検出して失敗させる処理を追加した。

この記事は継続更新する。今後も、ゆまラボで実際に行う改修で比較を追加していく予定だ。

更新履歴#

  • 2026年9月12日:検証4。本文画像の最適化を追加。Astraは思考量「軽」で実行したが5時間枠を使い切り、比較タスクを完走できず
  • 2026年9月11日:検証3。内部リンク切れ検出を追加。Astraは思考量を「中」まで下げて実行
  • 2026年9月10日:検証2。カスタム404ページ作成の比較を追加
  • 2026年9月9日:初版。TOPページの「新着・更新記事」対応でLunaとAstraを比較

最初の検証はTOPページの小さな改修#

ゆまラボでは、公開済みの記事へ大きな追記をした場合にupdatedAtを更新している。

ただ、TOPページの記事一覧は公開日の新しい順で表示していた。継続更新する記事を増やすなら、更新した古い記事もTOPへ戻したい。

今回Codexへ渡した要件は次の3点。

  1. TOPの「新着記事」を「新着・更新記事」へ変更する
  2. TOPだけ、updatedAt ?? pubDateを基準に新しい順で表示する
  3. 更新記事では「更新日」と「公開日」を分けて表示する

/blog/の記事一覧、カテゴリ、サブカテゴリ、タグ、シリーズなど、TOP以外の並び順は変更しない条件も付けた。

依頼時はupdatedDate ?? pubDateという表現を使っていたが、実際のContent Schemaを確認すると、このプロジェクトでは更新日にupdatedAtを使っている。LunaもAstraも既存スキーマを確認し、実装ではupdatedAt ?? pubDateを使っている。

概念としては次の処理になる。

const latestDate = post.data.updatedAt ?? post.data.pubDate;

今回の作業は、要件が明確で、対象もTOP周辺に限定されている。最初の比較対象として扱いやすい規模だ。

同じBASE_COMMITから別ブランチを作った#

モデル比較では、一方がもう一方の実装を引き継ぐ状態を避けた。

開始時のGit状態はclean。BASE_COMMITは次のコミットで固定した。

7cbc718d20173c20ff2a62314f478aa59b1d0403

Luna用とAstra用に別ブランチを作った。

experiment/top-latest-updated-luna
experiment/top-latest-updated-astra

Luna側を完了してcommitした後、AstraはLunaブランチを引き継がず、同じBASE_COMMITから開始している。

モデルの切り替えだけはCodex側に任せず、手動で行った。

CodexでGPT-5.6 Lunaを選択した画面

Luna側の実装が終わった後、GPT-6 Astraへ切り替えた。

CodexでGPT-6 Astraを選択した画面

モデル選択画面では、どちらも「極高」の表示になっている状態で実行した。

ただし、この比較は完全なブラインドテストではない。

Astra開始時にLunaのdiffや保存済み比較ファイルを新しく読ませない条件にはしたが、同じCodexの会話にはLuna作業時の履歴が残っている。またnode_modulesやビルドキャッシュも同じローカル環境を使っている。

同じコードと同じ依頼から独立実装している。ただし、研究用途の厳密なベンチマークではなく、普段のCodex利用に近い実測として扱う。

利用枠は開始前後の画面を保存した#

Codexから5時間・週間利用枠の数値を直接ログへ取得することはできなかった。そのため、モデルを動かす前後に「CodexとWorkのアナリティクス」を開いて画面を保存した。

Luna開始前の表示は、5時間枠が99%残り、週間利用上限が86%残り。

Luna開始前のCodexとWork利用枠。5時間99%残り、週間86%残り

Luna終了後は、5時間枠が98%残り、週間は86%残りのまま。ここをそのままAstra開始前の基準にした。

Luna終了後かつAstra開始前の利用枠。5時間98%残り、週間86%残り

この時点までの表示差は単純だ。

横にスクロールできます
モデル5時間枠 開始5時間枠 終了週間枠 開始週間枠 終了
GPT-5.6 Luna99%残り98%残り86%残り86%残り
GPT-6 Astra98%残り後述86%残り後述

ここで使っている「1%」「98%」は、トークン数や料金を表しているわけではない。管理画面に表示される残量の整数値だ。

OpenAIの公式案内でも、WorkとCodexは利用枠を共有し、5時間枠と週間枠の両方が使われる場合があるとしている。実際にどれだけ使えるかは、モデル、タスク、入力と出力の大きさ、推論設定などで変わる。

この点は、後でAstraの結果を見るとかなり重要になる。

Lunaは5分17秒で実装を完了#

Lunaの計測開始は2026年9月9日18時40分33秒。

実装、ビルド、指定ケースの確認は18時45分51秒に完了した。

経過時間: 00:05:17.8874742

約5分18秒。

ログ上の結果は次の通り。

横にスクロールできます
項目Luna
実装・確認時間5分17.887秒
ターミナル呼び出し20回
観測可能な作業ステップ13
ソース変更ファイル4
追加行20
削除行10
ビルド失敗0
サイト実装のやり直し0
テスト記述の修正1
ユーザー追加指示0

Lunaは最初にTOP、記事カード、日付コンポーネント、Content Schema、既存のソート処理を調べた。

実装は4ファイルに分かれた。

src/components/ArticleCard.astro
src/components/FormattedDate.astro
src/pages/index.astro
src/utils/posts.ts

特徴は、今回の処理を既存コンポーネント側へ少し一般化したことにある。

src/utils/posts.tsには、更新日を優先する比較関数を追加した。

export const sortPostsByLatestDate = (a: BlogPost, b: BlogPost) =>
  (b.data.updatedAt ?? b.data.pubDate).valueOf() -
  (a.data.updatedAt ?? a.data.pubDate).valueOf() ||
  b.id.localeCompare(a.id, 'ja', { numeric: true });

TOPではこの関数を使う。

const posts = [...allPosts]
  .sort(sortPostsByLatestDate)
  .slice(0, 6);

ArticleCard.astroにはshowUpdatedAtを追加し、TOPから指定した場合だけ更新日と公開日を2段で表示するようにした。

さらにFormattedDate.astrocompact表示を追加している。

既存部品を拡張して再利用する方向の実装になっている。

途中で1回だけ、指定ケースを確認するfixtureのDate変換順を誤り、テストが終了コード1になった。原因はサイト実装ではなくテスト記述側。fixtureを修正した後はPASSしている。

最終的なnpm run buildは終了コード0。

160 page(s) built
Pagefind: Indexed 47 pages

既存のnode scripts/verify.mjsもPASSしている。

Astraは3分29秒。変更は2ファイルに収まった#

Astraの実装計測は19時01分04秒に開始した。

実装、正式ビルド、必要な確認を完了した時刻は19時04分34秒。

経過時間: 209.981秒

3分29.981秒。

Lunaより107.906秒短い。Lunaの実装時間を基準にすると、約33.9%短い。

Astra側の記録はこちら。

横にスクロールできます
項目Astra
実装・確認時間3分29.981秒
計測区間のターミナル呼び出し14回
観測可能な作業ステップ20
ソース変更ファイル2
追加行16
削除行4
ビルド失敗0
サイト実装のやり直し0
追加検証スクリプトの修正2
ユーザー追加指示0

Astraが変更したサイト本体のファイルは2つだけ。

src/components/ArticleCard.astro
src/pages/index.astro

TOPだけで使うソートはindex.astroの中に置いている。

const posts = [...allPosts].sort((a, b) =>
  (b.data.updatedAt ?? b.data.pubDate).valueOf() -
  (a.data.updatedAt ?? a.data.pubDate).valueOf()
).slice(0, 6);

日付表示は、ArticleCardにnamed slotを1つ追加した。

<slot name="dates"><FormattedDate date={post.data.pubDate} /></slot>

TOP側からだけdatesを渡す。

<ArticleCard post={post}>
  <span slot="dates" class="card-dates">
    {post.data.updatedAt && (
      <span>
        更新 <time datetime={post.data.updatedAt.toISOString()}>
          {formatDate(post.data.updatedAt)}
        </time>
      </span>
    )}
    <span>
      公開 <time datetime={post.data.pubDate.toISOString()}>
        {formatDate(post.data.pubDate)}
      </time>
    </span>
  </span>
</ArticleCard>

Lunaが共通部品を拡張したのに対し、Astraは今回必要なTOPだけへ処理を寄せた。

変更範囲だけを見るとAstraの方が小さい。

一方で、Astraは実装後の検証にかなり手をかけている。

Astroテンプレートを単独コンパイルして指定ケースを確認するverify-astra.mjsを作り、最初の実行でcreateMetadata関連のエラーが出た。

その後、実際のAstroコンパイル処理やbindingの型定義まで確認し、runtime指定を変更。2回目も同じエラーになったため、さらにresolvePathを追加して3回目でPASSしている。

ここはサイトコードを直し直したわけではない。Astra自身が追加した検証コード側で2回手戻りが発生した。

それでも正式なnpm run buildは最初から成功している。

160 page(s) built
Pagefind: Indexed 47 pages

ビルド失敗は0回。

画面はLunaとAstraで同じになった#

両ブランチをそれぞれビルドし、生成結果も比較した。

Luna側のTOPはこちら。

Luna実装後のTOPページ。新着・更新記事と更新日・公開日が表示されている

Astra側はこちら。

Astra実装後のTOPページ。Lunaと同じ新着・更新記事表示になっている

見た目だけでは違いが分からない。

比較スクリプトでも、現在TOPに表示される6カードは同一になった。

さらにブラウザで1440×1000と390×844の2サイズを確認し、両方とも横方向のoverflowはなし。日付表示のテキストとジオメトリも同一になった。

TOP以外については、Astroのscope属性、stylesheet、空白だけを正規化して159ページを比較したが、差分は0ページ。

つまり今回要求した「TOPだけ変更し、その他の一覧へ影響させない」は両方とも満たしている。

指定ケースも両方PASSした。

公開日のみ
→ 公開 2026.09.09

更新日あり
→ 更新 2026.09.10
→ 公開 2026.09.01

2026.09.12更新の記事と2026.09.11公開の記事
→ 更新記事を先に表示

機能的な完成結果には差がなかった。

同じ日付の記事だけ、並び方が違う#

完全に同じ実装ではないため、1つだけ挙動差が見つかった。

updatedAt ?? pubDateで求めた基準日が同じ記事同士の順序だ。

Lunaは比較関数の最後で記事IDを使っている。

b.id.localeCompare(a.id, 'ja', { numeric: true })

一方Astraは基準日の差だけを返しているため、同じ日付なら元の配列順を維持する。元の配列は公開日順なので、結果としてその順序が残る。

比較用データでは次の差になった。

横にスクロールできます
条件LunaAstra
基準日が同じ2記事記事IDによる順序元の公開日順を維持

今回の依頼には「同じ基準日のとき何で並べるか」を指定していなかったため、どちらも要件違反ではない。

ただ、今後本番へ採用するなら決めておいた方がよい仕様だと思う。

更新日まで同じ記事が複数ある場合に、公開日を第2キーにするのか、記事IDを使うのか。今回の比較で、モデルによってこうした細部の判断が変わることも確認できた。

2つの実装は方向が違う#

結果の画面は同じでも、コードの作り方は分かれた。

横にスクロールできます
LunaAstra
変更ファイル42
差分+20 / -10+16 / -4
ソート処理posts.tsへ共通関数追加TOPに直接記述
日付表示ArticleCardへprop追加named slot追加
日付フォーマットFormattedDateを拡張TOP内の関数
方向再利用できる形へ拡張TOP限定の変更に寄せる

Lunaの実装は、今後ほかの場所でも「最終更新日順」を使ったり、FormattedDateのコンパクト表示を再利用したりするなら扱いやすい。

Astraの実装は、依頼どおり「TOPだけ」を強く意識している。既存の共通コンポーネントへ手を入れる範囲が小さく、今回だけなら影響範囲を追いやすい。

どちらが正しいという差ではない。

小さい改修でも、AIがどこまで共通化するかには違いが出る。

時間だけならAstraが速い#

ここまでの実装結果を並べる。

横にスクロールできます
項目GPT-5.6 LunaGPT-6 Astra
実装・確認時間5分17.887秒3分29.981秒
Lunaとの差-1分47.906秒短い
ターミナル呼び出し2014(計測区間)
観測可能な作業ステップ1320
ソース変更ファイル42
ソース差分+20 / -10+16 / -4
ビルド失敗00
サイト実装のやり直し00
検証コード側の失敗12
最終画面要件達成要件達成
TOP以外への影響なしなし

Astraは実装時間を約34%短縮した。

ただし「作業ステップ数」はそのままモデル性能として比較しない方がよい。

Lunaのログは一部のコマンドで実行時刻を直接取得できず、複数確認を1つの手順として記録している。Astra側はJSONでシェル呼び出しを細かく保存し、外部ドキュメント参照や検証スクリプト修正も1ステップずつ数えている。

同じ計数方法ではないため、13対20だけを見て「Astraの方が手順が多い」と断定はできない。

比較しやすいのは、実装開始と終了を記録した経過時間、Git差分、ビルド結果、最終出力だ。

Astra終了時の利用枠は、その場で取り損ねた#

今回、特に差が大きく見えたのが利用枠の変化だ。

ただし、ここは測定上の注意がある。

Astraは19時04分34秒に実装、ビルド、指定確認を完了した。その時点でCodexは次のチェックポイントを表示している。

USAGE CHECKPOINT - ASTRA END
5時間制限と週次制限の使用量を確認・スクリーンショット保存してください。

本来ならここで画面を保存すれば、Astraの実装だけに近い差を取れた。

その直後にCodexが比較作業へ進んだ。

ログには、19時05分31秒以降にLuna側のログとdiffの読み込み、Lunaブランチの再ビルド、両出力の比較、ブラウザ確認が残っている。

19:05:31 Lunaの結果とdiffを読み込み
19:05:56 Lunaブランチへ切り替え
19:05:58 Lunaを再ビルド
19:07:44 両出力を比較
19:08:34 ブラウザでLuna/Astraを確認

その後、Codex側で利用上限に達した。

最終的に保存できた画面はこちら。

Astra実行後に5時間枠が0%、週間枠が71%になったCodexとWorkの利用状況

開始前と最終画面だけを並べると、次の変化になる。

横にスクロールできます
5時間枠週間枠
Luna開始前99%残り86%残り
Luna終了 / Astra開始前98%残り86%残り
Astra作業と後続比較の終了後0%残り71%残り

Lunaでは表示上、5時間枠が1ポイント減り、週間枠は整数表示上変化しなかった。

Astra側は、Astra開始前の98%から最終的に0%になり、週間枠も86%から71%になった。

ただし、「Astraの3分29秒の実装だけで98ポイント消費した」とは書けない。

0%の画面を保存した時点には、実装後の比較、Luna再ビルド、HTML比較、ブラウザ確認などが含まれている。Astra実装終了直後の中間値を記録できていないためだ。

また、このパーセントは内部トークン消費量そのものではない。

それでも、小規模な同一作業でLuna終了時には98%残っていた5時間枠が、Astraへ切り替えた後の一連の作業で上限まで到達したことは、実際の運用では無視しにくい結果になった。

Astraは実装以外の検証にも動いている#

Astraのログを見ると、単純に2ファイルを書き換えて終わったわけではない。

実装の前後で、次の確認を行っている。

  • AGENTS.md、package.json、TOP、ArticleCard、FormattedDate、Content Schema、posts.tsをまとめて確認
  • Astro公式ガイドを参照
  • 既存verifyスクリプトとAstro設定を確認
  • npm run build
  • Astro Containerやcompiler-rsの型定義を確認
  • 独自のverify-astra.mjsを作成
  • createMetadataエラーを2回調査
  • Astro本体のcompile.jsとbinding型定義を確認
  • 指定ケースを再実行
  • git diff --check

実装完了後にはさらに、Lunaブランチを再ビルドし、HTML差分とブラウザ表示まで比較した。

ここまで含めて見ると、Astra側の作業は「コードを書く時間」だけではない。

ソース変更はLunaより小さい一方、検証のために低レベルなAstroコンパイラまで追っている。

この追加検証が利用枠にどの程度影響したかは分からない。OpenAIも、Work/Codexの消費量はモデル、タスク、入出力サイズ、推論設定などによって変わるとしているため、1回の結果から原因を分解することはできない。

ただ、実際にCodexへ「比較用のログを細かく残し、ビルドと挙動まで確認してほしい」と頼むと、高性能モデルが実装以上の確認へ広く動くケースがあることは記録できた。

小さな改修ではLunaで要件を満たせた#

今回のタスクだけで見ると、Lunaで不足はなかった。

Lunaは5分17秒で要件を満たし、ビルドも成功。Astraはそこから約1分48秒短縮し、ソース変更を2ファイルに収めた。

最終画面は同じ。TOP以外への影響もない。

Astraには、短時間で局所的な変更へ寄せた利点がある。一方で、この程度の改修で最終的な機能差は出なかった。

利用枠については測定タイミングの問題があるため、AstraとLunaの消費倍率を出すことはできない。それでも、今回の一連のAstra作業で5時間枠の上限まで到達し、その後Codexを続けられなくなったことは無視できない。

小さく、要件が明確で、変更対象が数ファイルに限られる作業なら、まずLunaで進める運用は十分現実的だと思う。

逆に、複数の機能を横断する改修、影響範囲の広い変更、難しい不具合調査では、Astraが短い時間や少ない手戻りで終わるなら利用枠を多く使う意味が出てくるかもしれない。

そこは今回1件だけでは判断できない。

検証2:カスタム404ページを同じ条件で作る#

2回目の検証は、ゆまラボ専用の404ページ追加にした。

対象は、存在しないURLへアクセスしたときに、通常のヘッダーとフッターを残しながら「ページが見つかりません」と表示し、トップページと記事一覧へ戻れるようにする改修。

実装内容は第25回 ゆまラボ専用の404ページを作る―存在しないURLから記事へ戻れる導線を追加にまとめている。

初回比較で残った測定上の問題も修正した。

最初のTOP改修では、Astraが実装を終えた後もCodexが比較処理を続けたため、Astra終了直後の利用枠を記録できなかった。そこで検証2では、モデルごとに実装、ビルド、ローカル確認が完了した時点でCodexを停止し、その直後に利用枠画面を保存した。

また、LunaとAstraは別のCodexチャットで実行した。開始地点だけを共通のBASE_COMMITへ固定し、AstraにはLuna側のdiffや実装コードを読ませていない。

同じBASE_COMMITから404ページを作る#

開始地点は次のコミット。

9e1d2e67be253e660303ec9a143ca62497f844f8

ブランチも分けた。

experiment/404-page-luna
experiment/404-page-astra

BASE_COMMITの時点では、src/pages/404.astrosrc/pages/404.mdはどちらも存在していない。

一方、Cloudflare Workers側のwrangler.jsoncには、すでに次の設定が入っていた。

{
  "assets": {
    "not_found_handling": "404-page"
  }
}

そのため、両モデルへ要求したサイト本体の変更はsrc/pages/404.astroの追加だけになる。

共通条件は次の通り。

  • SiteLayoutなど既存のレイアウトを再利用する
  • 404と「ページが見つかりません」を表示する
  • トップページと記事一覧へ移動できるようにする
  • 通常ページのURLや既存機能を変更しない
  • 存在しないURLをトップへリダイレクトしない
  • Astro previewとWranglerでHTTP 404を確認する
  • PCとスマホ幅への影響も確認する

利用枠は実装終了直後に保存した#

Luna開始前は、5時間枠が93%残り、週間枠が70%残り。

404検証でGPT-5.6 Lunaを選択した画面

404検証のLuna開始前。5時間93%残り、週間70%残り

Lunaが実装、ビルド、ローカル確認を終えたところで追加作業を停止した。直後の表示は5時間89%残り、週間69%残り。

404検証のLuna終了直後。5時間89%残り、週間69%残り

ここから新しいCodexチャットを開き、GPT-6 Astraへ切り替えた。

404検証でGPT-6 Astraを選択した画面

Astra開始前の利用枠は、Luna終了直後と同じ5時間89%残り、週間69%残り。

404検証のAstra開始前。5時間89%残り、週間69%残り

Astra側も実装、ビルド、ローカル確認が終わった時点で比較処理へ進ませず停止した。終了直後は5時間32%残り、週間60%残りになった。

404検証のAstra終了直後。5時間32%残り、週間60%残り

管理画面の表示値をそのまま並べるとこうなる。

横にスクロールできます
モデル5時間枠 開始5時間枠 終了表示差週間枠 開始週間枠 終了表示差
GPT-5.6 Luna93%残り89%残り-4pt70%残り69%残り-1pt
GPT-6 Astra89%残り32%残り-57pt69%残り60%残り-9pt

前回と違い、両モデルとも実装終了直後に画面を保存している。少なくとも前回のように、Astra終了後のLuna再ビルドや比較処理が混ざった値ではない。

ただし、この数字をそのまま「AstraはLunaの14.25倍トークンを使った」とは扱わない。

表示は整数単位の残量であり、トークン数ではない。WorkとCodexの利用枠はモデル、タスク、入出力、推論設定などでも変わる。今回確認できる事実は、同じ404実装で管理画面上の5時間枠がLunaでは4ポイント、Astraでは57ポイント低下したことまでになる。

OpenAIの案内でも、同じタスクでもモデルによって利用枠の消費量が異なり、Astraは利用枠を速く使う場合があるとしている。今回の実測でも、その差を無視しにくい結果になった。

Lunaは93行、Astraは30行で同じ要件を満たした#

両モデルとも変更したサイト本体のファイルは1つだけ。

src/pages/404.astro

追加パッケージもなく、package.jsonastro.config.mjswrangler.jsoncは変更していない。

ただし、作った404.astroの構成はかなり違う。

Luna側は93行。

404の数字を大きく中央へ配置し、サイト名の表示、中央寄せ、ボタン風の戻りリンク、520px以下でリンクを縦積みにするメディアクエリまでページ内へ持たせた。

実装の主要部分は次の形。

<main class="not-found">
  <p class="eyebrow">{SITE_TITLE}</p>
  <p class="status">404</p>
  <h1>{title}</h1>
  <p class="message">
    ゆまラボ内のページが見つかりませんでした。
    URLをご確認いただくか、次のページからお探しください。
  </p>
  <nav class="actions" aria-label="404ページのナビゲーション">
    <a class="primary" href="/">トップページへ戻る</a>
    <a href="/blog/">記事一覧を見る</a>
  </nav>
</main>

Astra側は30行。

通常の記事や固定ページに近い左寄せの余白を使い、404、見出し、説明、2本のテキストリンクだけに絞った。

<main>
  <section class="not-found" aria-labelledby="not-found-title">
    <p class="error-code">404</p>
    <h1 id="not-found-title">{title}</h1>
    <p class="description">
      お探しのページは、URLが変更されたか、削除された可能性があります。<br />
      トップページや記事一覧から記事をお探しください。
    </p>
    <nav class="return-links" aria-label="404ページからの移動先">
      <a href="/">トップページへ戻る</a>
      <a href="/blog/">記事一覧を見る</a>
    </nav>
  </section>
</main>

要件達成だけを見ると両方とも同じ。

Lunaは404ページ単体のUIをはっきり作る方向、Astraは現在のゆまラボの通常レイアウトへ寄せて変更量を小さくする方向になった。

公開後の画面はこちら。

公開したゆまラボ専用404ページ

公開画面の文言とレイアウトはAstra側の実装と一致している。本番へ反映されたのはAstra案。

Astraはブラウザ確認まで自力で広げた#

実装時間以外にも差が出た。

LunaはAstro previewとWranglerを起動し、正常URLが200、存在しないURLが404になることを確認した。ただしブラウザ自動操作環境を利用できないと判断し、PC・スマホはHTMLとCSSの静的確認で終了している。

その途中で検証系の失敗が3回あった。

  • previewサーバーへの初回接続失敗
  • PowerShellのHttpClient型指定エラー
  • Nodeコマンドのシェルクォートエラー

サイト本体の修正は必要なく、すべて確認処理側の失敗として解消している。

Astraはプロジェクト内にPlaywright等がないことを確認したあと、同じWindows環境にインストールされているMicrosoft Edgeを見つけ、CDPを使った確認処理を追加した。

結果として、Astro previewとWranglerの2環境で36回のHTTP確認を実施。正常ページ、複数の存在しないURL、HEADリクエストまで確認している。

PCは1440×900、スマホは390×844でスクリーンショットも保存し、トップページと記事一覧のリンクを実際にクリックした。

Astraがローカル環境で確認した404ページのPC表示

Astraがローカル環境で確認した404ページのスマホ表示

ここは利用枠の差を見るうえで無視できない。

Astraは同じ1ファイルの実装でも、Lunaより確認範囲を広く取っている。高性能モデルの利用枠が単純に「30行のコードを書くためだけ」に使われたとは見ない方がよい。

標準化した実装時間ではAstraが約2分3秒短い#

今回、比較用ログで定義した計測区間は、実装調査開始から、実装・ビルド・ローカル確認が終わるまで。

結果はこちら。

横にスクロールできます
項目GPT-5.6 LunaGPT-6 Astra
比較用の計測時間5分16.822秒3分13.527秒
Lunaとの差-2分03.295秒短い
ソース変更ファイル11
ソース差分+93 / -0+30 / -0
コマンド記録26エントリ15シェル呼び出し
観測可能な作業ステップ1016
ビルド回数21
ビルド失敗00
サイト実装のやり直し00
検証失敗30※
ブラウザ実画面確認できずPC・スマホ確認
HTTP 404preview / Wranglerで確認preview / Wranglerで確認

※Astraには計測開始前に文字コードの読み直しとオーケストレーション側のReferenceErrorが1件ずつあったが、実装計測区間の検証失敗には含めていない。

AstraはLunaより123.295秒短く、Lunaの時間を基準にすると約38.9%短い。

一方、Codexの画面にはAstraのセッション全体として「5m 53s間作業しました」と表示された。比較ログで定義した開始・終了区間に加え、事前確認や終了後のログ保存・コミットなども含む表示と考えられる。

モデル間の比較表では、Luna/Astraで同じ定義を使えるログ上の3分13.527秒を採用する。

速度差より利用枠の差の方が大きく見える#

初回のTOP改修ではAstraが約34%短時間だったが、終了直後の利用枠を保存できなかった。

今回の404実装では、計測時間でもAstraが約39%短い。

ここまでなら、Astraは同じ要求を短時間で処理したと言える。

ただ、利用枠の表示差はそれ以上に大きかった。

Luna
5時間枠 93% → 89%
週間枠   70% → 69%

Astra
5時間枠 89% → 32%
週間枠   69% → 60%

最終機能はどちらも、

  • カスタム404を表示する
  • トップへ戻れる
  • 記事一覧へ移動できる
  • 正常URLは200
  • 存在しないURLは404

を満たしている。

今回の作業だけなら、Astraでなければ実装できなかった機能はない。

その一方、Astraはブラウザを見つけて実際のPC・スマホ表示まで検証し、HTTP確認も広く行った。この確認範囲を含めた品質確認まで任せたい場合は、利用枠を多く使っている理由の一部として見ることもできる。

それでも、5時間枠が57ポイント低下した事実は運用上かなり大きい。

短い改修を何本も続ける日なら、今回のような404ページ追加ではLunaを使い、難しい不具合調査や広い影響範囲の変更にAstraを残す運用の方が扱いやすい。

検証2までの段階では、その判断が初回より強くなった。

検証3:内部リンク切れをビルド時に検出する#

3回目は、これまでよりビルド処理へ踏み込む改修にした。

対象は、記事やページに存在しない内部URLへのリンクが含まれていた場合に、npm run buildの中で検出してビルドを失敗させる処理。

実装内容は第26回 記事内リンク切れをビルド時に検出する―記事が増えても404を残さない仕組みを作るにまとめている。

修正前は、記事へ次のような存在しない内部リンクを追加してもビルドが成功していた。

[リンク切れ確認用](/blog/__broken-link-test__/)

AstroはHTMLを生成し、Pagefindとsitemapの処理も完了する。

最終的に生成されたdistのHTMLを検査し、内部リンクのリンク先が実際の出力に存在するか確認する処理を追加した。

要求した主な条件は次の通り。

  • npm run buildだけで内部リンク検査まで実行する
  • 記事Markdownだけではなく、生成されたHTMLを基準にする
  • /始まり、相対URL、https://bringain.com/の同一サイト絶対URLを扱う
  • queryとhashはページ本体の存在確認から外す
  • RSS、XML、画像、PDFなどの静的ファイルも存在すれば正常扱いする
  • 外部サイトへHTTPリクエストを送らない
  • リンク切れがあればリンク元とリンク先を表示する
  • 複数件あれば一覧化してから終了コード1にする
  • 意図的なリンク切れで実際にbuildが失敗することを確認する
  • テスト用リンクを削除した後、再度buildが成功することを確認する

Astraの思考量を「中」に下げた#

最初の2回はLunaとAstraの思考量をどちらも「極高」にしていた。

3回目は条件を変えた。

GPT-5.6 Luna
思考量:極高

GPT-6 Astra
思考量:中

Astraは「極高」から2段下げている。

そのため、3回目はLunaとAstraを同じ推論設定で比較する実験ではない。

前回までAstraは短時間で実装を終える一方、5時間枠の表示が大きく低下していた。今回は思考量を下げ、実装要件を満たせるか、利用枠の表示差が小さくなるかを見る。

Luna終了後の変更はgit stash -uで退避した。

git stash push -u -m "broken-link-check-luna"

作業ツリーがcleanになったことを確認してから、同じHEADを起点にAstra用ブランチを作成した。

BASE_COMMIT
10e2a55213b094ce7f2a6a7b8fd51751f88442cc
experiment/broken-link-check-luna
experiment/broken-link-check-astra

AstraにはLuna側の実装コードやdiffを引き継がせていない。

Luna極高は8分6秒、Astra中は4分20秒#

計測結果は次の通り。

横にスクロールできます
項目GPT-5.6 LunaGPT-6 Astra
思考量極高
実装・確認時間8分6.182秒4分20.409秒
Lunaとの差-3分45.773秒短い
変更対象2ファイル4ファイル
追加パッケージなしparse5を直接dev依存化
専用テストファイルなしあり
意図的リンク切れ検出検出
リンク切れ時のbuild失敗失敗
テスト削除後のbuild成功成功
git diff --check成功成功
既存verify.mjs既存問題で失敗既存問題で失敗

Astra中は、Luna極高より3分45.773秒短かった。

Lunaの時間を基準にすると約46%短い。

ただし、思考量が違うため、この時間差だけでモデル性能を直接比較するものではない。

確認したいのは、Astraを「中」まで下げても必要な実装と検証が完了するかどうか。

今回については、Astra中でも要求した機能は成立した。

Lunaは依存追加なし、Astraはparse5と専用テストを追加した#

両モデルは同じ目的を達成したが、実装方法は分かれた。

Luna側の変更は2件。

package.json
scripts/check-internal-links.mjs

追加パッケージはない。

dist配下のHTMLを検査するスクリプトを127行で追加し、package.jsonのbuild末尾から実行する形にした。

最初の通常buildでは、既存404ページのcanonical URL /404/をリンク切れとして1件誤検出した。

canonicalは利用者がたどるナビゲーションリンクではないため検査対象から除外し、再ビルド後は正常になった。

最終的な通常状態はこうなった。

175 generated HTML page(s)
8448 internal link(s)
0 broken links

Astra側は4件。

package.json
package-lock.json
scripts/check-links.mjs
scripts/check-links.test.mjs

HTML解析にはparse5を使った。

parse5は既存の依存ツリーに間接依存として存在していたが、スクリプトから直接使うためdevDependenciesへ明示している。

AstraはさらにURL形式や除外条件を確認する専用テストを5件作成した。

初回テストでは期待リンク数を19件と書いていたが、正しい値は18件だったため、テスト記述を修正して全件PASSしている。

サイト本体のリンク検査ロジックを直し直したわけではない。

Lunaは依存追加を避けて1本の検査スクリプトへ収め、AstraはHTMLパーサーと専用テストを明示的に追加した。

今回も、最終機能が同じでも実装の方向は一致しなかった。

どちらも意図的なリンク切れでbuildを止めた#

Luna側ではテスト用URL、

/blog/__broken-link-test__/

を追加した状態でnpm run buildを実行し、終了コード1になることを確認した。

報告されたリンク元はこのURL。

/blog/404-page-guide/

Astra側でも同じURLを使った。

実際のログは次の形。

[links] Checked 175 HTML pages, 5913 internal links; broken links: 1.
[links] "/blog/broken-links-seo/" -> "/blog/__broken-link-test__/" (/blog/__broken-link-test__/)

こちらもbuildは終了コード1。

テスト用リンクを削除したあとに再ビルドすると、

[links] Checked 175 HTML pages, 5908 internal links; broken links: 0.

となり、正常終了した。

Astro 175ページ、Pagefind 55ページ、画像最適化、sitemapの既存処理も完了している。

Astra側では通常ビルドと復元後のHTML・CSS計180ファイルのハッシュも比較し、すべて一致した。

つまり、リンク検査を追加したことによって記事HTMLやCSSが書き換わったわけではない。

内部リンク件数はLunaとAstraで一致しなかった#

ここは結果をそのまま残す。

Lunaの最終報告では、

8448 internal link(s)

Astra側では、内部リンク数が次の値になった。

5908 internal links

同じ175 HTMLページを対象としているが、数えた内部リンク数は一致していない。

この差は少し引っかかった。

両方とも意図的に追加した存在しないURLは検出し、正常状態ではbroken links 0件になっている。

ただし、内部リンク件数が違う以上、2つのスクリプトが完全に同じ集合を数えているとは扱わない。

link要素、canonical、重複URL、静的ファイルなどの数え方に実装差がある可能性はあるが、今回の記録だけで2,540件の差を1つの原因へ断定はしない。

内部リンク件数そのものはLunaとAstraの性能比較値には使わない。

本番へ採用する実装を決めるなら、リンク切れを検出できるかに加え、どの種類のhrefを検査対象へ含めるかも確認する必要がある。

思考量を下げてもAstraの利用枠表示は大きく下がった#

今回も実装終了直後に利用枠を保存した。

Luna開始前は、5時間枠100%残り、週間枠60%残り。

Luna極高の終了直後は、5時間枠97%残り、週間枠60%残り。

表示差は5時間枠が3ポイント、週間枠は整数表示上0ポイント。

この状態からAstra中を開始した。

Astra終了直後は、5時間枠37%残り、週間枠50%残り。

内部リンク切れ検出でLuna極高とAstra中を実行したモデル設定と終了直後の利用枠

管理画面の表示をそのまま表にするとこうなる。

横にスクロールできます
モデル思考量5時間枠 開始5時間枠 終了表示差週間枠 開始週間枠 終了表示差
GPT-5.6 Luna極高100%97%-3pt60%60%0pt
GPT-6 Astra97%37%-60pt60%50%-10pt

Astraは思考量を「中」まで下げても、管理画面上の5時間枠は60ポイント低下した。

前回の404検証では、Astra極高で89%から32%へ57ポイント低下している。

今回の表示差だけを見ると、「思考量を2段下げれば利用枠の減少も大幅に小さくなる」という結果にはならなかった。

ただし、ここでもポイント差をトークン数や料金へ変換しない。

管理画面は整数の残量表示であり、WorkとCodexで利用枠を共有している。今回確認できるのは、実装開始前後に画面上の残量がこのように変化したことまで。

Astra中は4分20秒で要求を満たしたため、思考量を下げても実装能力が足りなかったという結果ではない。

一方、今回の目的の一つだった「Astraの思考量を下げれば利用枠を大きく節約できるか」については、この1回では確認できなかった。

3回目でも最終機能は両方成立した#

3回目まで、Astraの方が計測時間は短い。

TOP改修
Luna 5分17.887秒
Astra 3分29.981秒

404ページ
Luna 5分16.822秒
Astra 3分13.527秒

内部リンク切れ検出
Luna極高 8分6.182秒
Astra中   4分20.409秒

3回目はAstraの思考量を下げても、最終機能は両方成立した。

ただ、利用枠の表示差も3回続けてAstra側が大きい。

実装方法も、Lunaは追加依存なし、Astraはparse5と専用テストを追加する形に分かれた。

ここまでの結果では、「Astraでなければ実装できなかった」というタスクはまだない。

Astraは毎回短い時間で完了している。一方、複数の小さな改修を続ける日には、利用枠を残す目的でLunaを先に使う判断はまだ有効に見える。

難易度がさらに上がったとき、Luna側で手戻りや未達が増えるかは次の検証で確認する。

検証4:記事本文の画像をAstroで最適化する#

4回目は、これまでより対象数の多い作業にした。

記事本文に掲載しているローカル画像を調査し、Astroの画像処理を使ってWebP、srcsetsizeswidthheight、遅延読み込みを追加する。

実装内容は第27回 画像表示を見直す―Astroの画像最適化と遅延読み込みでページを軽くするにまとめている。

修正前の本文画像はpublic/images/配下をそのまま参照していた。

代表画像のHTMLでは、

<img src="/images/blog/..." alt="...">

となっており、確認した要素にはsrcsetsizesloadingwidthheightが付いていなかった。

調査対象は、PNG実ファイル278件、本文内参照281件、元画像総容量44,399,561 bytes。

今回の要求には、形式変換だけでなく、PC・スマホ確認、実際に配信される画像容量、lazy loading、画像404、既存build、内部リンクチェック、既存verifyまで含めた。

Lunaは極高で27分03秒、要求した確認まで完走した#

Lunaは思考量「極高」で実行した。

開始前は5時間枠100%残り、週間枠50%残り。終了直後は5時間枠88%残り、週間枠48%残りまで減った。

表示差は5時間枠が12ポイント、週間枠が2ポイント。

作業時間は、ログ上では以下。

開始      2026-09-12 00:56:16.892 +09:00
最終確認  2026-09-12 01:23:20.556 +09:00
実作業時間 27分03.664秒

Luna側では本文画像をsrc/assetsへ移し、共通のrehypeプラグインからAstro標準の画像処理へ渡した。

代表ページでは、

srcset  320 / 480 / 640 / 720w
sizes   (min-width: 720px) 720px, 100vw
形式    WebP
loading lazy

を確認している。

容量集計は、

元画像                    44,399,561 bytes
生成された本文画像候補     11,315,090 bytes
削減                       33,084,471 bytes
削減率                     74.52%

代表ページ/blog/25-custom-404-page/では、122,901 bytesから26,698 bytesまで減り、削減率は78.28%。

npm run buildも成功。

178 page(s) built
Pagefind: Indexed 57 pages
内部リンク 6,064件
broken links 0件

PC 1440×900、スマホ390×844も確認し、スマホでは本文幅343px、画像幅343px、横スクロールなし。

既存verify.mjsは重複slugによる58対57件の不一致で失敗したが、今回の変更前から存在する問題として修正対象から外した。

Astraは思考量を最も低い側の「軽」にした#

3回目ではAstraを「中」まで下げてもリンク切れ検出を完了できた。

4回目はさらに下げ、Codex画面の表記で**「軽」**を選択した。

開始時の利用枠はLuna終了直後と同じ。

5時間枠 88%残り
週間枠   48%残り

Astra側もLuna側の変更を引き継がない状態から開始した。

Astra軽は別の方法でビルド成功まで進んだ#

Astra軽は、途中まで何もできなかったわけではない。

調査画面では、

PNG 278ファイル
本文内281参照
合計44,399,561 bytes

を確認している。

実装方針はLunaと違った。

Lunaは本文画像の実ファイルをsrc/assetsへ移したが、AstraはMarkdownと元画像をそのまま残し、共通Markdownプラグインで画像をAstroへ渡す方法を選んだ。

画面上では、変更が設定ファイルと本文画像用プラグインの2ファイルに収まったと報告されている。

ビルドも成功した。

さらにキャッシュ無効のChromeで、

代表記事の本文画像2枚
PC      30,446 bytes
スマホ  10,474 bytes

を実測し、画面下の画像がスクロールまで読み込み保留になることも確認した。

ここまでを見ると、思考量「軽」でも実装とブラウザ確認自体は進められている。

48分後に5時間枠が0%になった#

その後、Codex画面には、

48分間作業しました

と表示された。

直後に、

利用制限に達しました。
さらに利用するには、ワークスペースのオーナーにお問い合わせください。

と表示され、処理が止まった。

停止時は、5時間枠0%残り、週間枠35%残り。

画像最適化でLuna極高とAstra軽を実行したときの開始・終了利用枠

Astra開始時からの表示差は、

5時間枠 88% → 0%   -88pt
週間枠   48% → 35%  -13pt

になる。

Astraがコードを書けなかったために失敗したわけではない。

ビルド成功、代表記事の容量測定、遅延読み込みの確認までは進んだ。

ただし、こちらが指定した全検証と最終報告を出し切る前に5時間枠を使い切った。

そのため、比較タスクとしては完走できなかったと扱う。

「軽」にしても、この規模では利用枠が足りなかった#

3回目ではAstraを「中」にし、リンク切れ検出を4分20秒で完了した。

4回目ではさらに「軽」へ下げた。

それでも48分の作業後に5時間枠が0%になった。

タスク内容が違うため、「中より軽の方が利用枠を多く使う」とは判断しない。

今回の画像最適化は、278ファイル、281参照、44MBを超える元画像を扱い、生成画像、レスポンシブ候補、PC・スマホ、Network、lazy loading、buildまで確認する要求。

今回確認できたのは、Astraの思考量を「軽」まで下げても、この規模の一連の作業を現在の残り利用枠で最後まで完走できなかったということ。

本番にはLuna版を採用する#

本番へ反映するのはLuna側の実装にした。

Luna側では、要求した容量集計、WebP生成、srcsetsizesloading="lazy"、PC・スマホ、画像HTTP 200、正式buildまで一通り確認できている。

Astra版は実装方法としては興味深い。

Markdownと元画像を移動せず、2ファイルに変更を収めていた。

ただ、利用制限に到達したため、今回要求した最終報告を最後まで取得できなかった。

今回の結果は、「Astra軽では画像最適化できない」ではない。

実装は進んだが、今回の比較条件ではクレジットが足りず最後まで完走できなかった。

ここを分けて記録しておく。

4回分を並べると利用枠の扱いが見えてきた#

横にスクロールできます
検証LunaAstraAstra思考量Astra側の結果
TOPの新着・更新記事5分17.887秒3分29.981秒極高完了
404ページ5分16.822秒3分13.527秒極高完了
内部リンク切れ検出8分6.182秒4分20.409秒完了
本文画像最適化27分03.664秒画面表示48分利用制限到達、比較タスク未完走

Astraは最初の3回では毎回Lunaより短時間で要求を満たした。

4回目は思考量を「軽」まで下げたが、作業規模が大きくなったところで5時間枠を使い切った。

この4回の実測だけでモデル全体の優劣は決めない。

少なくとも今回の画像最適化では、Luna極高は27分で完走し、Astra軽は48分作業した時点で利用制限に到達した。

総評#

4回の比較では、TOP改修、404ページ、内部リンク切れ検出の3件は、LunaとAstraのどちらも最終的な要件を満たした。計測時間だけを見ると、この3件はすべてAstraの方が短かった。

一方で、利用枠の減り方はAstra側が大きかった。404ページでは5時間枠が57ポイント、内部リンク切れ検出では思考量を「中」まで下げても60ポイント低下している。表示値はトークン数そのものではないため単純な倍率比較はできないが、同じ日に複数の改修を続ける運用では無視しにくい差。

4回目の本文画像最適化では、Luna極高が27分03.664秒で要求した確認まで完走した。Astraは思考量を「軽」まで下げ、実装とビルド、ブラウザでの容量確認や遅延読み込み確認までは進んだが、48分作業した時点で5時間枠が0%になり、比較タスクを最後まで終えられなかった。

実装方法にも差が出た。Lunaは既存部品の共通化や依存追加を避ける方向を選ぶ場面があり、Astraは変更ファイルを絞ったり、専用テストや追加検証まで広げたりする場面があった。最終結果が同じでも、そこへ到達する手順はかなり違う。

今回の4件だけでモデル全体の優劣は決められない。ただ、ゆまラボで実際に使った範囲では、短時間で局所的な変更を終える速さはAstraに分があり、利用枠を残しながら複数の作業を続ける扱いやすさはLunaの方が高かった。

最終的には、モデル名だけで選ぶより、作業時間、利用枠、変更範囲、検証の広さ、最後まで完走できるかをまとめて見る必要がある、という結果になった。

参考#