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
- 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.
- If the parser was intentionally removed, update the contract freeze section to guard the new module that owns the tracker-column references.
- 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.
- 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
- Centralize hardcoded web paths in one SYSTEM_PATHS-style constant shared by all freeze checks.
- When moving web files, grep test-all.mjs for the old path before deleting it.
- Prefer deriving the parser path from a package export or glob rather than a literal.
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)