ES /docs

ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'spacetimes.summary_text' in 'field list'

RCA: ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'spacetimes.summary_text' in 'field list'

Overview#

What Happened#

2026-08-06 14:27 KST경 cupixvista-api (tesla vista 배포)에서 Api::V1::FacilitiesController#update_spacetime 요청이 spacetimes 테이블에 summary_text 컬럼을 쓰려다 Mysql2::Error: Unknown column 'spacetimes.summary_text' in 'field list' 로 실패했다. 원인은 blue/green 배포 순간의 transient 문제가 아니라, 특정 환경의 DB 에서 spacetimes.summary_text 컬럼이 아예 생성되지 않은 migration version-ordering schema drift 다. 현재 배포된 코드(facility_repository.rb:132)는 항상 이 컬럼을 write 하므로, drift 된 DB 에서는 capture-intelligence-agent 가 생성한 spacetime summary 저장이 결정론적으로 실패한다. 이 결함을 정확히 진단·수정하는 커밋(707aac515 TSLA-13490)은 이미 존재하지만 develop/master 에 미병합이며 배포판 c1c2bbd4 에 포함되어 있지 않다.

Quick Facts#

Field Value
exception.class ActiveRecord::StatementInvalid (rescue 후 Cupix::Errors::Parameter)
exception.message Mysql2::Error: Unknown column 'spacetimes.summary_text' in 'field list'
top_frame vendor/bundle/ruby/3.3.0/gems/mysql2-0.5.4/lib/mysql2/client.rb (_query)
runtime Ruby 3.3.0, Rails (ActiveRecord 7.2), mysql2 0.5.4
deploy production-us-west-2-20260804t0618z0-c1c2bbd4-cupixvista ~ ...20260804t1219z0-c1c2bbd4 (동일 SHA c1c2bbd4)
env production, us-west-2
is_crash false (HTTP 400 로 매핑)

Affected Teams#

cupixvista-api 는 로그 0건이나, 동일 tesla 코드의 cupixworks-api 배포에서 같은 메시지·코드·엔드포인트로 28건 관측되어 영향 범위를 대변한다. 모든 요청은 UA cupix-capture-intelligence-agent 이며 여러 tenant 에 걸쳐 있다 — broad, 결정론적 drift 임을 뒷받침한다.

Team / Domain Error Count (14d, cupixworks-api) Impact
bnbuilders 13 spacetime summary 저장 실패 (동일 spacetime 927107 반복 재시도)
walmart 9 spacetime summary 저장 실패
pclconstruction 2 spacetime summary 저장 실패
southlandind 2 spacetime summary 저장 실패
whitingturner 1 spacetime summary 저장 실패
clark-vdc 1 spacetime summary 저장 실패

Timeline#

  1. 2026-03-10 07:55 KST — 원본 migration 20260306071939_add_summary_to_spacetimes 커밋(TSLA-12069). version 은 20260306071939 로 backdated.
  2. 2026-07-06 13:31 KST — schema drift 를 진단·수정하는 커밋 707aac515 (TSLA-13490) 작성. 브랜치 origin/jarvis/TSLA-13490 에만 존재, 미병합.
  3. 2026-08-06 14:06 KSTcupixworks-api 에서 update_spacetime 400 발생 관측 시작 (14d retention 창 첫 로그).
  4. 2026-08-06 14:27 KSTcupixvista-api ET issue first_seen.
  5. 2026-08-06 14:32 KSTcupixvista-api ET issue last_seen (occurrence 16). cupixworks-api 에서는 14:42 KST 이후로도 계속 발생.

Error Log#

Datadog Logs

text
Mysql2::Error: Unknown column 'spacetimes.summary_text' in 'field list'

Impact#

  • Service: cupixvista-api (tesla vista 배포; 동일 tesla 코드의 cupixworks-api 에서도 동일 발생)
  • 발생 횟수: 16 (ET issue, cupixvista-api)
  • 최초 발생: 2026-08-06 14:27 KST
  • 최근 발생: 2026-08-06 14:32 KST

Root Cause Summary#

spacetimes.summary_text 컬럼을 추가하는 migration 20260306071939_add_summary_to_spacetimes 는 실제로는 2026-03-09 에 커밋되었으나 version timestamp 가 20260306071939backdated 되었다. Rails 는 schema_migrations 의 max version 보다 큰 version 만 실행하므로, 이 migration 이 병합되기 전에 이미 더 높은 version(20260309000001_add_summary_state_columns 등)을 적용한 환경은 backdated migration 을 영영 건너뛴다. 그 결과 db/schema.rb (regenerate 시 컬럼 포함, schema.rb:4126 t.text "summary_text")와 달리 해당 DB 에는 spacetimes.summary_text 컬럼이 존재하지 않는다. 현재 배포 코드 FacilityRepository#update_spacetime 는 summary 저장 시 항상 spacetime.summary_text = spacetime.summary_text_for_search 를 세팅하고 save! 하므로(facility_repository.rb:132,143), drift 된 DB 에서 UPDATE 가 Unknown column 'spacetimes.summary_text' 로 실패한다. 이는 배포 cutover transient 가 아니라 결정론적 schema drift 버그이며, 이미 정확히 진단·수정하는 커밋(707aac515 TSLA-13490, forward-dated idempotent re-add migration)이 있으나 develop/master 에 미병합·미배포 상태다.

Technical Analysis#

Code Path#

  • Entry point: PUT /api/v1/facilities/:key/spacetimes/:spacetime_idApi::V1::FacilitiesController#update_spacetime (route config/routes.rb:1342)
  • Repository: FacilityRepository#update_spacetime (app/repositories/facility_repository.rb:122)
  • Failure point: spacetime.save! (facility_repository.rb:143) — summary_text 컬럼 write 시 MySQL 이 컬럼 부재로 거부
  • 매핑: rescue → Cupix::Errors::Parameter ARG10001 (facility_repository.rb:145) → client_400_error → HTTP 400 (app/controllers/concerns/client_error_controller.rb:10,61)

update_spacetimesummary 파라미터가 있으면 summary_text 컬럼에 flat 검색 텍스트를 미리 저장한다:

app/repositories/facility_repository.rb:122-149ruby
def update_spacetime(spacetime_id, params)
  raise Cupix::Errors::PermissionDenied.new(code: 'PERM10000', reason: 'Permission denied') unless self.model.updatable_by?(self.current_user)

  spacetime = @model.spacetimes.find_by(id: spacetime_id)
  raise Cupix::Errors::NotFound.new(code: 'ARG10002', reason: 'Spacetime not found') if spacetime.nil?

  if params[:summary].present?
    summary = params[:summary].is_a?(ActionController::Parameters) ? params[:summary].permit!.to_h : params[:summary]
    spacetime.validate_summary!(summary)
    spacetime.summary = summary
    spacetime.summary_text = spacetime.summary_text_for_search  # summary_text 컬럼 write
  end

  spacetime.summary_state = params[:summary_state] if params.key?(:summary_state)

  if params.key?(:summary_vector_embedding)
    spacetime.validate_summary_vector_embedding!(params[:summary_vector_embedding])
    spacetime.summary_vector_embedding = params[:summary_vector_embedding]
  end

  begin
    spacetime.save!   # 여기서 Unknown column 'spacetimes.summary_text' 발생
  rescue StandardError => e
    raise Cupix::Errors::Parameter.new(code: 'ARG10001', reason: 'Invalid argument', message: e.message)
  end

  spacetime
end

현재 스키마에는 컬럼이 존재한다 — 즉 코드가 잘못된 컬럼을 참조하는 것이 아니라, 특정 DB 만 컬럼이 누락된 drift 다:

db/schema.rb:4124-4127ruby
t.json "summary"
t.string "summary_state", default: "none", null: false
t.text "summary_text"
t.json "summary_vector_embedding"

원본 migration 은 backdated version 을 가진다:

db/migrate/20260306071939_add_summary_to_spacetimes.rbruby
class AddSummaryToSpacetimes < ActiveRecord::Migration[7.2]
  def change
    change_table :spacetimes, bulk: true do |t|
      t.json :summary
      t.text :summary_text
    end
  end
end

기대 동작: summary 파라미터 저장 시 summary_text 컬럼에 flat text 를 write 하고 200 반환. 실제 동작: drift 된 DB 에서 summary_text 컬럼이 없어 save!Mysql2::Error: Unknown column 으로 실패 → rescue StandardError 가 이를 ARG10001 400 으로 매핑 → agent 의 summary 저장이 조용히 소실.

Log Evidence#

Datadog 쿼리 (cupixvista-api 는 retention 창 내 로그 0건, 동일 코드의 cupixworks-api 로 실증):

text
service:cupixvista-api "summary_text"
text
(service:cupixvista-api OR service:cupixworks-api) "spacetimes.summary_text"

cupixworks-api 에서 28건 관측. 대표 로그 항목(원문):

json
{
  "timestamp": "2026-08-06T05:06:14.171Z",
  "service": "cupixworks-api",
  "status": "info",
  "message": "[400] PUT /api/v1/facilities/rk93lz/spacetimes/1525775 (Api::V1::FacilitiesController#update_spacetime)",
  "attributes": {
    "error": {
      "reason": "Invalid argument",
      "code": "ARG10001",
      "message": "Mysql2::Error: Unknown column 'spacetimes.summary_text' in 'field list'",
      "class": "Cupix::Errors::Parameter"
    },
    "action": "update_spacetime",
    "controller": "Api::V1::FacilitiesController",
    "tenant": "cupix",
    "user_agent": "cupix-capture-intelligence-agent",
    "team": { "domain": "whitingturner", "id": 140 },
    "params": { "fields": ["id","summary","summary_state","facility","record","level"], "key": "rk93lz" }
  },
  "tags": ["version:production-us-west-2-20260805t2305z0-c1c2bbd4-cupixworks"]
}

분포 (14d, cupixworks-api, 위 쿼리 28건):

  • 100% action: update_spacetime, 100% ARG10001 / HTTP 400
  • UA 전부 cupix-capture-intelligence-agent
  • 발생 시각 05:06~05:42+ UTC 로 지속 (transient burst 아님), 여러 tenant(bnbuilders 13, walmart 9, pclconstruction 2, southlandind 2, whitingturner 1, clark-vdc 1)
  • deploy version 3종 전부 동일 SHA c1c2bbd4 (20260805t2305z0, 20260806t0214z0, 20260806t0341z0) → old/new 코드 mismatch 아님
  • 동일 spacetime 927107 (team bnbuilders) 8회 이상 반복 → agent 결정론적 재시도

TSLA-13490 커밋 메시지가 이 정확한 메커니즘을 진단한다:

text
Diagnosis: the column IS defined by 20260306071939_add_summary_to_spacetimes
and IS present in db/schema.rb (spacetimes block, line ~4150) ... The original
migration was committed 2026-03-09 but backdated to a 2026-03-06 version.
Environments that had already applied a higher-version migration (e.g.
20260309000001) before this one merged skipped it, because Rails only runs
migrations with a version greater than max(schema_migrations).

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Migration version-ordering schema drift — backdated migration 20260306071939 이 higher-version 을 이미 적용한 DB 에서 skip 되어 summary_text 컬럼 부재 schema.rb:4126 컬럼 존재하나 코드가 write; 커밋 707aac515(TSLA-13490) 이 동일 메시지·원인 진단; 원본 migration 커밋일 2026-03-09 vs version 20260306071939 backdated; higher-version 20260309000001 존재 Confirmed
H2 blue/green 배포 cutover 시점의 transient schema/code mismatch (ispring acdd2caa 유형) 05:2x UTC 창 발생, is_crash:false 로그가 05:06~05:42+ 지속 발생·다수 tenant·동일 SHA c1c2bbd4 3개 deploy 판 전부에서 재발 → old/new mismatch 아니라 결정론적. regression 필드 부재 Rejected
H3 코드가 존재하지 않는 컬럼을 잘못 참조 (a59d1eba records.name 유형) 메시지 형태 동일 schema.rb:4126 에 컬럼 정의 존재, migration 도 정의 → 코드-스키마는 정합, 특정 DB 만 drift Rejected
H4 client 입력 오류 (noise) HTTP 400 / ARG10001 로 매핑됨 입력 무관 — 서버측 컬럼 부재가 원인. rescue 가 schema 오류를 400 으로 mis-map 한 것일 뿐 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • 이미 작성된 수정 커밋 707aac515 (TSLA-13490, 브랜치 origin/jarvis/TSLA-13490)의 open PR 을 develop/master 로 병합·배포한다. 이 커밋은 forward-dated idempotent migration 20260613000000_readd_summary_columns_to_spacetimes 를 추가하여 drift 된 DB 에서만 summary/summary_text 컬럼을 조건부 재생성하고, 이미 있는 환경에서는 no-op 이다 (column_exists? 가드 사용). 본 클러스터는 신규 코드 작업이 아니라 미병합 PR 병합으로 해소되는 duplicate 성격이다.
db/migrate/20260613000000_readd_summary_columns_to_spacetimes.rb (from 707aac515)ruby
class ReaddSummaryColumnsToSpacetimes < ActiveRecord::Migration[7.2]
  def change
    change_table :spacetimes, bulk: true do |t|
      t.json :summary unless column_exists?(:spacetimes, :summary)
      t.text :summary_text unless column_exists?(:spacetimes, :summary_text)
    end
  end
end

단기 개선 (1주 이내)#

  • update_spacetimerescue StandardError => e → ARG10001(400) (facility_repository.rb:144-145)이 schema 오류·DB 오류 등 server-side 결함을 client 400 으로 뭉뚱그려 오분류한다. ActiveRecord::StatementInvalid 같은 서버측 예외는 5xx 로 표면화하도록 rescue 를 좁혀, 이런 drift 가 400 뒤에 숨어 조용히 데이터 소실되는 것을 방지한다 (프런트/agent 응답 계약 조율 필요).

장기 개선 (재발 방지)#

  • migration version backdating 금지 규칙 + CI 검증: db/schema.rb 에 존재하는 컬럼이 실제 target 환경 DB 에 모두 반영되는지 배포 파이프라인에서 schema_migrations 정합성(drift) 검사.
  • 컬럼 추가 migration 은 version 이 반드시 병합 시점 기준 최신이 되도록 강제(pre-merge lint), 또는 idempotent column_exists? 가드 패턴을 컬럼 추가 migration 표준으로 채택.

Monitoring#

배포 후 재발 여부 확인 (release dashboard timeseries widget 용):

text
service:cupixvista-api "Unknown column 'spacetimes.summary_text'"
text
(service:cupixvista-api OR service:cupixworks-api) "spacetimes.summary_text" @action:update_spacetime
text
(service:cupixvista-api OR service:cupixworks-api) @action:update_spacetime @error.code:ARG10001

Risk Assessment#

  • Risk level: medium (사용자 500 은 아니나 agent 의 spacetime summary 저장이 조용히 소실 → capture intelligence 검색/요약 데이터 결손)
  • 예상 복잡도: trivial (idempotent migration 병합·배포; 코드 로직 변경 없음)

Noise Verdict#

bug — spacetimes.summary_text 컬럼이 backdated migration 누락으로 특정 DB 에 아예 없어 agent 의 summary 저장이 결정론적으로 실패하는 진짜 schema drift 결함이며, 이미 진단·수정된 미병합 PR(TSLA-13490)을 배포하면 해소된다.