0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

バッチワーカーに中立サンドボックスを渡すと、ファイル列挙タスクが構造的に失敗する

0
Last updated at Posted at 2026-09-01

自動化ワーカーを安全に動かすために、作業ディレクトリを分離するのは自然です。ところが、タスク契約が「リポジトリ上のファイルを列挙して判断する」ことを前提にしていると、中立サンドボックスは失敗の発生源になります。

手元の失敗台帳では、全 2679 件のうち fail_type=blocked_by_input が 1208 件、fail_type=missing_inputs が 20 件ありました。根拠は次のような行です。

{"status":"partial","fail_type":"blocked_by_input","dept":"marketing","lane":"ops","project":"revenue2"}
{"status":"blocked","fail_type":"missing_inputs","dept":"video","lane":"youtube-en","project":"sci-shorts"}

この数字だけで「全部が同じ原因」とは言えません。ただし、カードが「リポジトリを見て対象を選べ」と要求しているなら、入力不足を個別事故として扱うより、実行契約を疑ったほうが再発防止に近づきます。

なお、既公開一覧の Qiita セクションには、入力検証、allow-list、ステージング失敗の記事がありました。本稿は既公開 33 本以上の Qiita 記事と照合し、重複しない「cwd 隔離とタスク契約の不整合」に絞っています。

失敗の形

最小化すると、失敗はこうです。

タスク契約:
  repo/articles 配下を列挙し、未投稿の記事候補を選ぶ

実行環境:
  worker の cwd は空の一時ディレクトリ
  repo 本体は見えない

結果:
  ファイルが存在しないので候補 0 件
  ワーカーは missing_inputs または blocked_by_input で止まる

ワーカーは悪くありません。契約に必要な入力が、ワーカーから見える場所にないだけです。問題は「cwd を隔離する」設計と「cwd からリポジトリを探索する」設計が、同時に成立しないことです。

最小再現

次の Node.js スクリプトは、articles ディレクトリを列挙して最初の Markdown を選ぶだけです。

// worker.js
const fs = require("node:fs");
const path = require("node:path");

const root = process.cwd();
const articlesDir = path.join(root, "articles");

if (!fs.existsSync(articlesDir)) {
  console.error(JSON.stringify({
    status: "blocked",
    fail_type: "missing_inputs",
    reason: "articles directory is not visible from cwd"
  }));
  process.exit(2);
}

const files = fs.readdirSync(articlesDir)
  .filter((name) => name.endsWith(".md"))
  .sort();

if (files.length === 0) {
  console.error(JSON.stringify({
    status: "blocked",
    fail_type: "blocked_by_input",
    reason: "no markdown candidates"
  }));
  process.exit(2);
}

console.log(JSON.stringify({
  status: "done",
  selected: path.join("articles", files[0])
}));

リポジトリ直下で実行すると通ります。

New-Item -ItemType Directory -Force articles | Out-Null
"# hello" | Set-Content articles\a.md -Encoding UTF8
node worker.js

一方、ワーカーだけを別 cwd で起動すると落ちます。

New-Item -ItemType Directory -Force sandbox | Out-Null
Copy-Item worker.js sandbox\worker.js
Push-Location sandbox
node worker.js
Pop-Location

出るのは、おおむね次の種類のエラーです。

{"status":"blocked","fail_type":"missing_inputs","reason":"articles directory is not visible from cwd"}

これは「ファイルがない」ではなく、「契約に必要なファイルをワーカーに渡していない」です。

直し方: 探索させず、入力目録を渡す

修正は、ワーカーにリポジトリを探させないことです。呼び出し側が、許可された入力だけを manifest として渡します。

{
  "inputs": [
    { "id": "a", "path": "staged/articles/a.md" },
    { "id": "b", "path": "staged/articles/b.md" }
  ]
}

ワーカー側はこうします。

// worker-fixed.js
const fs = require("node:fs");

const manifestPath = process.argv[2];
if (!manifestPath) {
  throw new Error("usage: node worker-fixed.js manifest.json");
}

const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
const candidates = manifest.inputs
  .filter((item) => item.path.endsWith(".md"))
  .sort((a, b) => a.path.localeCompare(b.path));

if (candidates.length === 0) {
  console.error(JSON.stringify({
    status: "blocked",
    fail_type: "missing_inputs",
    reason: "manifest has no markdown candidates"
  }));
  process.exit(2);
}

console.log(JSON.stringify({
  status: "done",
  selected: candidates[0].id
}));

実行手順です。

@'
{
  "inputs": [
    { "id": "a", "path": "staged/articles/a.md" }
  ]
}
'@ | Set-Content sandbox\manifest.json -Encoding UTF8

Copy-Item worker-fixed.js sandbox\worker-fixed.js
Push-Location sandbox
node worker-fixed.js manifest.json
Pop-Location

この形にすると、cwd がどこであっても、ワーカーの判断材料は manifest に固定されます。

契約を2つに分ける

実装上は、次の 2 段に分けると事故が減ります。

prepare:
  候補を列挙し、許可されたファイルだけを staging に置く
  manifest.json を作る

worker:
  staging と manifest.json だけを見る
  成果物と result.json だけを書く

prepare は探索してよいが、worker は探索しない。worker の安全境界を狭くしたいなら、その内側に必要な入力をすべて置く必要があります。

blocked_by_input が多いパイプラインでは、ワーカーを責める前に「判断に必要なものが見えているか」を確認したほうがよいです。中立サンドボックスは便利ですが、ファイル列挙まで中に押し込むと、入力不足を量産します。探索は prepare、実行は worker。この分離だけで、失敗の扱いは読みやすくなります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?