chore: merge executor worktree (worktree-agent-ad1b2de59871ef5b9)
This commit is contained in:
@@ -31,6 +31,9 @@ jobs:
|
||||
- name: Format check
|
||||
run: pnpm format:check
|
||||
|
||||
- name: Markdown lint
|
||||
run: pnpm md:lint
|
||||
|
||||
- name: Typecheck
|
||||
run: pnpm typecheck
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// .markdownlint-cli2.jsonc
|
||||
{
|
||||
"config": {
|
||||
// Disable all rules that conflict with Prettier (23 rules — line-length, list-indent,
|
||||
// blanks-around-fences, emphasis-style, etc.)
|
||||
"extends": "markdownlint/style/prettier",
|
||||
|
||||
// Content rules to KEEP:
|
||||
"MD001": true, // heading-increment: no skipping h1→h3
|
||||
"MD024": true, // no-duplicate-heading
|
||||
"MD040": true, // fenced-code-language: all fences must declare a language
|
||||
"MD031": true, // blanks-around-fences (re-enabled — see Pitfall 4 in RESEARCH.md)
|
||||
"MD051": true, // link-fragments: broken anchor links
|
||||
"MD052": true, // reference-links-images: undefined link references
|
||||
|
||||
// Rules DISABLED (Prettier owns these OR they fire on non-author-controlled files):
|
||||
"MD041": false, // first-line-h1: CLAUDE.md legitimately starts with ## Project
|
||||
"MD034": false, // no-bare-urls: CLAUDE.md version table uses pkg@version syntax
|
||||
"MD036": false, // no-emphasis-as-heading: docs/API.md uses **Response 200** as label
|
||||
},
|
||||
"globs": ["docs/**/*.md", "*.md", "apps/**/*.md"],
|
||||
"ignores": [".planning/**", "node_modules/**", "**/node_modules/**", ".pnpm-store/**"],
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
phase: 15-ci-skip-api-harness-jobs-for-doc-only-prs
|
||||
plan: "01"
|
||||
subsystem: ci
|
||||
tags: [markdownlint, ci, docs, fast-checks]
|
||||
dependency_graph:
|
||||
requires: []
|
||||
provides:
|
||||
- markdownlint-cli2 root devDependency (0.22.1)
|
||||
- md:lint root package.json script
|
||||
- .markdownlint-cli2.jsonc config (Prettier-compatible preset + content rules)
|
||||
- Markdown lint step in fast-checks CI job
|
||||
affects:
|
||||
- .gitea/workflows/ci.yml (fast-checks job — new Markdown lint step)
|
||||
- package.json (new script + devDependency)
|
||||
- 7 doc files (13 baseline violations fixed)
|
||||
tech_stack:
|
||||
added:
|
||||
- markdownlint-cli2@0.22.1 (root devDependency)
|
||||
patterns:
|
||||
- Config-file-driven markdownlint (globs/ignores in .markdownlint-cli2.jsonc, not CLI args)
|
||||
- markdownlint/style/prettier preset to avoid Prettier/markdownlint rule conflicts
|
||||
key_files:
|
||||
created:
|
||||
- .markdownlint-cli2.jsonc
|
||||
modified:
|
||||
- package.json
|
||||
- pnpm-lock.yaml
|
||||
- .gitea/workflows/ci.yml
|
||||
- README.md
|
||||
- apps/api/README.md
|
||||
- apps/pwa/README.md
|
||||
- apps/pwa/e2e/README.md
|
||||
- docs/API.md
|
||||
- docs/ARCHITECTURE.md
|
||||
- docs/DEVELOPMENT.md
|
||||
- docs/GETTING-STARTED.md
|
||||
decisions:
|
||||
- "md:lint script uses no glob args — globs and ignores live in .markdownlint-cli2.jsonc so pnpm md:lint and npx markdownlint-cli2 behave identically (RESEARCH Open Question 3)"
|
||||
- "MD031 re-enabled despite prettier preset disabling it — GETTING-STARTED.md has a genuine structural fix (fence inside list item with no blank lines); verified MD031 fix does not conflict with Prettier (format:check still 0 after fix)"
|
||||
- "MD040 bare fences tagged as 'text' for plain-output blocks (SSE event format, directory trees); 'bash' for shell commands"
|
||||
- "Prettier reformatted .markdownlint-cli2.jsonc (added trailing commas per JSONC trailingComma:all rule) — committed in Task 2"
|
||||
metrics:
|
||||
duration_minutes: 4
|
||||
completed_date: "2026-06-12"
|
||||
tasks_completed: 2
|
||||
files_changed: 12
|
||||
---
|
||||
|
||||
# Phase 15 Plan 01: Markdown Lint Gate Summary
|
||||
|
||||
**One-liner:** markdownlint-cli2@0.22.1 with Prettier-compatible config wired into fast-checks CI; 13 baseline violations fixed across 7 doc files, gate starts green.
|
||||
|
||||
## Tasks Completed
|
||||
|
||||
| Task | Name | Commit | Files |
|
||||
|------|------|--------|-------|
|
||||
| 1 | Install markdownlint-cli2, add md:lint script, create .markdownlint-cli2.jsonc | adb7641 | .markdownlint-cli2.jsonc, package.json, pnpm-lock.yaml |
|
||||
| 2 | Fix 13 baseline violations; green md:lint + format:check; wire fast-checks step | 46bea03 | .gitea/workflows/ci.yml, .markdownlint-cli2.jsonc (Prettier reformat), README.md, apps/api/README.md, apps/pwa/README.md, apps/pwa/e2e/README.md, docs/API.md, docs/ARCHITECTURE.md, docs/DEVELOPMENT.md, docs/GETTING-STARTED.md |
|
||||
|
||||
## What Was Built
|
||||
|
||||
### Task 1: markdownlint-cli2 install + config
|
||||
|
||||
- Installed `markdownlint-cli2@0.22.1` as a root workspace devDependency via `pnpm add -D markdownlint-cli2@0.22.1 --workspace-root`
|
||||
- Added `"md:lint": "markdownlint-cli2"` script to root `package.json` after `format:check`
|
||||
- Created `.markdownlint-cli2.jsonc` at repo root with:
|
||||
- `extends: "markdownlint/style/prettier"` — disables the 23 rules Prettier owns (including MD013 line-length, which would produce 700+ false positives against printWidth 100)
|
||||
- Content rules ENABLED: MD001, MD024, MD040, MD031, MD051, MD052
|
||||
- Rules DISABLED: MD041 (CLAUDE.md starts with `## Project`), MD034 (pkg@version syntax in version tables), MD036 (docs/API.md uses `**Response 200**` as semantic labels)
|
||||
- `globs`: `["docs/**/*.md", "*.md", "apps/**/*.md"]`
|
||||
- `ignores`: `[".planning/**", "node_modules/**", "**/node_modules/**", ".pnpm-store/**"]`
|
||||
|
||||
### Task 2: Baseline fixes + CI wiring
|
||||
|
||||
Fixed all 13 violations:
|
||||
- **MD040 (11 bare fences):** Added language tags across 7 files:
|
||||
- `apps/api/README.md:19` — directory tree → `text`
|
||||
- `apps/pwa/e2e/README.md:76` — pseudo-code block → `text`
|
||||
- `apps/pwa/README.md:45` — directory tree → `text`
|
||||
- `docs/API.md:517` — SSE event format → `text`
|
||||
- `docs/API.md:544` — SSE event format example → `text`
|
||||
- `docs/ARCHITECTURE.md:64` — directory tree → `text`
|
||||
- `docs/ARCHITECTURE.md:171` — backend module flow → `text`
|
||||
- `docs/DEVELOPMENT.md:9` — directory tree → `text`
|
||||
- `docs/DEVELOPMENT.md:22` — directory tree → `text`
|
||||
- `README.md:78` — monorepo structure → `text`
|
||||
- `README.md:119` — CalDAV principal URL → `text`
|
||||
- **MD031 (2 violations):** `docs/GETTING-STARTED.md:52-54` — added blank lines before ```` ```bash ```` and after closing ```` ``` ```` surrounding the `node -e` command inside a list item
|
||||
|
||||
Wired CI step in `.gitea/workflows/ci.yml`:
|
||||
```yaml
|
||||
- name: Markdown lint
|
||||
run: pnpm md:lint
|
||||
```
|
||||
Inserted after `Format check`, before `Typecheck` in the `fast-checks` job.
|
||||
|
||||
**Verification performed:**
|
||||
- `pnpm md:lint` exits 0 (Summary: 0 error(s), 12 files scanned)
|
||||
- `pnpm format:check` exits 0 (no Prettier conflict from MD031 blank-line additions)
|
||||
- Gate-can-fail test: appended a bare fence to README.md, confirmed `pnpm md:lint` exits non-zero (1 error), then reverted via `git checkout -- README.md` (NOTE: this reverted the Task 2 README.md fixes; they were re-applied before the Task 2 commit)
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Prettier reformatted .markdownlint-cli2.jsonc**
|
||||
- **Found during:** Task 2 format:check run
|
||||
- **Issue:** `.markdownlint-cli2.jsonc` created in Task 1 had no trailing commas; Prettier's `trailingComma: "all"` added trailing commas to the JSONC properties and arrays
|
||||
- **Fix:** Ran `pnpm format -- .markdownlint-cli2.jsonc` to apply Prettier's preferred style; verified `pnpm md:lint` still passes after the reformat
|
||||
- **Files modified:** `.markdownlint-cli2.jsonc`
|
||||
- **Commit:** 46bea03 (included in Task 2 commit with the doc fixes)
|
||||
|
||||
**2. [Rule 1 - Bug] gate-can-fail test reverted README.md MD040 fixes**
|
||||
- **Found during:** Task 2 gate verification test
|
||||
- **Issue:** Using `git checkout -- README.md` to revert the test bare fence also reverted the two MD040 fixes previously applied in Task 2 (README.md:78 and :119). The gate-can-fail test used `git checkout -- README.md` for cleanup which is a blanket revert.
|
||||
- **Fix:** Re-read README.md, re-applied both MD040 fixes (`text` language tags at lines 78 and 119), confirmed `pnpm md:lint` exits 0 before committing
|
||||
- **Files modified:** README.md
|
||||
- **Commit:** 46bea03
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — plan goal (markdownlint gate) is fully wired and green.
|
||||
|
||||
## Threat Surface Scan
|
||||
|
||||
No new network endpoints, auth paths, file access patterns, or schema changes introduced. The only surface is the `markdownlint-cli2` devDependency (supply chain) — addressed in the plan's threat model (T-15-01: pinned to exact 0.22.1, package legitimacy audit OK in RESEARCH.md).
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- `.markdownlint-cli2.jsonc` exists at repo root: FOUND
|
||||
- `package.json` contains `md:lint` script and `markdownlint-cli2` devDep: FOUND
|
||||
- `.gitea/workflows/ci.yml` contains `pnpm md:lint` step: FOUND
|
||||
- Commit adb7641 exists: FOUND
|
||||
- Commit 46bea03 exists: FOUND
|
||||
- `pnpm md:lint` exits 0: VERIFIED
|
||||
- `pnpm format:check` exits 0: VERIFIED
|
||||
@@ -75,7 +75,7 @@ The API listens on port 3000. The PWA build is served separately (Vite `preview`
|
||||
|
||||
## Monorepo Structure
|
||||
|
||||
```
|
||||
```text
|
||||
apps/
|
||||
api/ Hono backend — CalDAV sync, OIDC auth, lists API, push notifications
|
||||
pwa/ React 19 PWA — calendar view, lists UI, service worker
|
||||
@@ -116,7 +116,7 @@ docker-compose.dev.yml Dev overrides (bind-mount src/, expose DB/Redis ports)
|
||||
|
||||
FamilySync reads and writes calendars via CalDAV against Fastmail — not JMAP (not available for Fastmail calendars). Configure your Fastmail app password under the "Mail, Contacts & Calendars" scope. The principal URL follows the pattern:
|
||||
|
||||
```
|
||||
```text
|
||||
https://caldav.fastmail.com/dav/principals/user/<your-fastmail-address>/
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ Part of the [FamilySync monorepo](../../README.md).
|
||||
|
||||
## Source layout
|
||||
|
||||
```
|
||||
```text
|
||||
src/
|
||||
index.ts Hono app entrypoint; server startup; background worker initialization
|
||||
routes/
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ The API backend must also be running for most features. See [GETTING-STARTED.md]
|
||||
|
||||
## Source layout
|
||||
|
||||
```
|
||||
```text
|
||||
src/
|
||||
api/ # Typed fetch wrappers for @familysync/api (client.ts, listsClient.ts)
|
||||
components/ # Shared UI components co-located with their *.test.tsx files
|
||||
|
||||
@@ -73,7 +73,7 @@ Set `DB_PASSWORD` (and other non-default values) via the shell or the repo root
|
||||
|
||||
The API enforces this via `apps/api/src/auth/devBypass.ts`:
|
||||
|
||||
```
|
||||
```text
|
||||
if (process.env.NODE_ENV === 'production') → bypass is a no-op (always)
|
||||
if (process.env.DEV_AUTH_BYPASS !== 'true') → bypass is a no-op
|
||||
```
|
||||
|
||||
+2
-2
@@ -514,7 +514,7 @@ Streams `heartbeat` events every 10 seconds indefinitely. Used as a Pangolin tun
|
||||
|
||||
**Event format**
|
||||
|
||||
```
|
||||
```text
|
||||
event: heartbeat
|
||||
id: 0
|
||||
data: {"ts":"2025-06-10T14:00:00.000Z","id":0}
|
||||
@@ -541,7 +541,7 @@ A `heartbeat` event is sent every 30 seconds to keep the Pangolin connection ali
|
||||
|
||||
**Event format example**
|
||||
|
||||
```
|
||||
```text
|
||||
event: item:added
|
||||
id: 1-1718020800000
|
||||
data: {"type":"item:added","listId":1,"payload":{"id":11,"listId":1,"text":"Eggs"}}
|
||||
|
||||
@@ -61,7 +61,7 @@ graph TD
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
```text
|
||||
familysync/
|
||||
├── apps/
|
||||
│ ├── api/ # Hono backend (Node 22 + TypeScript)
|
||||
@@ -168,7 +168,7 @@ familysync/
|
||||
|
||||
### Backend modules
|
||||
|
||||
```
|
||||
```text
|
||||
routes/events.ts ──→ broker/expand.ts (read: RRULE expansion)
|
||||
──→ calendarOutbox (DB) (write: enqueue)
|
||||
──→ broker/sync.ts (write-sync after outbox drain)
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ Local development setup and workflows for FamilySync — a pnpm monorepo with tw
|
||||
|
||||
## Repo Layout
|
||||
|
||||
```
|
||||
```text
|
||||
familysync/
|
||||
├── apps/
|
||||
│ ├── api/ # Hono API server — Node.js 22, TypeScript, Drizzle/MariaDB
|
||||
@@ -19,7 +19,7 @@ familysync/
|
||||
|
||||
Key paths inside `apps/api/src/`:
|
||||
|
||||
```
|
||||
```text
|
||||
src/
|
||||
├── db/
|
||||
│ ├── schema.ts # Drizzle table definitions (source of truth for migrations)
|
||||
|
||||
@@ -49,9 +49,11 @@ Open `.env` and fill in the required values. See [docs/CONFIGURATION.md](CONFIGU
|
||||
|
||||
- `DB_PASSWORD` and `DB_ROOT_PASSWORD` — pick any local passwords
|
||||
- `APP_PASSWORD_ENCRYPTION_KEY` — 64 hex characters; generate with:
|
||||
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
```
|
||||
|
||||
- `DEV_AUTH_BYPASS=true` — bypasses the live Authelia OIDC flow for local dev
|
||||
- `DB_HOST=localhost` — the dev Docker Compose exposes MariaDB on the host at `localhost:3306`
|
||||
|
||||
|
||||
+3
-1
@@ -12,7 +12,8 @@
|
||||
"lint": "pnpm -r --if-present lint",
|
||||
"typecheck": "pnpm -r typecheck",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check ."
|
||||
"format:check": "prettier --check .",
|
||||
"md:lint": "markdownlint-cli2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.39.4",
|
||||
@@ -20,6 +21,7 @@
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-react-hooks": "7.1.1",
|
||||
"markdownlint-cli2": "0.22.1",
|
||||
"prettier": "3.8.4",
|
||||
"typescript-eslint": "8.61.0"
|
||||
}
|
||||
|
||||
Generated
+644
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user