コンテンツにスキップ

AI Code Import — I/O 定義

このページは apps/code-import/(src/code_import/ 配下の Python パッケージ code_import)に実装する code-import ワーカーの 公式 I/O 契約 です。フィールド・形状・ステータス値・失敗区分の変更はすべて契約変更であり、コードをマージする前に本ページおよび test-cases.ja.md に反映してください。

読み順: 概要 → 入力 → 処理契約 → 出力 → エラーハンドリング → 冪等性。文末の フィールド参照 はルックアップ用です。


概要

flowchart LR
  api[guinness-backend] -->|INSERT code status=0| RDB[(PostgreSQL)]
  api -->|SendMessage| Q[(SQS code-import)]
  Q --> L[AI Code Import worker]
  L -->|validate optional reference| S3[(S3 preview metadata)]
  L -->|one semantic run| LLM[(DESC_MODEL)]
  L -->|one batch, two inputs| EMB[(Embeddings 512)]
  L -->|transactional replace + invalidate| Doc[(DocumentDB code + code_index)]
  L -->|POST /v1/webhooks/ai-status| api
  api -->|UPDATE code status=1 or 2| RDB
項目 値
トリガー code-import キュー上の SQS レコード
入力 SQS メッセージ + 任意 canonical S3 preview reference
出力 DocumentDB アップサート 1 件(code コレクション)+ Webhook POST 1 件
DocumentDB 書き込み evidence 変更時に scoped code replace と code_index.status=stale を同一 transaction で実行
RDB 書き込み なし — ワーカーは PostgreSQL / MySQL にアクセスしない
外部呼び出し deterministic source parsing、PydanticAI semantic agent 1 回、provider-selected embeddings(1 call / 2 inputs)、Webhook POST
AI フレームワーク changed record ごとに PydanticAI Agent 1 回。embedding は configured OpenAI-compatible client

入力

1. SQS メッセージ(トリガー)

Lambda は標準の AWS SQS イベントを受信します。バックエンド(apps/app/src/services/code.ts)が code-import キューに投入し、各ジョブの Records[*].body に JSON 文字列が入ります。

{
  "Records": [{
    "messageId": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
    "body": "{\"code_id\":\"660e8400-e29b-41d4-a716-446655440001\",\"organization_id\":1,\"project_id\":42,\"name\":\"button-primary\",\"type\":1,\"based_on\":0,\"source_code\":\"<button className='btn btn-primary'>Click me</button>\",\"css_code\":\".btn-primary { background:#007bff; }\",\"img_url\":\"s3://bucket/code/42_button.png\"}",
    "attributes": { "ApproximateReceiveCount": "1" },
    "eventSource": "aws:sqs"
  }]
}

ボディフィールド(Records[*].body をパース後、Pydantic の CodeImportMessage で検証 — 概要 §1)。

フィールド 型 必須 備考
code_id string (UUID) ✓ RFC 4122 UUID v4 — DocumentDB の _id および Webhook の recordId になる
organization_id integer ✓ テナント分離;DocDB に永続
project_id integer ✓ 下流のベクトル検索スコープ用
name string ✓ そのまま保存
type integer ✓ 0 = page、1 = code
based_on integer ✓ 0 imported、1 design、2 wireframe
source_code string ✓ 非空;上流は ≤200 KB を推奨 — 未解決事項
css_code string | null ✗ あればそのまま保存
img_url string | null ✗ 任意 canonical preview reference。metadata として保存し、worker は download しない
component_level string | null ✗ 任意 hint: atom, molecule, organism, template, component

Body のアンラップ。 Lambda/API Gateway の差を吸収するため、ハンドラは次を(優先度順で)許容します。

  1. フラット — 上記のオブジェクト自体が body
  2. SQS-in-SQS — 外側の Records[0].body に内側の JSON 文字列
  3. API Gateway プロキシ — body.body(任意で isBase64Encoded)
  4. 二重ラップ(レガシー) — テストフィクスチャ にある余分な Records ネスト;フラットな CodeImportMessage が見えるまでアンラップ

それ以外の形状は検証エラー。

2. S3: オプションのコンポーネントスクリーンショット

プロパティ 値
ソース img_url が非 null のとき
検証 bucket は S3_BUCKET_NAME、key は org/project/code の canonical preview key、extension は png/jpg/webp
Worker access S3 GET なし。visual.metadata.image_url に reference のみ保存
無い場合 image URL は null。semantic/context import は同じ

3. RDB 行の状態(読み取りは他システム)

ワーカーは PostgreSQL の code 行を直接読まない。バックエンドが SQS 公開前に行を作成(通常 status = 0)。完了は Webhook で通知し、ステートマシンのオーナーはバックエンド。


処理契約

SQS レコードごとに同期的に以下の順で処理する:

  1. 必要なら アンラップ したうえで CodeImportMessage をパース+検証。
  2. preview reference 検証 — img_url がある場合 canonical bucket/key を要求し、download しない。
  3. code context 抽出 — name/source/CSS/component-level hint から family、variant、structured imports、exports、references、class names、tokens、context text を deterministic に生成する。
  4. コード解析エージェント(テキスト) — 入力: source_code + 任意 css_code、出力: semantic_words(5〜10 文字列)。
  5. 埋め込み — configured provider を 1 回、入力 2 つ(deterministic semantic identity、context text)、512 dimensions で呼ぶ。data[0] → semantic、data[1] → context。
  6. ドキュメント組み立て — 出力 1 のロック形状。
  7. DocumentDB write — scoped replace_one(..., upsert=True) と scoped singleton code_index.status=stale を同一 transaction で実行。
  8. result.keywords に semantic_words を載せた成功 Webhook を POST(embeddingDims は常に 512)。

一致する processing.hash がある場合は既存 vector/keyword を再利用し、必要なら preview URL のみ patch して success を送る。部分書き込みは禁止。


出力

出力 1: DocumentDB code コレクション(アップサート)

仕様 §5.2 に一致 — 要約:

{
  "_id": "660e8400-e29b-41d4-a716-446655440001",
  "organization_id": 1,
  "project_id": 42,
  "name": "button-primary",
  "type": 1,
  "based_on": 0,
  "source_code": "<button className='btn btn-primary'>Click me</button>",
  "css_code": ".btn-primary { background:#007bff; }",
  "visual": {
    "metadata": {
      "name": "button-primary",
      "image_url": "s3://bucket/1/42/code/660e8400-e29b-41d4-a716-446655440001.png"
    }
  },
  "semantics": {
    "metadata": { "words": ["submit", "checkout", "transaction", "action", "primary"] },
    "vector_embedding": [/* 512 floats */]
  },
  "context": {
    "metadata": {
      "component_level": "atom",
      "family": "button",
      "variant": "primary",
      "imports": [{"source": "react", "specifiers": [], "default_import": "React", "namespace_import": null}],
      "exports": ["Button"],
      "referenced_components": ["button"],
      "class_names": ["btn-primary"],
      "source_tokens": ["button", "primary", "click"],
      "text": "level=atom family=button variant=primary exports=Button references=button tokens=button primary click"
    },
    "vector_embedding": [/* 512 floats */]
  },
  "processing": {
    "hash": "<64-character SHA-256 fingerprint>"
  }
}
フィールド ルール
visual.metadata.image_url img_url のコピー;スクショなしの場合は null
semantics.metadata.words Code Semantics エージェントの semantic_words と同一
semantics.vector_embedding ちょうど 512 次元 — deterministic semantic identity text の埋め込み
context.metadata level、family、variant、structured imports、exports、references、class names、tokens、canonical text
context.vector_embedding ちょうど 512 次元 — context.metadata.text の埋め込み
processing.hash unchanged import を再利用する stable SHA-256 fingerprint

ベクトルインデックス(packages/models/documentdb/code.py が冪等に作成):

インデックス名 パス 次元 類似度 HNSW m efConstruction
codeSemanticVectorIndex semantics.vector_embedding 512 cosine 16 64
codeContextVectorIndex context.vector_embedding 512 cosine 16 64

出力 2: Webhook — 成功

POST {WEBHOOK_BASE_URL}
Content-Type: application/json
X-API-Key: {WEBHOOK_API_KEY}

{
  "type":      "code-import",
  "recordId":  "660e8400-e29b-41d4-a716-446655440001",
  "projectId": 42,
  "organizationId": 1,
  "status":    "success",
  "result": {
    "keywords":      ["submit", "checkout", "transaction", "action", "primary"],
    "embeddingDims": 512
  }
}
フィールド 備考
type 常に "code-import"
recordId code_id のエコー(UUID 文字列)— 未解決事項
projectId project_id のエコー
organizationId organization_id のエコー
result.keywords semantics.metadata.words と同一
result.embeddingDims 常に 512

出力 3: Webhook — 失敗

POST {WEBHOOK_BASE_URL}
Content-Type: application/json
X-API-Key: {WEBHOOK_API_KEY}

{
  "type":      "code-import",
  "recordId":  "660e8400-e29b-41d4-a716-446655440001",
  "projectId": 42,
  "organizationId": 1,
  "status":    "failed"
}

失敗時は result なし。例外本文は Webhook に含めない(CloudWatch に送る)。

失敗 Webhook は 再送出の前 に送る。


エラーハンドリング

code と variation の import は、一時的な database transaction エラーを指数バックオフと jitter 付きで最大 8 回試行する。毎回新しい session を使い、evidence 書き込みと index 無効化の原子性を維持する。この retry では AI 呼び出しを繰り返さない。永続エラーは直ちに失敗し、再試行上限後は SQS と DLQ に委ねる。Webhook delivery failure も retry 対象の record failure。

シナリオ Webhook(code_id が分かる場合) ワーカー側
エンベロープ不正 / Records なし ❌ ValueError 等
JSON パース不可 ❌ JSONDecodeError
Pydantic 検証 ベストエフォート failed ValidationError
preview reference 不正 failed record failure
セマンティック AgentRunError failed record failure
埋め込み API エラー failed 再送出
DocumentDB 書き込みエラー failed 再送出
Webhook HTTP エラー WARN ログ SQS retry のため record failure

handler は全 record を処理して SQS batchItemFailures を返す。1 record の失敗で同じ batch の後続 record は停止しない。event source mapping では ReportBatchItemFailures が必須。


冪等性

  1. scoped _id replace — evidence 変更時のみ document replace と current index invalidation を原子的に行う。
  2. RDB への書き込みなし — 少なくとも 1 回の Webhook で success が重複し得る。バックエンドは (type, recordId) の重複投稿に耐性を持つ。
  3. fingerprint short circuit — 同一 evidence は既存 vector/keyword を再利用し、preview metadata のみ必要に応じ patch する。

ロックされたパラメータ

パラメータ 値 / 規則 参照
セマンティック単語数 5〜10 個 コード解析の構造化出力
埋め込み次元 512 HNSW + Webhook embeddingDims
埋め込み API 呼び出し 1 回、入力 2 つ semantic identity と deterministic context
Webhook での識別子 "type": "code-import" ai-status ルーティング
HTTP クライアントの Webhook リトライ timeout=10s、retries=2、指数バックオフ 仕様 §2

ロギング(推奨)

イベント レベル タイミング
code_import.received INFO process_record 開始
code_import.parsed INFO Pydantic 検証後
code_import.semantic.done INFO コード解析エージェント後
code_import.embeddings.done INFO configured provider embedding 後
code_import.documentdb.upserted INFO transaction replace/index invalidation 後
code_import.webhook.sent INFO HTTP 2xx 後
code_import.failed ERROR 終端失敗
code_import.webhook.failed WARN Webhook が失敗し、SQS retry 対象

extra に載せるとよい値: code_id、project_id、organization_id、message_id。


未解決事項: recordId の型

解決済み。PostgreSQL code.id、worker code_id、webhook recordId は同じ UUID v4 string で、backend schema も受理する。

未解決事項: ソースサイズ上限

仕様書 §11 の「source_code は推奨 200 KB 以下」— Pydantic で同じ上限を強制するか、バックエンドと合意のうえ共通上限を見直す。


フィールド参照(ルックアップ表)

フィールド SQS 入力 DocumentDB 出力 Webhook 出力
code_id ✓ _id recordId
organization_id ✓ ✓ organizationId
project_id ✓ ✓ projectId
name / type / based_on ✓ ✓ —
source_code / css_code ✓ ✓ —
img_url ✓ visual.metadata.image_url* —
component_level ✓ context.metadata.component_level —
derived family / variant — context.metadata.* —
semantic_words(エージェント) — semantics.metadata.words result.keywords
source parser output — context.metadata.* —
semantics.vector_embedding — ✓ —
context.vector_embedding — ✓ —
stable fingerprint — processing.hash —
status — — success / failed

*field は常に存在し、preview reference がない場合は null。


関連リンク

  • 概要 — 処理フロー、埋め込みの意図、エージェントのコード例、依存関係、シーケンス図。
  • テストケース設計 — 本契約を検証するカタログ。