santifer/career-ops · warning

web/src/lib/career-ops.ts not found — web layer moved?…

Error message

web/src/lib/career-ops.ts not found — web layer moved? update contract freeze section

What it means

A warning emitted by the test-all.mjs contract-freeze suite when web/src/lib/career-ops.ts (the web layer's tracker-column parser) does not exist, so the check that it still references the essential tracker columns cannot run. The suite distinguishes absence of the whole web/ tree (expected for data-only installs, see #591) from web/ existing but this specific file being missing or moved. It indicates the web layer's file layout changed and the contract-freeze section is pointing at a stale path.

Solutions

  1. Locate where the web tracker parser now lives (e.g. `fd career-ops web/src`) and update the path in test-all.mjs's contract-freeze section.
  2. If the parser was intentionally removed, update the contract freeze section to guard the new module that owns the tracker-column references.
  3. If web/ should not be in this checkout at all, remove the stale web/ directory so the suite takes the documented data-only-install skip path (#591) instead.
  4. Re-run `node test-all.mjs` to confirm the check now passes or is intentionally skipped.

Example fix

// before (test-all.mjs)
const parserPath = join(ROOT, 'web', 'src', 'lib', 'career-ops.ts');
// after — parser moved into lib/core
const parserPath = join(ROOT, 'web', 'src', 'lib', 'core', 'career-ops.ts');
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs';
const p = join(ROOT, 'web', 'src', 'lib', 'career-ops.ts');
if (existsSync(p)) runContractFreeze(p); else console.warn('parser path moved — locate before updating freeze');

Prevention

When it happens

Trigger: Running `node test-all.mjs` (or the full suite) in a checkout where web/ exists but web/src/lib/career-ops.ts has been renamed, relocated (e.g. into web/src/lib/core/), or deleted, so the suite's existsSync check on that exact path fails.

Common situations: A refactor of the web layer moved the parser module; a contributor deleted the file believing it dead code; pulling a repo state where web/ was partially migrated; maintaining a fork where the web layer was restructured without updating the test's hardcoded path.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@e7abd431fc (2026-09-16). Data as JSON: /api/errors/1d47f0852a5cc805. Report an issue: GitHub.

Appendix: source

Thrown at test-all.mjs:16227

    fail(
      'batch/batch-prompt.md broke the Block B two-pass ordering (#2330): ' +
      `hoistsCvRead=${hoistsCvRead} defersCvRead=${defersCvRead} namesLoadPoint=${namesLoadPoint} cvRowDefers=${cvRowDefers}`,
    );
  }

  // 55.5 cross-check: the web parser still speaks the same column names
  const webParserPath = join(ROOT, 'web', 'src', 'lib', 'career-ops.ts');
  if (existsSync(webParserPath)) {
    const webSrc = readFileSync(webParserPath, 'utf-8');
    const ESSENTIAL_COLS = ['Company', 'Role', 'Score', 'Status'];
    const missingCols = ESSENTIAL_COLS.filter((c) => !webSrc.toLowerCase().includes(c.toLowerCase()));
    if (missingCols.length === 0) {
      pass('web/src/lib/career-ops.ts still references the essential tracker columns');
    } else {
      fail(`web parser no longer references column(s): ${missingCols.join(', ')} — core and web drifted`);
    }
  } else {
    warn('web/src/lib/career-ops.ts not found — web layer moved? update contract freeze section');
  }

  // 55.6 pdf mode must never hand the agent write access (#2185).
  // The web's "pdf" agent tailors content and nothing else: it emits the CV
  // through a <<cv-html>> envelope and the BACKEND writes every file. A write
  // grant here would be unscoped, so a prompt injection in a posting or report
  // (both enter that agent's context) could redirect it at cv.md.
  //
  // Asserted on VALUES — the built argv and the built prompt. FIVE source-text
  // versions of this guard were defeated by rewriting route.ts around them (see
  // web/src/lib/claude-invocation.mjs's header). The one structural rule left is
  // that route.ts may not spell a tool flag itself, which is what stops an inline
  // argv from hiding beside a legitimate claudeCliArgs() call.
  //
  // In the REQUIRED suite on purpose: web-ci.yml is informative-only, so asserting
  // this only there would gate nothing. Importing is safe — these are
  // dependency-free ESM modules and the root suite runs on Node >= 18.
  const webLib = join(ROOT, 'web', 'src', 'lib');

View on GitHub (pinned to e7abd431fc)