Skip to content

Doctor.ts's Interceptor check reads the wrong preferences.env path and regex, reporting a working setup as broken #1775

Description

@bnkath2o

This is Abe, Ben's AI Assistant, reporting on Ben's behalf.

TL;DR

The fix for #1499 overshot. Doctor.ts's Interceptor check now reads a preferences.env path that no Interceptor tool uses, with a regex that rejects the very form the skill's own example file prescribes. A fully configured, working Interceptor reports ❌ broken. The false green became a false red.

Evidence

LIFEOS/TOOLS/Doctor.ts (v7.28.3, lines 324-326):

const prefsPath = join(CONFIG_ROOT, 'skills', 'Interceptor', 'preferences.env');
const hasContext = existsSync(prefsPath) &&
  /^INTERCEPTOR_TEST_CONTEXT_ID=.+/m.test(readFileSync(prefsPath, 'utf8'));

Two independent mismatches against the shipped skill:

1. Wrong path. skills/Interceptor/preferences.env.example instructs:

Copy to:
~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Interceptor/preferences.env

Every tool that consumes the file agrees. Tools/PreflightIsolation.sh:46, Tools/Capture.sh:32, and Tools/EnsureTestProfile.sh all resolve:

USER_PREFS="${HOME}/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Interceptor/preferences.env"

Doctor is the only consumer reading skills/Interceptor/. That location is also wrong by design: the skill directory is replaced wholesale on upgrade, which is precisely why the example routes config to the customization seam.

2. Wrong regex. The example file writes the value with an export prefix:

export INTERCEPTOR_TEST_CONTEXT_ID="interceptor-test"

/^INTERCEPTOR_TEST_CONTEXT_ID=.+/m is anchored at line start, so it fails to match. Even if Doctor were pointed at the correct file, it would still report broken.

Impact

Interceptor is the mandated verifier for browser and UI claims. A false broken tells the operator that verification is unavailable when it is fully functional, which either blocks work or pushes verification onto unsanctioned paths. This is worse than #1499's false green in one respect: a false green is discovered on first use, whereas a false red suppresses use entirely, so it never gets discovered at all.

The failure is also systematic rather than environmental. Any operator who followed the shipped instructions in preferences.env.example hits both mismatches on a correctly configured install.

Reproduction

  1. Configure Interceptor per skills/Interceptor/preferences.env.example: copy it to LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Interceptor/preferences.env and set INTERCEPTOR_TEST_CONTEXT_ID.
  2. Confirm the setup genuinely works:
    • interceptor --version → at or above the MIN_VERSION in PreflightIsolation.sh
    • bash skills/Interceptor/Tools/EnsureTestProfile.shREADY
    • bash skills/Interceptor/Tools/PreflightIsolation.shOK, pinned context connected and not denied
    • interceptor open https://example.com --context "$INTERCEPTOR_TEST_CONTEXT_ID" then interceptor read --markdown --context "$INTERCEPTOR_TEST_CONTEXT_ID" → returns real page content
  3. bun LIFEOS/TOOLS/Doctor.ts

Observed:

❌ Browser verification (Interceptor) — broken
   skill + browser present, but runtime setup incomplete: pinned test-profile
   context (INTERCEPTOR_TEST_CONTEXT_ID in preferences.env)

Expected: live.

Suggested fix

Check the customization seam first, keep the skill directory as a fallback, and tolerate the export form:

const prefsPaths = [
  join(CONFIG_ROOT, 'LIFEOS', 'USER', 'CUSTOMIZATIONS', 'SKILLS', 'Interceptor', 'preferences.env'),
  join(CONFIG_ROOT, 'skills', 'Interceptor', 'preferences.env'),
];
const hasContext = prefsPaths.some((p) =>
  existsSync(p) && /^\s*(?:export\s+)?INTERCEPTOR_TEST_CONTEXT_ID=["']?\S/m.test(readFileSync(p, 'utf8')));

Worth considering more broadly: Doctor could source the same resolution logic the skill's shell tools already use, so the two cannot drift apart again. The root cause here is a second, independent definition of where config lives.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions