Skip to content

Code Analysis Change Questions

Tu Shaokun edited this page Nov 6, 2026 · 4 revisions

Paired source questions

Draft #1229 isolates fresh before/after orientation for one required JS/TS source entry. Candidate b6ad7bfc6aaaf47b9f72e8609d96bea008603741 builds on #1227 c4374a78fd57e27c137673e624e4b3aa4ed7c5ff; both are unmerged experiments. This page records selected source answers, the corresponding tool evidence and remaining gaps. It does not measure general accuracy or reader benefit.

The command captures two existing roots with the current TypeScript extractor and one analysis configuration. It keeps source text and positions, lexical call references and module-import reading locations separate. The output is an intermediate artifact for the function analysis workflow, not a completed semantic review.

Source answers and observed results

Expected source changes were read before candidate scans. Redux cases use project roots with analysis include: ["src/**"], retaining the root compiler configuration while capturing 17 files. Commander uses default filters (149 files), except the explicit declaration case with exclude: [] (150 files). These selections do not cover every Git change.

Question Source-backed answer Observed orientation and boundary
What did Redux expose publicly? 85d7f27a → c9e06506 imports the existing default helper at src/index.ts:8 and exports it publicly as isPlainObject at line 48. The implementation is unchanged. Selecting the helper yields zero changed definitions, but incoming module-reading references increase 3→4. Selecting index.ts shows a file text change with no function changes. Read the export source to establish the public name; an import edge alone does not establish it.
What behavior did Redux #4633 change? 0e8a7b00 → cfc31458 adds the null-prototype alternative to the helper's return predicate. Independent execution of this inspected helper confirms Object.create(null): false→true. One function-text change, with three source-confirmed lexical references on each side: combineReducers:33, createStore:271, utils/isAction:6. Source-contained unresolved member calls increase 3→4. The references identify reading locations; they do not prove each runtime path reaches the changed case.
Does a function-text change prove behavior changed? 66f955f7 → 50b01021 only wraps the same return predicate in parentheses across lines. The ten controlled helper observations are identical. Still one function-text change, as intended. End line shifts 14→16; three lexical references and four unresolved member calls remain. Here the createStore callsite is line 272 on both sides. This is a control against reading text differences as semantic differences.
How does Commander's new hook enter dispatch? 3ae30a29 → 2c7f687e adds the pre-subcommand hook path. Read registration at lib/command.js:401–411, dispatch at 1053–1066, the member call at 1058 and the new _chainOrCallSubCommandHook body at 1202–1212. The callback hook(this, subCommand) is at 1207. The new method is unpaired; its callback stays unresolved and it has zero supported lexical references despite the source member caller. Four default-captured files change, with two changed definition pairs and five unpaired records. Four of those records are duplicate write slots across the two sides, not four added functions.
What about Commander's public hook type? The same commit adds preSubcommand to HookEvent in typings/index.d.ts:268. This is a declaration change and requires reading that diff. With declaration inclusion explicit, both sides report definitionCoverage: declaration-file-unsupported, partial status and exit 1. Zero measured function changes is not evidence of an unchanged type contract.
What happens for identical inputs? Redux's fixed cfc31458 root is used as both sides. No file or definition changes; snapshot IDs match. This checks empty-change handling, not runtime completeness.

The helper behavior check executes only the inspected TypeScript function after type erasure, with plain objects, null-prototype objects, a plain object from another VM context, arrays, dates, null, undefined, numbers, functions and custom-prototype objects. It is not a full Redux build or released-package test. The formatting control's equal observations support this finite input set; source inspection explains why the predicate is unchanged.

Capture, compatibility and limits

Both sides use adapter revision 9 and js-ts-lexical-v2. An optional capture observer exposes effective compiler options and actually read configuration/package inputs. It preserves raw facts and snapshot fingerprints against the parent on the fixed Redux and Commander heads.

The explicit entry limits definition selection; references search captured files. Unique file/qualified-name/syntax-kind slots are reading pairs, not persistent IDs. Renames, moves and duplicate slots stay unpaired. Unavailable source suppresses trusted navigation. Changed compiler or package inputs limit attribution even when their edits may be irrelevant; matching observed settings do not prove identical runtime environments or source candidates.

A reproduced local-prototype gap discarded explicit declaration coverage and returned ready with zero function changes. This port includes the correction: declaration coverage is retained in both the artifact and JSON receipt. Unsupported definitions remain available as source-reading work, not silently counted as fully analyzed.

Every list reports total/included/omitted at a 40-item cap. Ready means usable orientation, not zero omissions or complete impact. Paired mode requires installed analyzer dependencies, writes outside both source roots, does not run the analyzed application and does not persist a raw-facts directory. Automatic entry selection, JSON inventory, UI, semantic diffing and complete/transitive impact remain outside this slice.

Validation record

  • Exact parent CLI rejects --base-root; 44 focused tests and all 278 module tests pass on the candidate with official Node 22.23.2 and Python 3.13.16.
  • The initial symlink-TMPDIR snapshot fixture also fails on the exact parent. Physical TMPDIR passes; no product workaround was added.
  • Seven normal paired CLI cases pass, including the implementation/declaration distinction. Both raw-fact controls remain byte-identical to the parent.
  • The archive repeats byte for byte: SHA256 a9de1aed12ce0d3a9bb825aaa93c0555f063beb1291584695208e344bf8a85c0. All seven paired outputs and both raw-fact controls match source and unpacked archive.
  • The first real-case evaluator misspelled the Commander method name. Direct source confirmed _chainOrCallSubCommandHook; the evaluator was corrected and rerun without a product edit.
  • A fresh public fetch reran all seven paired cases, the independent helper check and both raw-fact/archive controls successfully. Analyzer checkouts use sparse paths to avoid downloading unrelated repository artifacts; target source checkouts are complete.
  • CI completed with the same sole README Classic motion-proof digest failure independently reproduced on exact Labs bf0a29e7; expected and actual hashes match. All other executed jobs passed, including Code Analysis, ZIP freshness, package smoke and Windows portability. The aggregate Node 22 failure follows that regression; CI is not green.

These are source-first checks by the implementing agent. They are not independent reader trials, proof of production quality or a general accuracy rate. The next useful checks are answers that require configuration context, unsupported dispatch or multiple source entries; simply counting more references would not establish a better answer.

Reproduce

Use Bash, Git, Node 22, npm and unzip. The script fetches every fixed revision from public GitHub, installs only analyzer dependencies in temporary checkouts, runs the selected helper behavior probe and normal CLI checks, then compares the committed unpacked archive. No target project dependencies or live Archify installation are changed. The printed evidence directory contains complete JSON artifacts and receipts.

Public fetch, assertions and archive comparison
#!/usr/bin/env bash
set -euo pipefail
node -e 'if (Number(process.versions.node.split(".")[0]) !== 22) throw Error("Use Node 22")'
w=$(mktemp -d "${TMPDIR:-/tmp}/archify-paired-public.XXXXXXXX")
w=$(cd "$w" && pwd -P)
export TMPDIR=$(cd "${TMPDIR:-/tmp}" && pwd -P)
printf 'Evidence workspace: %s\n' "$w"
fetch() {
  name=$1; repository=$2; revision=$3; shift 3
  git init -q "$w/$name"
  git -C "$w/$name" remote add origin "https://github.com/$repository.git"
  if [ "$#" -gt 0 ]; then
    git -C "$w/$name" sparse-checkout init --no-cone
    git -C "$w/$name" sparse-checkout set --no-cone "$@"
    git -C "$w/$name" -c http.version=HTTP/1.1 fetch -q --depth 1 --filter=blob:none origin "$revision"
  else
    git -C "$w/$name" -c http.version=HTTP/1.1 fetch -q --depth 1 origin "$revision"
  fi
  git -C "$w/$name" -c http.version=HTTP/1.1 checkout -q --detach FETCH_HEAD
  test "$(git -C "$w/$name" rev-parse HEAD)" = "$revision"
}
fetch analyzer tt-a1i/archify b6ad7bfc6aaaf47b9f72e8609d96bea008603741 '/archify/' '/archify.zip'
fetch parent tt-a1i/archify c4374a78fd57e27c137673e624e4b3aa4ed7c5ff '/archify/'
fetch redux-base reduxjs/redux 85d7f27a0f017c80798207b5e799899078a90ca0
fetch redux-head reduxjs/redux c9e06506f88926e252daf5275495eba0c04bf8e3
fetch commander-base tj/commander.js 3ae30a291a777ad1f748d86f49903579277f9ea0
fetch commander-head tj/commander.js 2c7f687eaea6e7b29b917db8d71a06fe6fbfb53e
fetch redux-fix-base reduxjs/redux 0e8a7b00db58796f7a7adef6ac9ebed9420c18cb
fetch redux-fix-head reduxjs/redux cfc31458f87a74b682865940726444533aa3a163
fetch redux-format-base reduxjs/redux 66f955f764cb8e1a21ce42f8e4c522cdb87d056a
fetch redux-format-head reduxjs/redux 50b010210df25c470386f7e39a9389a4a77b3842
for name in analyzer parent; do
  (cd "$w/$name/archify/modules/code-analysis" && npm ci --ignore-scripts --no-audit --no-fund)
done
export EVIDENCE_ROOT="$w/evidence" NEW_SOURCES="$w" OLD_SOURCES="$w"
export PARENT_CLI="$w/parent/archify/bin/archify.mjs"
export ANALYZER_PACKAGE="$w/analyzer/archify/modules/code-analysis/package.json"
mkdir "$EVIDENCE_ROOT"
cat > "$w/verify-pairs.mjs" <<'NODE_VERIFY'
import fs from 'node:fs';
import path from 'node:path';
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';

const e = process.env.EVIDENCE_ROOT;
const w = process.env.NEW_SOURCES;
const old = process.env.OLD_SOURCES;
const cli = process.argv[2];
const label = process.argv[3] || 'candidate';
const prior = process.env.PARENT_CLI;
const config = `${e}/src-only.json`, declarations = `${e}/include-declarations.json`;
fs.mkdirSync(e, { recursive: true });
fs.writeFileSync(config, JSON.stringify({ include: ['src/**'] }) + '\n');
fs.writeFileSync(declarations, JSON.stringify({ exclude: [] }) + '\n');
const pins = {
  [`${old}/redux-base`]: '85d7f27a0f017c80798207b5e799899078a90ca0',
  [`${old}/redux-head`]: 'c9e06506f88926e252daf5275495eba0c04bf8e3',
  [`${old}/commander-base`]: '3ae30a291a777ad1f748d86f49903579277f9ea0',
  [`${old}/commander-head`]: '2c7f687eaea6e7b29b917db8d71a06fe6fbfb53e',
  [`${w}/redux-fix-base`]: '0e8a7b00db58796f7a7adef6ac9ebed9420c18cb',
  [`${w}/redux-fix-head`]: 'cfc31458f87a74b682865940726444533aa3a163',
  [`${w}/redux-format-base`]: '66f955f764cb8e1a21ce42f8e4c522cdb87d056a',
  [`${w}/redux-format-head`]: '50b010210df25c470386f7e39a9389a4a77b3842',
};
const hash = value => createHash('sha256').update(value).digest('hex');
function command(program, args, expectedExit = 0) {
  const r = spawnSync(program, args, { encoding: 'utf8', timeout: 180000, maxBuffer: 1024 * 1024 });
  assert.equal(r.status, expectedExit, r.stderr || r.stdout || String(r.error));
  return r;
}
for (const [root, revision] of Object.entries(pins)) {
  assert.equal(command('git', ['-C', root, 'rev-parse', 'HEAD']).stdout.trim(), revision);
  assert.equal(command('git', ['-C', root, 'status', '--porcelain', '--untracked-files=no']).stdout, '');
}
const helper = 'src/utils/isPlainObject.ts';
const cases = [
  { name: 'redux-public-helper', base: `${old}/redux-base`, head: `${old}/redux-head`, entry: helper, config },
  { name: 'redux-public-index', base: `${old}/redux-base`, head: `${old}/redux-head`, entry: 'src/index.ts', config },
  { name: 'redux-fix', base: `${w}/redux-fix-base`, head: `${w}/redux-fix-head`, entry: helper, config },
  { name: 'redux-format', base: `${w}/redux-format-base`, head: `${w}/redux-format-head`, entry: helper, config },
  { name: 'redux-unchanged', base: `${w}/redux-fix-head`, head: `${w}/redux-fix-head`, entry: helper, config },
  { name: 'commander-implementation', base: `${old}/commander-base`, head: `${old}/commander-head`, entry: 'lib/command.js' },
  { name: 'commander-declaration', base: `${old}/commander-base`, head: `${old}/commander-head`, entry: 'typings/index.d.ts', config: declarations, partial: true },
];
const results = [];
for (const c of cases) {
  const out = `${e}/${label}-${c.name}.json`;
  const args = [cli, 'code-analysis', 'task', '--question', 'Which source behavior or contract changed, what evidence supports it, and what remains unknown?', '--base-root', c.base, '--root', c.head, '--entry', c.entry, '--format', 'json', '--out', out, '--json'];
  if (c.config) args.push('--config', c.config);
  const r = command(process.execPath, args, c.partial ? 1 : 0);
  fs.writeFileSync(`${out}.receipt.json`, r.stdout); fs.writeFileSync(`${out}.stderr`, r.stderr);
  const brief = JSON.parse(fs.readFileSync(out)), receipt = JSON.parse(r.stdout);
  assert.equal(brief.stage, 'orientation-only'); assert.equal(brief.status, c.partial ? 'partial' : 'ready');
  assert.deepEqual(brief.definitionCoverage, { base: c.partial ? 'declaration-file-unsupported' : 'available', head: c.partial ? 'declaration-file-unsupported' : 'available' });
  assert.deepEqual(receipt.definitionCoverage, brief.definitionCoverage); assert.equal(receipt.evidence, brief.status);
  assert.equal(brief.comparison.sourceText, 'reading-signals-only');
  assert.equal(brief.comparison.bindingAttribution, 'same-observed-settings');
  for (const side of ['base', 'head']) { assert.equal(brief.sides[side].callModel, 'js-ts-lexical-v2'); assert.equal(brief.sides[side].snapshot.adapterRevision, 9); }
  if (c.name.startsWith('redux-public')) {
    assert.deepEqual(brief.fileChanges.items.map(x => x.file), ['src/index.ts']);
    assert.equal(brief.changedDefinitions.total, 0); assert.equal(brief.unpairedDefinitions.total, 0); assert.equal(brief.positionOnlyDefinitions.total, 0);
    if (c.name.endsWith('helper')) {
      assert.equal(brief.moduleReading.base.resolvedReferences.total, 3); assert.equal(brief.moduleReading.head.resolvedReferences.total, 4);
      assert.ok(brief.moduleReading.head.resolvedReferences.items.some(x => x.fact.from === 'src/index.ts' && x.fact.line === 8 && x.navigation.status === 'valid'));
    }
  }
  if (c.name === 'redux-fix' || c.name === 'redux-format') {
    assert.deepEqual(brief.fileChanges.items.map(x => x.file), [helper]); assert.equal(brief.changedDefinitions.total, 1);
    assert.equal(brief.positionOnlyDefinitions.total, 0); assert.equal(brief.unpairedDefinitions.total, 0);
    const change = brief.changedDefinitions.items[0]; assert.equal(change.pairing, 'unique-exact-source-slot');
    for (const side of ['base', 'head']) {
      const d = change[side]; assert.equal(d.definition.name, 'isPlainObject'); assert.equal(d.definition.line, 5);
      assert.equal(d.definition.endLine, c.name === 'redux-format' && side === 'head' ? 16 : 14);
      assert.equal(d.knownReferences.total, 3); assert.ok(d.knownReferences.items.every(x => x.navigation.status === 'valid'));
      assert.deepEqual(d.knownReferences.items.map(x => [x.fact.file, x.fact.line]), [['src/combineReducers.ts', 33], ['src/createStore.ts', c.name === 'redux-format' ? 272 : 271], ['src/utils/isAction.ts', 6]]);
      assert.equal(d.unresolvedWithinSourceRange.total, c.name === 'redux-fix' && side === 'base' ? 3 : 4);
      assert.ok(d.unresolvedWithinSourceRange.items.every(x => x.fact.resolution === 'unresolved'));
    }
  }
  if (c.name === 'redux-unchanged') {
    for (const key of ['fileChanges', 'changedDefinitions', 'positionOnlyDefinitions', 'unpairedDefinitions']) assert.equal(brief[key].total, 0);
    assert.equal(brief.sides.base.snapshot.snapshotId, brief.sides.head.snapshot.snapshotId);
  }
  if (c.name === 'commander-implementation') {
    assert.deepEqual(brief.fileChanges.items.map(x => x.file), ['examples/hook.js', 'lib/command.js', 'tests/command.hook.test.js', 'typings/index.test-d.ts']);
    const added = brief.unpairedDefinitions.items.find(x => x.side === 'head' && x.definition.name === '_chainOrCallSubCommandHook');
    assert.ok(added); assert.equal(added.definition.line, 1202); assert.equal(added.definition.endLine, 1212); assert.equal(added.knownReferences.total, 0);
    assert.ok(added.unresolvedWithinSourceRange.items.some(x => x.fact.line === 1207 && x.fact.resolution === 'unresolved'));
  }
  if (c.partial) {
    assert.equal(brief.changedDefinitions.total, 0); assert.equal(brief.unpairedDefinitions.total, 0);
    assert.ok(brief.comparison.reasons.some(x => x.code === 'definition-regions-unsupported'));
    assert.ok(brief.fileChanges.items.some(x => x.file === c.entry && x.status === 'text-changed'));
  }
  if (label === 'archive') assert.equal(hash(fs.readFileSync(out)), hash(fs.readFileSync(`${e}/candidate-${c.name}.json`)), `${c.name}: paired orientation archive parity`);
  results.push({ name: c.name, base: pins[c.base], head: pins[c.head], entry: c.entry, status: brief.status, sourceFiles: { base: brief.sides.base.capturedFiles, head: brief.sides.head.capturedFiles }, fileChanges: brief.fileChanges.total, changedDefinitions: brief.changedDefinitions.total, unpairedDefinitions: brief.unpairedDefinitions.total, ...(label === 'archive' ? { archiveParity: true } : {}) });
  console.log(JSON.stringify(results.at(-1)));
}
const preservation = [];
for (const c of [cases[0], cases[5]]) {
  const root = c.head, name = c.name.startsWith('redux') ? 'redux' : 'commander';
  for (const [which, program] of label === 'candidate' ? [['parent', prior], [label, cli]] : [[label, cli]]) {
    const out = `${e}/facts-${name}-${which}`;
    const args = [program, 'code-analysis', 'check', root, '--language', 'ts', '--fail-on', 'never', '--out', out, '--json'];
    if (c.config) args.push('--config', c.config);
    const r = command(process.execPath, args);
    fs.writeFileSync(`${out}.receipt.json`, r.stdout); fs.writeFileSync(`${out}.stderr`, r.stderr);
  }
  const raw = fs.readFileSync(`${e}/facts-${name}-${label}/raw-facts.json`);
  assert.equal(hash(raw), hash(fs.readFileSync(`${e}/facts-${name}-parent/raw-facts.json`)), `${name}: raw facts changed from parent`);
  if (label === 'archive') assert.equal(hash(raw), hash(fs.readFileSync(`${e}/facts-${name}-candidate/raw-facts.json`)));
  preservation.push({ project: name, sourceRevision: pins[root], exactRawFactsUnchanged: true, sha256: hash(raw) });
}
fs.writeFileSync(`${e}/${label}-results.json`, JSON.stringify({ node: process.version, questions: results, preservation }, null, 2) + '\n');
console.log(JSON.stringify({ preservation }));
NODE_VERIFY
cat > "$w/runtime-oracle.mjs" <<'NODE_RUNTIME'
import fs from 'node:fs';
import path from 'node:path';
import vm from 'node:vm';
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';

const e = process.env.EVIDENCE_ROOT;
const w = process.env.NEW_SOURCES;
const require = createRequire(process.env.ANALYZER_PACKAGE);
const ts = require('typescript');
const pins = {
  "redux-fix-base": "0e8a7b00db58796f7a7adef6ac9ebed9420c18cb",
  "redux-fix-head": "cfc31458f87a74b682865940726444533aa3a163",
  "redux-format-base": "66f955f764cb8e1a21ce42f8e4c522cdb87d056a",
  "redux-format-head": "50b010210df25c470386f7e39a9389a4a77b3842"
};
const results = [];
for (const [name, revision] of Object.entries(pins)) {
  const source = fs.readFileSync(`${w}/${name}/src/utils/isPlainObject.ts`, 'utf8');
  const output = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.CommonJS }, reportDiagnostics: true });
  assert.deepEqual(output.diagnostics, []);
  const filename = `${w}/${name}-isPlainObject.cjs`;
  fs.writeFileSync(filename, output.outputText);
  const isPlainObject = require(filename).default;
  const cases = [
    ['plain-object', {}, true],
    ['null-prototype', Object.create(null), name !== 'redux-fix-base'],
    ['foreign-plain-object', vm.runInNewContext('({})'), true],
    ['array', [], false], ['date', new Date(0), false], ['null', null, false],
    ['undefined', undefined, false], ['number', 1, false],
    ['function', function controlled() {}, false], ['custom-prototype', Object.create({}), false],
  ];
  const observations = cases.map(([input, value, expected]) => {
    const actual = isPlainObject(value); assert.equal(actual, expected, `${name}: ${input}`);
    return { input, result: actual };
  });
  results.push({ name, revision, sourceSha256: createHash('sha256').update(source).digest('hex'), observations });
}
assert.deepEqual(results[2].observations, results[3].observations);
fs.writeFileSync(`${e}/runtime-results.json`, JSON.stringify({ node: process.version, typescript: ts.version, scope: 'Executed only the inspected helper after TypeScript type erasure; no full build, released package or whole-program claim.', versions: results }, null, 2) + '\n');
console.log(JSON.stringify({ versions: results.map(x => ({ name: x.name, nullPrototype: x.observations.find(c => c.input === 'null-prototype').result, cases: x.observations.length })), formatControlUnchanged: true }));
NODE_RUNTIME
node "$w/runtime-oracle.mjs"
node "$w/verify-pairs.mjs" "$w/analyzer/archify/bin/archify.mjs" candidate
node -e 'const fs=require("node:fs"),crypto=require("node:crypto");const h=crypto.createHash("sha256").update(fs.readFileSync(process.argv[1])).digest("hex");if(h!=="a9de1aed12ce0d3a9bb825aaa93c0555f063beb1291584695208e344bf8a85c0")throw Error(h)' "$w/analyzer/archify.zip"
unzip -q "$w/analyzer/archify.zip" -d "$w/unpacked"
(cd "$w/unpacked/archify/modules/code-analysis" && npm ci --ignore-scripts --no-audit --no-fund)
node "$w/verify-pairs.mjs" "$w/unpacked/archify/bin/archify.mjs" archive
printf 'PASS: seven paired cases, two unchanged-fact controls, helper behavior and archive parity; evidence: %s\n' "$EVIDENCE_ROOT"

Inherited scope correction

Parameter-default scope verification records the inherited false-target correction and updated #1229 head 3dda561d, v2 / revision 11. All 280 module tests, seven paired cases and two raw-fact controls pass; source/archive outputs agree. Earlier receipts above remain tied to their recorded head.

Vite follow-up

The Vite configuration study uses current head 3dda561d to follow one changed merge helper through unchanged wrappers. Two intentional error fixtures produce explicit partial capture; the helper matrix, independent source reading and fresh public archive comparison retain the distinction between merge values and application behavior.

Clone this wiki locally