Skip to content
Astera Technology

Why did an internal migration column appear in the export?

Keep the export projection explicit across target schema changes.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original export contract contains a, b only. A view built with SELECT * changes its shape when internal is added to the underlying table. Corrected view names a, b and keeps the internal value outside this export, including when there are no records.

Filled synthetic input
RecordInput JSON
Base input{"records":[{"a":"A","b":2,"internal":"secret"}]}
Download editable CSV ↓

Compare the actual paths

The bad export leaks a third column secret. Correct output retains two declared columns; column metadata is checked beside rows so an empty result cannot hide the schema change.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"columns":["a","b","internal"],"records":[{"a":"A","b":2,"internal":"secret"}]}
Corrected path{"columns":["a","b"],"records":[{"a":"A","b":2}]}
Download editable CSV ↓
Local Node.js program: 22.23.3 or 24.14.1
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};

import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
    const db=new DatabaseSync(':memory:');try{db.exec('CREATE TABLE target(a TEXT,b INTEGER);CREATE VIEW export AS SELECT '+(corrected?'a,b':'*')+' FROM target;');
      db.exec('ALTER TABLE target ADD COLUMN internal TEXT;');
      for(const r of i.records)db.prepare('INSERT INTO target VALUES(?,?,?)').run(r.a,r.b,r.internal);
      const stmt=db.prepare('SELECT * FROM export');return {columns:stmt.columns().map(c=>c.name),records:stmt.all().map(r=>({...r}))};
    }finally{db.close();}
  };
const cases=[{"label":"misleading base","input":{"records":[{"a":"A","b":2,"internal":"secret"}]},"expected":{"columns":["a","b","internal"],"records":[{"a":"A","b":2,"internal":"secret"}]},"corrected":false},{"label":"corrected base","input":{"records":[{"a":"A","b":2,"internal":"secret"}]},"expected":{"columns":["a","b"],"records":[{"a":"A","b":2}]},"corrected":true},{"label":"null internal value remains excluded","input":{"records":[{"a":"A","b":0,"internal":null}]},"expected":{"columns":["a","b"],"records":[{"a":"A","b":0}]},"corrected":true},{"label":"empty dataset still has export shape","input":{"records":[]},"expected":{"columns":["a","b"],"records":[]},"corrected":true}];
for(const test of cases){
  const actual=run(test.input,test.corrected);
  assert.deepEqual(actual,test.expected,test.label);
  console.log(test.label,actual);
}
Download runnable example ↓

Check boundaries before the next load

A null internal value is still excluded. Empty data retains the two-column export definition.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Null internal value remains excluded{"records":[{"a":"A","b":0,"internal":null}]}{"columns":["a","b"],"records":[{"a":"A","b":0}]}
Empty data with explicit shape{"records":[]}{"columns":["a","b"],"records":[]}
Download editable CSV ↓

Does an empty export prove its column contract stayed unchanged?

Show the worked answer

No. Inspect the columns too. Corrected empty output still declares exactly a, b.

Related resources