From 784f21d805c9d3373414046d584a898e0476f5c1 Mon Sep 17 00:00:00 2001 From: Claude Fable 5 Date: Sat, 11 Jul 2026 10:08:41 +0200 Subject: [PATCH] Add editor section node; serialize pnpm CI jobs to fix runner flake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two corrective changes: - Register the `section` node in the web TipTap editor (with wrapInSection/unwrapSection commands) so the editor schema matches the shared editorSchema again. The schema-drift guard (document-extensions.test) rightly failed after 2e96173 added `section` to the shared schema without the editor side — this restores it. - Replace the ineffective warm-up gate with a serial chain of the pnpm CI jobs (checks -> auth-e2e -> fidelity). Warming the shared action cache did not help: the dependent jobs still started together and corrupted the cache during concurrent extraction. Serializing them is what actually prevents it; CD image builds still run in parallel. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1 --- .gitea/workflows/ci.yml | 35 +++++++--------------- apps/web/src/editor/document-extensions.ts | 2 ++ apps/web/src/editor/nodes/text-basics.ts | 30 +++++++++++++++++++ 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index b9bb590..cc43169 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -13,29 +13,16 @@ on: branches: [main] jobs: - # Warm the runner's shared action cache once, alone, before the parallel - # pnpm jobs start. With the runner at capacity > 1, several jobs otherwise - # fetch the same actions (checkout, setup-node, pnpm/action-setup) into the - # shared offline cache simultaneously and read it half-written — a flaky - # "Cannot find module .../dist/…" in "Set up Node.js"/"Set up pnpm". Running - # these actions once here populates the cache completely; the dependent jobs - # then only read it. Cheap (~30 s) and keeps full parallelism afterwards. - prepare: - name: Warm action cache - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v4 - - name: Set up pnpm - uses: pnpm/action-setup@v4 - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - + # The pnpm jobs are chained (checks -> auth-e2e -> fidelity) so no two run + # at once. At runner capacity > 1 they otherwise start together and extract + # the same actions (setup-node, pnpm/action-setup) into the shared offline + # cache (`/run/act/actions`) concurrently, reading it half-written — a flaky + # "Cannot find module .../dist/…" in "Set up Node.js"/"Set up pnpm". Warming + # the cache first did not help (concurrent extraction still corrupts it); + # only serialization does. The CD image builds still run in parallel, so the + # runner's spare capacity is not wasted. checks: name: Lint, typecheck, test - needs: prepare runs-on: ubuntu-latest services: postgres: @@ -86,7 +73,7 @@ jobs: # already-built-and-seeded stack, instead of spinning up a second one. auth-e2e: name: Auth e2e pack - needs: prepare + needs: checks runs-on: ubuntu-latest services: postgres: @@ -377,7 +364,7 @@ jobs: # job (no sidecars there). fidelity: name: Import/export fidelity gate - needs: prepare + needs: auth-e2e runs-on: ubuntu-latest # A guard so a hung sidecar can never keep the job (and its containers) # alive on the shared runner host; the suite itself finishes in ~1 min. @@ -458,7 +445,7 @@ jobs: images: name: Build container images - needs: prepare + needs: checks # PR-only: on main the CD workflow builds and pushes the same images — # building twice would waste the runner (ADR 0014: build once, promote). if: github.event_name == 'pull_request' diff --git a/apps/web/src/editor/document-extensions.ts b/apps/web/src/editor/document-extensions.ts index 2e3e54a..55f515e 100644 --- a/apps/web/src/editor/document-extensions.ts +++ b/apps/web/src/editor/document-extensions.ts @@ -15,6 +15,7 @@ import { Heading, HorizontalRule, Paragraph, + Section, Text, } from './nodes/text-basics'; @@ -29,6 +30,7 @@ export const documentExtensions: AnyExtension[] = [ Paragraph, Heading, Blockquote, + Section, CodeBlock, HorizontalRule, BulletList, diff --git a/apps/web/src/editor/nodes/text-basics.ts b/apps/web/src/editor/nodes/text-basics.ts index 4db5098..b8fcd37 100644 --- a/apps/web/src/editor/nodes/text-basics.ts +++ b/apps/web/src/editor/nodes/text-basics.ts @@ -13,6 +13,12 @@ declare module '@tiptap/core' { setHorizontalRule: () => ReturnType; setHardBreak: () => ReturnType; }; + documentSection: { + /** Wrap the selection in a styled section (issue #75). */ + wrapInSection: (attrs: { pluginId: string; styleId: string }) => ReturnType; + /** Unwrap the nearest section, leaving its content in place. */ + unwrapSection: () => ReturnType; + }; } } @@ -112,6 +118,30 @@ export const Blockquote = Node.create({ }, }); +const sectionSpec = nodeSpec('section'); +export const Section = Node.create({ + name: 'section', + group: sectionSpec.group, + content: sectionSpec.content, + defining: sectionSpec.defining, + addAttributes() { + return attributesFromSpec(sectionSpec); + }, + ...passthroughNodeIO(sectionSpec), + addCommands() { + return { + wrapInSection: + (attrs) => + ({ commands }) => + commands.wrapIn(this.name, attrs), + unwrapSection: + () => + ({ commands }) => + commands.lift(this.name), + }; + }, +}); + const codeBlockSpec = nodeSpec('code_block'); export const CodeBlock = Node.create({ name: 'code_block',