Replaces ## TODO: Code Quality Issues to Address (lines 182-236) with
## Directory Compliance pointer section linking to the canonical rule
list in .planning/codebase/CONVENTIONS.md#directory-compliance.
Preserved verbatim:
- ### Beta Release Strategy (BRAT workflow, line 66)
- ### Memory Reminders (no Claude/AI references in commits)
CLAUDE.md is gitignored (line 28 of .gitignore) — the file was updated
in-place in the working directory. This commit records the change via
.planning/phases/08-type-hygiene-conventions/08-05-CLAUDE-md-change.md.
Appends ## Directory Compliance to .planning/codebase/CONVENTIONS.md
with 4 rule clusters (DOM API, Lifecycle & Compatibility, Type Hygiene,
Release & Docs) — 16 rule blocks total in the 4-line Don't/Do/Why/Docs
format per D-03. Includes Verifying compliance bash snippet.
Closes DOC-02 part A (single source of truth for directory-compliance
rules; ESLint enforces each rule via eslint.config.mjs).
Deletes the contiguous Phase-8 override block from eslint.config.mjs
(lines 73-113 — the `// Phase 8 — DIR-01 / DIR-09 / DIR-10` headers
and both sub-blocks).
Adds the D-08-extension override (a `src/**/*.ts no-unsafe-*: off`
block) that mirrors the existing `**/*.d.ts no-explicit-any: off`
exclusion's strategy: silence the typed-linting cascade from
ical.js's untyped APIs at the consumption sites, since the root-
cause fix (hand-typing ical.js) is deferred to FRAG-02. The new
override is NOT tied to a scorecard finding — `no-unsafe-*` is
not a DIR-NN rule.
Closes scorecard findings DIR-01, DIR-09, DIR-10 at the acceptance
level: `npm run lint` now passes clean. Remaining narrow overrides:
- Phase-5 tightening (no-unused-vars: error, no-restricted-syntax
for document.createElement)
- `**/*.d.ts` no-explicit-any: off (Plan 02 — ical.d.ts shim)
- `src/**/*.ts` no-unsafe-*: off (this commit — ical.js cascade)
- globalIgnores (node_modules, main.js, build scripts)
See 08-04-CHECKPOINT.md for the Rule-4 architectural escalation
that surfaced this design (Option B was chosen).
Plan 03 added 6 `// eslint-disable-next-line no-console -- DEBUG
flag (Phase 8 D-07)` comments expecting Plan 04 to activate
`no-console` globally. The `no-console` rule is OFF in obsidianmd's
recommended config (not just in the Phase-8 override), so the
disables never had effect — they become "unused eslint-disable
directive" warnings once the Phase-8 override is removed.
Also changes CalendarService.ts:303 from `console.log` to
`console.debug` so it complies with `obsidianmd/rule-custom-message`
(which disallows console.log but allows console.debug). The
MemoChron: prefix convention is preserved.
Removed disables: CalendarService.ts:302,388,407,458 and
timezoneUtils.ts:211,221.
Prepares the tree for the Phase-8 override-block deletion in the
next commit.
Plan 04 paused at a Rule-4 architectural checkpoint when removing the
Phase-8 ESLint override block exposed 33 errors not anticipated by the
original plan (32 typed-linting cascade from ical.js + 1 obsidianmd/
rule-custom-message error on console.log + 6 unused eslint-disable
directives from Plan 03).
User chose Option B from 08-04-CHECKPOINT.md (narrow no-unsafe-* override
mirroring D-08's documented strategy). Amendment:
- files_modified now lists eslint.config.mjs + CalendarService.ts +
timezoneUtils.ts (was eslint.config.mjs only).
- must_haves.truths adds D-08-extension allowance (the new src/**/*.ts
no-unsafe-*: off block) and Class 2/3 housekeeping requirements.
- Single task split into two: Task 1 cleans up Plan 03's wrong-rule
disables and the console.log site; Task 2 deletes the Phase-8
override block and adds the D-08-extension.
See 08-04-CHECKPOINT.md for the full Rule-4 analysis.
Plan 08-04 reached an architectural checkpoint during execution:
deleting the phase-8 ESLint override surfaced 33 errors + 6 warnings
from a typed-linting cascade rooted in ical.d.ts (any returns).
The cascade was not inventoried in 08-RESEARCH.md because the override
block silenced it at inventory time.
CHECKPOINT.md (renamed from SUMMARY.md to keep the plan open) documents
three resolution options. Plan stays incomplete in ROADMAP until the
phase is resumed with a decision on the cascade.
Wave 3 closes DIR-01 at the source level. 33 sites deleted, 6 gated
behind per-file const DEBUG = false in CalendarService.ts and
timezoneUtils.ts. Aggregate: 0 bare console.* in src/; rule-explicit
no-console lint pass clean; npm run lint and npm run build clean.
Plan 04 will remove the global no-console override at eslint.config.mjs;
the per-line eslint-disable directives on the 6 gated sites are in place
so that removal lands clean.
DIR-01 progress (Task 3 of 4). 20 console.* sites deleted across 7 files:
- main.ts (2): invalid-color load-time validation warnings
- services/NoteService.ts (6): all silent-recovery or caller-handles paths
- services/IcsImportService.ts (2): timezone-registration noise (debug/warn)
- settings/SettingsTab.ts (2): missing-custom-settings + lifecycle log
- views/CalendarView.ts (6): all paired with Notice or silent fallback
- views/EmbeddedCalendarView.ts (1): daily-note open failure (Notice paired)
- views/EmbeddedAgendaView.ts (1): daily-note open failure (Notice paired)
Aggregate so far: 30 deleted across these 7 files + Task 1's 10 + Task 2's 3
= 33 deleted; 6 gated (Tasks 1 and 2). Total 39 sites closed (matches the
phase frontmatter must_haves declaration; the plan task header that said
'19 sites total' was off-by-one, the underlying per-file breakdown is 20).
Adjacent cleanup (caused by deletions):
- CalendarView: empty try/catch wrappers collapsed to `catch {}` where the
error binding was solely the deleted console.error argument
- CalendarView event-click .catch: replaced 'Check the console for details'
Notice text with errorMessage(error) inline (the console it referenced
no longer exists — Rule 1 user-visible-signal preservation)
- NoteService.createEventNote: removed useless try/catch wrapper that only
re-threw (no-useless-catch lint error after console.error deletion)
- IcsImportService timezone-registration catch: collapsed if/else branches
whose only difference was console.debug vs console.warn into a single
silent catch {}
DIR-01 progress (Task 2 of 4). 5 console.* sites in timezoneUtils.ts:
- GATE (2): invalid timezone warn (215), catastrophic TZ conversion error (224)
- DELETE (3): toJSDate-failed warn paths (179, 200) and convertTimezone
invalid-zone warn (266) — all fall back silently
Per-file const DEBUG = false at top; each gated site has per-line
eslint-disable-next-line no-console -- DEBUG flag (Phase 8 D-07).
Adjacent cleanup: deleted catch (error) bindings became catch {} where
the binding was solely the deleted console.* argument (matches Wave 1
catch {} convention from D-09). MemoChron: prefix added to the two
gated logs per CONVENTIONS.md §Logging.
DIR-01 progress (Task 1 of 4). 14 console.* sites in CalendarService.ts:
- GATE (4): cache miss (302), non-403/404 HTTP error, fetch catch, Outlook HTML
- DELETE (10): no-enabled-sources, fetch catch wrapper, background refresh
lifecycle, cache save log/error, 403/404 (Notice-paired), invalid data
(Notice-paired), local file read error, platform info debug
Per-file const DEBUG = false at top; each gated site has per-line
eslint-disable-next-line no-console -- DEBUG flag (Phase 8 D-07).
Adjacent cleanup (caused by deletions):
- Removed orphaned logPlatformInfo() method and its call site (function body
was solely the deleted console.debug)
- Removed unused Platform import (only used by the deleted function)
- Outer fetchCalendars catch now catch-less (error binding became unused
after console.error deletion; matches Wave 1's catch {} convention per D-09)
Plan 08-02 closed 18 DIR-09 violations across 10 files in three atomic
commits (413b6f3, e69c2fa, acf4626). Amendments A1 (typed moment import)
and A2 (getValues tightening) both applied. No executable ??-with-constant
LHS violations found in src/.
- pathUtils.ts:47 — wrap case PathType.FILE_URL body in { ... } block scope
(the let normalized declaration leaked across cases without braces)
- viewRenderers.ts:370 — drop unnecessary backslash inside regex character
class: [-\/] -> [-/] (slash does not need escaping inside [...])
Nullish-coalescing audit: grep -rnE '\b(null|undefined|"")\s*\?\?' src/
returned only the documentation-comment hit at SettingsTab.ts:262. No
executable violations.
Per Amendment A1, the 5 (window as any).moment casts get replaced with the
typed import { moment } from "obsidian" (obsidian.d.ts exports moment as
typeof Moment). Removes 5 dead null-check branches that existed only because
the cast was treated as nullable: 4 negative-shape (if (!moment) return) and
1 positive-shape (if (moment) { weekNum = ... } flattened to unconditional).
- CalendarView.ts: 3 sites (checkDailyNoteForDate, renderWeekNumber,
handleDailyNoteClick) — adds moment to existing obsidian import
- EmbeddedCalendarView.ts: 1 site — adds moment to existing obsidian import
- EmbeddedAgendaView.ts: 1 site — adds moment to existing obsidian import
Records the 18 @typescript-eslint/no-unused-vars violations closed,
the two catch-binding conversions, per-symbol grep verifications,
and the two minor deviations (DEFAULT_CALENDAR_URLS export delete
in constants.ts; split into two atomic per-task commits per executor
protocol).
Records BUG-07 closure with Obsidian-side root cause per CONTEXT D-12
step 3 outcome (b). UAT step 3 demonstrated asymmetric behavior: the
Settings modal stays open when MemoChron is disabled (amendment A1's
deletion of detachLeavesOfType from onunload eliminated that trigger),
but closes when MemoChron is re-enabled. The forum thread at
forum.obsidian.md/t/settings-modal-closes-when-disabling-a-plugins-actively-focused-view/111479
confirms the same modal-close reproduces with core plugins (graph view),
demonstrating the remaining trigger is in Obsidian core's
plugin-enable-while-view-focused code path, not in MemoChron.
A1 was the only plugin-side mitigation available — with detachLeavesOfType
removed, the plugin no longer explicitly tears down its workspace leaf on
disable, but Obsidian's automatic leaf cleanup during plugin enable still
runs and triggers the same modal-close path on re-enable. This cannot be
intercepted from plugin code.
07-HUMAN-UAT.md is updated to reference BUG-07-CLOSURE.md from step 3
Notes and to flip SC #5 to PASS (closure note recorded). Phase 7 is
fully complete with BUG-07 status closed-obsidian-side. Phase 8 (Type
Hygiene & Conventions / DOC-02) may begin.