Skip to content

feat(docs): turn documents into an operations wiki - #2542

Merged
yohamta0 merged 28 commits into
mainfrom
feat/docs-wiki
Aug 9, 2026
Merged

feat(docs): turn documents into an operations wiki#2542
yohamta0 merged 28 commits into
mainfrom
feat/docs-wiki

Conversation

@yohamta0

@yohamta0 yohamta0 commented Aug 8, 2026

Copy link
Copy Markdown
Member

Summary

  • turn Documents into an operations wiki with tags, ranked search, wikilinks, backlinks, templates, revision history, and restore
  • add binary attachments with paste/drop uploads, Obsidian-style image embeds, downloads, and deterministic storage
  • render live DAG status and definitions in documents and add permission-gated, confirmable runbook actions
  • carry document attachments through Git Sync as dedicated binary items with publish, pull, conflict, and diff metadata support

Why

Documents were isolated Markdown files without enough navigation, history, operational context, or asset support for runbooks. This makes them useful as a connected workspace-aware wiki while keeping the file-backed storage model and Git Sync workflow.

Impact

Authors can build linked operational documentation, embed current DAG information, run approved workflows from runbooks, restore earlier document versions, and synchronize attachments with the rest of the repository. Workspace permissions continue to scope document and DAG operations.

Testing

  • go test ./internal/core/docs ./internal/persis/file/doc ./internal/gitsync ./internal/service/frontend/api/v1
  • pnpm test -- --runInBand (from ui)
  • pnpm typecheck (from ui)
  • pnpm build (from ui)
  • focused ESLint and Prettier checks for the final UI refactor

Summary by cubic

Turned Documents into an operations wiki with tags, wikilinks/backlinks, templates, live DAG embeds and run actions, local revision history, and binary attachments synchronized via Git with binary-aware diffs.

  • New Features

    • Tags in frontmatter with list/search filtering and ranked results.
    • Wikilinks [[target]] with anchors/labels and backlinks (API /docs/backlinks + UI); Obsidian-style embeds ![[image.png]].
    • Live DAG UI in docs: status chips, info blocks, and confirmable run blocks gated by permissions.
    • Binary attachments stored at docs/.attachments/{docID}/{name} with paste/drop upload, safe names, image embeds; upload/download APIs; Git Sync doc-asset kind with size-based diffs; SSE/watchers skip .attachments.
    • Templates in create flow (built-ins plus _templates/ per workspace), and a DAG “Docs” tab to link/create runbooks.
    • Local revisions with automatic snapshots, list, diff, and restore.
    • API/UI: tag filters on /search/doc and flat /docs, revisions endpoints, binary-aware Git Sync diff; docs sidebar tag filters, backlinks panel, wikilink rendering, and attachment handling in Git Sync.
    • Document file format spec and conformance test.
  • Bug Fixes

    • Made doc search case-insensitive to match the search feed.
    • Open wikilinks in tabs to avoid URL sync loops; keep editor upload callbacks in sync on path changes and clean up listeners.
    • Hardened attachment and rename handling (validation, recursive merges) and reduced noise by skipping attachment trees in SSE/watch registration.
    • Show the DAG name in the DAG Docs tab empty state.

Written for commit 0ba6d87. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added document tags, multi-tag filtering, ranked search results, and match counts.
    • Added backlinks, revision history with restore, and attachment upload/download.
    • Added wiki links, attachment embeds, and live DAG information and run actions in Markdown.
    • Added document templates for runbooks, postmortems, architecture decisions, and onboarding docs.
    • Added a Docs tab to DAG details with related documents and runbook creation.
    • Added binary attachment synchronization with size-based diff displays.
  • Documentation
    • Added the document file format specification.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds document tags, wiki links, backlinks, revisions, attachments, templates, live DAG blocks, and document navigation. Git sync classifies document assets as binary items and reports size metadata.

Changes

Document platform and persistence

Layer / File(s) Summary
Document contracts and storage
internal/core/docs/..., internal/persis/file/doc/...
Adds tags, wiki-link extraction, backlinks, revisions, attachments, validation, and cleanup during document mutations.
Document API and search
api/v1/api.yaml, internal/service/frontend/api/v1/..., ui/src/api/v1/schema.ts
Adds tag filters, ranked search metadata, backlink endpoints, revision endpoints, and attachment upload/download endpoints.
Document authoring and navigation
ui/src/pages/docs/..., ui/src/features/dags/components/dag-details/...
Adds templates, revision history, attachment uploads, tag filters, backlink panels, DAG document listings, and document navigation.
Live document rendering
ui/src/components/docs-live/..., ui/src/components/ui/doc-markdown-preview.tsx
Adds live DAG lookup, dagu-info and dagu-run blocks, wiki-link routing, and attachment rendering.
Specifications and conformance
specs/..., conformance/spec034_doc_format/...
Adds the document format specification and conformance coverage for frontmatter, tags, identifiers, and backlinks.

Document asset synchronization

Layer / File(s) Summary
Asset classification and synchronization
internal/gitsync/..., internal/service/frontend/api/v1/sync.go
Adds the doc-asset kind, validates attachment paths, preserves filenames, syncs binary assets, and reports size-only diffs.
Asset presentation and watcher exclusions
ui/src/pages/git-sync/..., internal/service/frontend/sse/app_stream.go
Displays binary size summaries and excludes .attachments from document watches and Markdown snapshots.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarizes the main change: turning documents into an operations wiki.
Description check ✅ Passed The description provides a detailed summary, rationale, impact, changes, and testing information, although it does not use every template heading.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/docs-wiki

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🧹 Nitpick comments (15)
ui/src/pages/git-sync/DiffModal.tsx (1)

108-137: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a compact binary information block.

Reduce p-6 to compact padding such as p-3. Apply bg-muted/30 to the information block. This keeps the modal information-dense and preserves semantic theme styling.

As per coding guidelines, “Use information-dense, compact UI design with minimal whitespace.” Based on learnings, “use the semantic bg-muted/30 theme token for information blocks.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/git-sync/DiffModal.tsx` around lines 108 - 137, Update the
binary attachment information block in the binary rendering branch to use
compact padding such as p-3 instead of p-6, and add the semantic bg-muted/30
background class while preserving its existing content and layout.

Sources: Coding guidelines, Learnings

internal/service/frontend/sse/app_stream_test.go (1)

74-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the other exclusion paths.

This test covers only initial recursive watch-path discovery. Add focused tests for dynamically created .attachments directories and Markdown paths handled by snapshotMarkdownFiles and handleDocEvent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/frontend/sse/app_stream_test.go` around lines 74 - 85,
Expand coverage around recursiveWatchPathsSkipsAttachmentSubtree by adding
focused tests for dynamically created .attachments directories and Markdown
paths processed by snapshotMarkdownFiles and handleDocEvent. Verify each
exclusion path is ignored while preserving expected handling for valid document
paths.
ui/src/components/docs-live/DocLiveProvider.tsx (1)

41-54: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider removing the unused countsRef map.

countsRef tracks a per-reference count, but no code reads the map. enabled depends only on refCount, and lookup reads byRef. Removing the map reduces the state that must stay consistent.

♻️ Proposed simplification
   const [refCount, setRefCount] = useState(0);
-  const countsRef = useRef(new Map<string, number>());
 
-  const registerRef = useCallback((ref: string) => {
-    const counts = countsRef.current;
-    counts.set(ref, (counts.get(ref) ?? 0) + 1);
+  const registerRef = useCallback(() => {
     setRefCount((c) => c + 1);
     return () => {
-      const current = counts.get(ref) ?? 0;
-      if (current <= 1) {
-        counts.delete(ref);
-      } else {
-        counts.set(ref, current - 1);
-      }
       setRefCount((c) => Math.max(0, c - 1));
     };
   }, []);

Keep the registerRef: (ref: string) => () => void signature in context.ts if you plan to use per-reference counts later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/components/docs-live/DocLiveProvider.tsx` around lines 41 - 54, Remove
the unused countsRef map and all per-reference count updates from registerRef in
DocLiveProvider. Keep registerRef’s ref parameter and cleanup-returning
signature unchanged, and continue updating refCount with the existing increment
and nonnegative decrement behavior.
ui/src/components/docs-live/__tests__/DocLiveProvider.test.tsx (1)

99-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Guard both tests against a vacuous pass.

sseCalls.every(...) at Line 107 returns true for an empty array. The loop at Line 118 performs no assertion for an empty array. If the provider stops calling useDAGsListSSE, both tests still pass. Test 1 already guards this at Line 90.

♻️ Proposed fix to add non-empty assertions
     expect(sseCalls.every((c) => !c.enabled)).toBe(true);
+    expect(sseCalls.length).toBeGreaterThan(0);
   });
 
   it('scopes the default doc scope to the default workspace, never all', () => {
     sseCalls.length = 0;
     render(
       <DocLiveProvider workspace={null}>
         <Probe dagRef="daily-etl" />
       </DocLiveProvider>
     );
 
+    expect(sseCalls.length).toBeGreaterThan(0);
     for (const call of sseCalls) {
       expect(call.params).toMatchObject({ workspace: 'default' });
     }
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/components/docs-live/__tests__/DocLiveProvider.test.tsx` around lines
99 - 121, Add non-empty assertions for sseCalls in both tests: require at least
one captured call after rendering DocLiveProvider, before checking enabled flags
or workspace parameters. Keep the existing assertions unchanged so the tests
still verify the feed is disabled and the default scope is “default,” while
preventing vacuous passes if useDAGsListSSE stops being called.
ui/src/components/ui/__tests__/doc-markdown-preview.test.tsx (2)

125-147: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the patched URL methods after the test.

The test replaces URL.createObjectURL and URL.revokeObjectURL on the global object and never restores them. Later tests in this file and in the same worker keep the stubs. Use vi.stubGlobal with vi.unstubAllGlobals(), or restore the original descriptors in an afterEach hook.

♻️ Proposed cleanup
   it('renders ![[name]] embeds as attachment images', async () => {
-    Object.defineProperty(URL, 'createObjectURL', {
-      configurable: true,
-      value: () => 'blob:attachment-test',
-    });
-    Object.defineProperty(URL, 'revokeObjectURL', {
-      configurable: true,
-      value: () => {},
-    });
+    const createObjectURL = vi
+      .fn()
+      .mockReturnValue('blob:attachment-test');
+    vi.spyOn(URL, 'createObjectURL').mockImplementation(createObjectURL);
+    vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => {});

Add the restore hook next to the existing beforeEach:

afterEach(() => {
  vi.restoreAllMocks();
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/components/ui/__tests__/doc-markdown-preview.test.tsx` around lines
125 - 147, Update the attachment-image test around URL.createObjectURL and
URL.revokeObjectURL to avoid leaking global patches: use Vitest global stubbing
with vi.stubGlobal and add cleanup via vi.unstubAllGlobals(), or capture and
restore the original property descriptors in an afterEach hook alongside the
existing beforeEach.

161-171: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the rendered output, not container.

expect(container).toBeTruthy() passes for any render result. The test does not prove that the raw name is kept. Assert the anchor title and the absence of a thrown error.

♻️ Proposed assertion
-    // Must render without throwing; the raw value is kept as the name.
-    expect(container).toBeTruthy();
+    // The raw value is kept as the attachment name.
+    expect(screen.getByRole('link', { name: 'bad' })).toHaveAttribute(
+      'title',
+      'Download bad%ZZ.pdf'
+    );
+    expect(container.querySelector('img')).toBeNull();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/components/ui/__tests__/doc-markdown-preview.test.tsx` around lines
161 - 171, Update the malformed percent-encoding test for DocMarkdownPreview to
assert the rendered attachment link preserves the raw filename in its title, and
explicitly verify rendering does not throw. Replace the non-specific container
truthiness assertion while retaining coverage for both malformed image and PDF
attachment references.
ui/src/components/ui/doc-markdown-preview.tsx (1)

288-321: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Share one source of truth for the custom fence languages.

The fence language names appear in the code override and again in the pre override. A new block type requires two edits, and a missed edit leaves a stray <pre> wrapper. Extract one map and derive both branches from it.

♻️ Proposed refactor
+const FENCE_BLOCKS = {
+  'language-mermaid': MermaidBlock,
+  'language-dagu-info': DaguInfoBlock,
+  'language-dagu-run': DaguRunBlock,
+} as const;
+
           code({ className: codeClassName, children }) {
-            if (codeClassName === 'language-mermaid') {
-              return <MermaidBlock code={String(children)} />;
-            }
-            if (codeClassName === 'language-dagu-info') {
-              return <DaguInfoBlock source={String(children)} />;
-            }
-            if (codeClassName === 'language-dagu-run') {
-              return <DaguRunBlock source={String(children)} />;
-            }
+            if (codeClassName === 'language-mermaid') {
+              return <MermaidBlock code={String(children)} />;
+            }
+            const Block =
+              codeClassName && codeClassName in FENCE_BLOCKS
+                ? FENCE_BLOCKS[codeClassName as keyof typeof FENCE_BLOCKS]
+                : undefined;
+            if (Block && Block !== MermaidBlock) {
+              return <Block source={String(children)} />;
+            }
             return <code className={codeClassName}>{children}</code>;
           },
           pre({ children }) {
             const childArray = Array.isArray(children) ? children : [children];
             const unwrapped = childArray.some((child) => {
               if (!isValidElement(child)) return false;
-              if (
-                child.type === MermaidBlock ||
-                child.type === DaguInfoBlock ||
-                child.type === DaguRunBlock
-              ) {
+              if (
+                Object.values(FENCE_BLOCKS).some((b) => child.type === b)
+              ) {
                 return true;
               }
               const className = (child.props as { className?: string })
                 .className;
-              return (
-                className === 'language-mermaid' ||
-                className === 'language-dagu-info' ||
-                className === 'language-dagu-run'
-              );
+              return !!className && className in FENCE_BLOCKS;
             });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/components/ui/doc-markdown-preview.tsx` around lines 288 - 321,
Extract the custom fence language names into one shared mapping or set near the
markdown component, then update both the code override and the pre override to
derive their dispatch and unwrapping checks from it. Ensure adding a new custom
block requires updating only this centralized definition while preserving the
existing MermaidBlock, DaguInfoBlock, and DaguRunBlock behavior.
ui/src/pages/docs/components/DocHistoryModal.tsx (1)

69-83: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Guard against out-of-order revision responses.

selectRevision sets selectedRev immediately and applies the response later. If the user selects a second revision before the first response arrives, the slower response can overwrite the newer content. Compare the requested rev with the current selection before you apply the result.

♻️ Proposed change
   const selectedRevRef = useRef<string | null>(null);
   const selectRevision = async (rev: string) => {
     setSelectedRev(rev);
+    selectedRevRef.current = rev;
     setRevisionContent(null);
     setLoadError(null);
     const { data: revData, error } = await client.GET('/docs/doc/revision', {
       params: {
         query: { remoteNode, path: docPath, rev, ...workspaceQuery },
       },
     });
+    if (selectedRevRef.current !== rev) return;
     if (error || !revData) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/docs/components/DocHistoryModal.tsx` around lines 69 - 83,
Update selectRevision to ignore stale asynchronous responses: after client.GET
resolves, verify the requested rev still matches the current selected revision
before applying either the load error or revision content. Preserve the existing
behavior for the latest selection while preventing an earlier response from
overwriting it.
ui/src/pages/docs/components/CreateDocModal.tsx (1)

149-149: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a smaller select height.

The coding guidelines require select boxes with a height of h-7 or smaller. SelectTrigger uses h-8 here.

♻️ Proposed change
-                <SelectTrigger id="doc-template" className="col-span-3 h-8">
+                <SelectTrigger id="doc-template" size="sm" className="col-span-3 h-7">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/docs/components/CreateDocModal.tsx` at line 149, Update the
SelectTrigger for doc-template in CreateDocModal to use h-7 or smaller instead
of h-8, preserving the existing styling and behavior.

Source: Coding guidelines

ui/src/pages/docs/components/DocTreeSidebar.tsx (1)

764-775: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the clear action part of the menu.

The "Clear filter" control is a plain button inside DropdownMenuContent. Radix keyboard navigation moves between menu items only, so this control is not reachable with the arrow keys. Use DropdownMenuItem instead.

♻️ Proposed change
-                    <button
-                      type="button"
-                      className="w-full text-left text-xs px-2 py-1 text-muted-foreground hover:bg-accent rounded-sm"
-                      onClick={() => setSelectedTags([])}
-                    >
-                      Clear filter
-                    </button>
+                    <DropdownMenuItem
+                      className="text-xs text-muted-foreground"
+                      onSelect={() => setSelectedTags([])}
+                    >
+                      Clear filter
+                    </DropdownMenuItem>

Add DropdownMenuItem to the import at Line 9-18.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/docs/components/DocTreeSidebar.tsx` around lines 764 - 775,
Replace the plain “Clear filter” button in the selected-tags section of
DocTreeSidebar with DropdownMenuItem, preserving its onClick behavior and
styling as appropriate; also add DropdownMenuItem to the existing Radix menu
imports.
ui/src/pages/docs/components/DocBacklinksPanel.tsx (1)

41-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Expose the collapse state to assistive technology.

The toggle button changes the visibility of the backlink list. Add aria-expanded so screen readers report the state.

♻️ Proposed change
       <button
         type="button"
         onClick={() => setCollapsed((c) => !c)}
+        aria-expanded={!collapsed}
         className="w-full flex items-center gap-1 px-3 py-1.5 text-xs font-medium uppercase tracking-wide text-muted-foreground hover:text-foreground"
       >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/docs/components/DocBacklinksPanel.tsx` around lines 41 - 45, Add
an aria-expanded attribute to the collapse toggle button in DocBacklinksPanel,
binding it to the current collapsed state with the correct expanded-value
inversion. Keep the existing setCollapsed toggle behavior unchanged.
ui/src/pages/docs/lib/doc-templates.ts (1)

11-12: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider delimiting the placeholder token.

DOC_TEMPLATE_DAG_NAME is the bare token DAG_NAME. Consumers replace every occurrence with split(...).join(...) (see ui/src/features/dags/components/dag-details/DAGDocsTab.tsx line 153). The replacement also hits substrings inside larger identifiers, for example MY_DAG_NAME_SUFFIX, and any prose that mentions DAG_NAME. A delimited token avoids this.

♻️ Proposed change
-export const DOC_TEMPLATE_DAG_NAME = 'DAG_NAME';
+export const DOC_TEMPLATE_DAG_NAME = '{{DAG_NAME}}';

Built-in template bodies already interpolate the constant, so they need no edit. Existing user templates that use the old token require a migration note.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/docs/lib/doc-templates.ts` around lines 11 - 12, Change the
value of DOC_TEMPLATE_DAG_NAME to a clearly delimited placeholder token so
replacements only target the intended marker, and add a migration note for
existing user templates that still use the bare DAG_NAME token. Keep built-in
templates relying on DOC_TEMPLATE_DAG_NAME unchanged.
internal/persis/file/doc/store_test.go (1)

592-623: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a non-matching document to the ranking fixtures.

Every fixture in both tests contains the query term. The tests therefore cannot detect whether Search excludes documents with no match. That gap hides the filtering defect flagged in internal/persis/file/doc/search.go Lines 50-78.

Add a document that does not contain the query and assert it is absent from the results.

💚 Proposed addition
 	require.NoError(t, store.Create(ctx, "m-single", "one etl mention"))
+	// A document with no match must not appear in the results.
+	require.NoError(t, store.Create(ctx, "no-match", "completely unrelated body"))
 
 	results, err := store.Search(ctx, "etl")
 	require.NoError(t, err)
 	require.Len(t, results, 3)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/persis/file/doc/store_test.go` around lines 592 - 623, Add a fixture
document without the query term to both TestSearchRanking and
TestSearchRankingTiebreakByID, then assert the returned results contain only the
matching documents and exclude the non-matching document.
internal/persis/file/doc/store.go (1)

112-116: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Guard WithDataDir against an empty directory.

filepath.Clean("") returns ".". An empty argument therefore enables revisions and writes revisions.json plus blobs into the process working directory. NewDocStore currently checks cfg.Paths.DataDir != "" before calling this option, so production is safe today. Add the guard inside the option so a future caller cannot break it.

♻️ Proposed guard
 func WithDataDir(dir string) Option {
 	return func(s *Store) {
+		if dir == "" {
+			return
+		}
 		s.dataDir = filepath.Clean(dir)
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/persis/file/doc/store.go` around lines 112 - 116, Update WithDataDir
to ignore empty dir values before calling filepath.Clean or assigning
Store.dataDir; preserve the existing behavior for non-empty directories.
internal/persis/file/doc/revision.go (1)

58-96: 🚀 Performance & Scalability | 🔵 Trivial

Consider the whole-file manifest rewrite as the document count grows.

revisions.json holds every document's revision list. Each snapshot, delete, and rename loads and rewrites the entire file while mutationMu is held. Cost grows linearly with the number of documents that have history, up to 20 entries each. This is acceptable for a wiki-scale workload. If document counts grow large, move to a per-document manifest under the revisions directory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/persis/file/doc/revision.go` around lines 58 - 96, Keep the current
whole-file revisions manifest implementation for the wiki-scale workload, but
document the scalability boundary around loadRevisionsManifest and
saveRevisionsManifest: note that each snapshot, delete, and rename rewrites all
document revision lists while mutationMu is held, and identify a per-document
manifest under the revisions directory as the future approach if document counts
become large.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/core/docs/link.go`:
- Around line 37-45: Update the line-processing logic around the
inlineCodeRegexp and wiki-link matching to preserve inline-code delimiter state
across lines, ensuring wiki links inside multi-line code spans are ignored while
same-line spans retain current behavior. Add a regression test covering a
multi-line inline-code span containing a [[target]] link and verify no backlink
is created.

In `@internal/gitsync/git.go`:
- Around line 586-597: Update the filesystem traversal around the directory
handling and relPath computation to skip any entry whose d.Type().IsRegular() is
false, including symlinks and other non-regular entries. Perform this check
before filepath.Rel and appending to files, while preserving the existing .git
directory SkipDir behavior.

In `@internal/gitsync/service.go`:
- Around line 1698-1704: Update the remote metadata branch around
GetFileSizeAtCommit to call s.gitClient.Open() before reading the remote file
size, and handle the open error explicitly instead of silently continuing.
Preserve diff.RemoteCommit assignment while ensuring repository-open or
size-lookup failures are returned or represented according to the surrounding
service error-handling contract.
- Around line 138-147: Change SyncItemDiff’s binary size representation to
preserve unavailable values, using pointer sizes or explicit availability
fields, and assign them only after successful local stat or remote lookup.
Update the mapper in the sync API flow to serialize unavailable sizes
distinctly, then adjust affected tests to verify zero-byte sizes remain valid
while missing sizes trigger the UI fallback.

In `@internal/persis/file/doc/attachment.go`:
- Around line 47-74: Update PutAttachment to call io.ReadAll(content) before
acquiring mutationMu, returning the existing wrapped read error immediately if
buffering fails. Then acquire mutationMu and keep the document existence check,
directory creation, and atomic file write inside the locked filesystem-work
section.

In `@internal/service/frontend/api/v1/docs.go`:
- Around line 340-346: Update the oversized attachment branch in
UploadDocAttachment to use api.ErrorCodePayloadTooLarge instead of
api.ErrorCodeBadRequest, while preserving the existing HTTP 413 status and
message.

In `@specs/034-doc-format.md`:
- Around line 1-126: The spec 034 entry is marked Implemented without tracked
conformance coverage. Add conformance/spec034_doc_format coverage for the
document-format behaviors defined in specs/034-doc-format.md, then update
specs/034-doc-format.md and specs/README.md to reflect the actual available
conformance results; at specs/034-doc-format.md lines 1-126 and specs/README.md
lines 38-39, make the status and listing consistent, with no direct change
required to the README beyond aligning it with the coverage status.

In `@ui/src/components/docs-live/DagStatusChip.tsx`:
- Around line 29-49: Update the loading and not-found branches in DagStatusChip
to render the computed text directly, preserving an explicitly empty label as an
empty chip. Keep the dagRef fallback only for the undefined-label case handled
when text is initialized, and leave the found branch unchanged.

In `@ui/src/components/docs-live/DocLiveProvider.tsx`:
- Around line 79-88: Update the byRef useMemo map construction in
DocLiveProvider to enforce deterministic name-first resolution: first index
every item.dag.name, then add item.fileName entries only when those keys are not
already mapped. Preserve the existing first-item-wins behavior for duplicate
logical names and file names.

In `@ui/src/features/dags/components/dag-details/DAGDetailsContent.tsx`:
- Around line 299-305: Remove the non-modal Docs LinkTab from the DAG details
tab list, including its surrounding conditional if it is only used by this tab.
Leave the modal docs behavior and other tabs unchanged, so DAG details no longer
links to the generic /docs route.

In `@ui/src/features/dags/components/dag-details/DAGDocsTab.tsx`:
- Around line 144-172: Update handleCreate to catch rejections from client.POST
and set createError to the request error message or a suitable fallback, while
retaining the existing success flow and finally block that clears loading state.
- Around line 38-44: Update docLink and the navigate call in DAGDocsTab to
encode the document ID using the same per-segment encodeURIComponent rule as
encodeDocPathForURL, replacing encodeURI while preserving the existing workspace
query handling so both document-link surfaces produce identical URLs.

In `@ui/src/lib/remark-wikilink.ts`:
- Around line 24-40: Remove the decodeURIComponent try/catch and related
decoding comments from parseWikilinkHref, preserving href slicing and hash-based
target/anchor parsing so percent sequences remain literal.

In `@ui/src/pages/docs/components/DocEditor.tsx`:
- Around line 320-322: Update uploadFiles to await each uploadAttachment call
sequentially rather than starting all uploads concurrently, preserving
completion order and ensuring currentValueRef.current includes previously
appended Markdown links before the next setCurrentValue update; keep the
existing selection and no-selection handling unchanged.

In `@ui/src/pages/docs/components/DocHistoryModal.tsx`:
- Around line 109-112: Update the empty-content branch in DocHistoryModal to use
the useQuery loading flag: display a loading message while the revisions request
is in flight, and show “No stored revisions yet” only after loading completes
with no revisions. Preserve the existing revisions list rendering.

---

Nitpick comments:
In `@internal/persis/file/doc/revision.go`:
- Around line 58-96: Keep the current whole-file revisions manifest
implementation for the wiki-scale workload, but document the scalability
boundary around loadRevisionsManifest and saveRevisionsManifest: note that each
snapshot, delete, and rename rewrites all document revision lists while
mutationMu is held, and identify a per-document manifest under the revisions
directory as the future approach if document counts become large.

In `@internal/persis/file/doc/store_test.go`:
- Around line 592-623: Add a fixture document without the query term to both
TestSearchRanking and TestSearchRankingTiebreakByID, then assert the returned
results contain only the matching documents and exclude the non-matching
document.

In `@internal/persis/file/doc/store.go`:
- Around line 112-116: Update WithDataDir to ignore empty dir values before
calling filepath.Clean or assigning Store.dataDir; preserve the existing
behavior for non-empty directories.

In `@internal/service/frontend/sse/app_stream_test.go`:
- Around line 74-85: Expand coverage around
recursiveWatchPathsSkipsAttachmentSubtree by adding focused tests for
dynamically created .attachments directories and Markdown paths processed by
snapshotMarkdownFiles and handleDocEvent. Verify each exclusion path is ignored
while preserving expected handling for valid document paths.

In `@ui/src/components/docs-live/__tests__/DocLiveProvider.test.tsx`:
- Around line 99-121: Add non-empty assertions for sseCalls in both tests:
require at least one captured call after rendering DocLiveProvider, before
checking enabled flags or workspace parameters. Keep the existing assertions
unchanged so the tests still verify the feed is disabled and the default scope
is “default,” while preventing vacuous passes if useDAGsListSSE stops being
called.

In `@ui/src/components/docs-live/DocLiveProvider.tsx`:
- Around line 41-54: Remove the unused countsRef map and all per-reference count
updates from registerRef in DocLiveProvider. Keep registerRef’s ref parameter
and cleanup-returning signature unchanged, and continue updating refCount with
the existing increment and nonnegative decrement behavior.

In `@ui/src/components/ui/__tests__/doc-markdown-preview.test.tsx`:
- Around line 125-147: Update the attachment-image test around
URL.createObjectURL and URL.revokeObjectURL to avoid leaking global patches: use
Vitest global stubbing with vi.stubGlobal and add cleanup via
vi.unstubAllGlobals(), or capture and restore the original property descriptors
in an afterEach hook alongside the existing beforeEach.
- Around line 161-171: Update the malformed percent-encoding test for
DocMarkdownPreview to assert the rendered attachment link preserves the raw
filename in its title, and explicitly verify rendering does not throw. Replace
the non-specific container truthiness assertion while retaining coverage for
both malformed image and PDF attachment references.

In `@ui/src/components/ui/doc-markdown-preview.tsx`:
- Around line 288-321: Extract the custom fence language names into one shared
mapping or set near the markdown component, then update both the code override
and the pre override to derive their dispatch and unwrapping checks from it.
Ensure adding a new custom block requires updating only this centralized
definition while preserving the existing MermaidBlock, DaguInfoBlock, and
DaguRunBlock behavior.

In `@ui/src/pages/docs/components/CreateDocModal.tsx`:
- Line 149: Update the SelectTrigger for doc-template in CreateDocModal to use
h-7 or smaller instead of h-8, preserving the existing styling and behavior.

In `@ui/src/pages/docs/components/DocBacklinksPanel.tsx`:
- Around line 41-45: Add an aria-expanded attribute to the collapse toggle
button in DocBacklinksPanel, binding it to the current collapsed state with the
correct expanded-value inversion. Keep the existing setCollapsed toggle behavior
unchanged.

In `@ui/src/pages/docs/components/DocHistoryModal.tsx`:
- Around line 69-83: Update selectRevision to ignore stale asynchronous
responses: after client.GET resolves, verify the requested rev still matches the
current selected revision before applying either the load error or revision
content. Preserve the existing behavior for the latest selection while
preventing an earlier response from overwriting it.

In `@ui/src/pages/docs/components/DocTreeSidebar.tsx`:
- Around line 764-775: Replace the plain “Clear filter” button in the
selected-tags section of DocTreeSidebar with DropdownMenuItem, preserving its
onClick behavior and styling as appropriate; also add DropdownMenuItem to the
existing Radix menu imports.

In `@ui/src/pages/docs/lib/doc-templates.ts`:
- Around line 11-12: Change the value of DOC_TEMPLATE_DAG_NAME to a clearly
delimited placeholder token so replacements only target the intended marker, and
add a migration note for existing user templates that still use the bare
DAG_NAME token. Keep built-in templates relying on DOC_TEMPLATE_DAG_NAME
unchanged.

In `@ui/src/pages/git-sync/DiffModal.tsx`:
- Around line 108-137: Update the binary attachment information block in the
binary rendering branch to use compact padding such as p-3 instead of p-6, and
add the semantic bg-muted/30 background class while preserving its existing
content and layout.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 64eab593-0ec7-4c0f-bd5a-cbe52862b6a3

📥 Commits

Reviewing files that changed from the base of the PR and between 4588800 and 0083e43.

⛔ Files ignored due to path filters (1)
  • ui/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (66)
  • api/v1/api.gen.go
  • api/v1/api.yaml
  • internal/core/docs/doc.go
  • internal/core/docs/link.go
  • internal/core/docs/link_test.go
  • internal/gitsync/git.go
  • internal/gitsync/pull_external_test.go
  • internal/gitsync/service.go
  • internal/gitsync/service_test.go
  • internal/gitsync/state.go
  • internal/persis/file/doc/attachment.go
  • internal/persis/file/doc/attachment_test.go
  • internal/persis/file/doc/backlinks.go
  • internal/persis/file/doc/backlinks_test.go
  • internal/persis/file/doc/revision.go
  • internal/persis/file/doc/revision_test.go
  • internal/persis/file/doc/search.go
  • internal/persis/file/doc/store.go
  • internal/persis/file/doc/store_test.go
  • internal/persis/file/doc/tree.go
  • internal/persis/file/service_stores.go
  • internal/service/frontend/api/v1/docs.go
  • internal/service/frontend/api/v1/docs_response.go
  • internal/service/frontend/api/v1/docs_test.go
  • internal/service/frontend/api/v1/search.go
  • internal/service/frontend/api/v1/sync.go
  • internal/service/frontend/api/v1/sync_test.go
  • internal/service/frontend/sse/app_stream.go
  • internal/service/frontend/sse/app_stream_test.go
  • internal/service/mcp/docs_tool.go
  • specs/034-doc-format.md
  • specs/README.md
  • ui/package.json
  • ui/src/api/v1/schema.ts
  • ui/src/components/docs-live/DagStatusChip.tsx
  • ui/src/components/docs-live/DaguInfoBlock.tsx
  • ui/src/components/docs-live/DaguRunBlock.tsx
  • ui/src/components/docs-live/DocLiveProvider.tsx
  • ui/src/components/docs-live/__tests__/DaguRunBlock.test.tsx
  • ui/src/components/docs-live/__tests__/DocLiveProvider.test.tsx
  • ui/src/components/docs-live/context.ts
  • ui/src/components/editors/MarkdownEditor.tsx
  • ui/src/components/ui/__tests__/doc-markdown-preview.test.tsx
  • ui/src/components/ui/doc-markdown-preview.css
  • ui/src/components/ui/doc-markdown-preview.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsContent.tsx
  • ui/src/features/dags/components/dag-details/DAGDocsTab.tsx
  • ui/src/features/dags/components/dag-details/__tests__/DAGDetailsContent.test.tsx
  • ui/src/hooks/useDocAttachmentUrl.ts
  • ui/src/lib/remark-wikilink.ts
  • ui/src/pages/docs/components/CreateDocModal.tsx
  • ui/src/pages/docs/components/DocBacklinksPanel.tsx
  • ui/src/pages/docs/components/DocEditor.tsx
  • ui/src/pages/docs/components/DocHistoryModal.tsx
  • ui/src/pages/docs/components/DocTreeSidebar.tsx
  • ui/src/pages/docs/components/__tests__/CreateDocModal.test.tsx
  • ui/src/pages/docs/components/__tests__/DocEditor.test.tsx
  • ui/src/pages/docs/hooks/useDocTemplates.ts
  • ui/src/pages/docs/index.tsx
  • ui/src/pages/docs/lib/doc-attachments.ts
  • ui/src/pages/docs/lib/doc-templates.ts
  • ui/src/pages/git-sync/DiffModal.tsx
  • ui/src/pages/git-sync/__tests__/DiffModal.test.tsx
  • ui/src/pages/git-sync/__tests__/sync-kind.test.ts
  • ui/src/pages/git-sync/index.tsx
  • ui/src/pages/git-sync/sync-kind.ts

Comment thread internal/core/docs/link.go Outdated
Comment thread internal/gitsync/git.go
Comment thread internal/gitsync/service.go Outdated
Comment thread internal/gitsync/service.go
Comment thread internal/persis/file/doc/attachment.go
Comment thread ui/src/features/dags/components/dag-details/DAGDocsTab.tsx
Comment thread ui/src/features/dags/components/dag-details/DAGDocsTab.tsx
Comment thread ui/src/lib/remark-wikilink.ts
Comment thread ui/src/pages/docs/components/DocEditor.tsx Outdated
Comment thread ui/src/pages/docs/components/DocHistoryModal.tsx

yohamta0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Addressed the review summary nitpicks in 3c84f09e1 and ab005ecc5: compact binary diff styling, attachment watcher coverage, live-provider cleanup and stronger tests, restored URL globals, meaningful malformed-percent assertions, shared custom-fence handling, stale revision-response protection, compact template selection, accessible backlinks/filter controls, a delimited DAG placeholder, and an empty WithDataDir guard.

I left two suggestions unchanged after checking them: TestSearch already asserts that nonmatching documents are excluded, and a speculative revision-manifest scalability comment would describe an unimplemented future design rather than the current contract. I also skipped a migration note for the old bare DAG_NAME token because the token is introduced and replaced within this unreleased PR.

Local validation is green for the affected Go packages and conformance test, all frontend tests, TypeScript checking, and ESLint on changed frontend files.

yohamta0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/features/dags/components/dag-details/DAGDocsTab.tsx`:
- Around line 200-202: Update the wikilink example in the DAGDocsTab render so
dagName is interpolated as JSX text rather than displayed literally. Preserve
the surrounding explanatory text and existing validSegment-based path rendering.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4cb3657b-7c2d-43af-914d-f5975e66de95

📥 Commits

Reviewing files that changed from the base of the PR and between 0083e43 and ab005ec.

📒 Files selected for processing (38)
  • conformance/spec034_doc_format/doc_format_test.go
  • internal/core/docs/link.go
  • internal/core/docs/link_test.go
  • internal/gitsync/git.go
  • internal/gitsync/git_test.go
  • internal/gitsync/pull_external_test.go
  • internal/gitsync/service.go
  • internal/persis/file/doc/attachment.go
  • internal/persis/file/doc/revision_test.go
  • internal/persis/file/doc/store.go
  • internal/persis/file/doc/store_test.go
  • internal/service/frontend/api/v1/docs.go
  • internal/service/frontend/api/v1/docs_test.go
  • internal/service/frontend/api/v1/sync.go
  • internal/service/frontend/api/v1/sync_test.go
  • internal/service/frontend/sse/app_stream_test.go
  • ui/src/components/docs-live/DagStatusChip.tsx
  • ui/src/components/docs-live/DocLiveProvider.tsx
  • ui/src/components/docs-live/__tests__/DaguRunBlock.test.tsx
  • ui/src/components/docs-live/__tests__/DocLiveProvider.test.tsx
  • ui/src/components/ui/__tests__/doc-markdown-preview.test.tsx
  • ui/src/components/ui/doc-markdown-preview.tsx
  • ui/src/features/dags/components/__tests__/DAGStatus.test.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsContent.tsx
  • ui/src/features/dags/components/dag-details/DAGDocsTab.tsx
  • ui/src/features/dags/components/dag-details/__tests__/DAGDetailsContent.test.tsx
  • ui/src/features/search/components/SearchResult.tsx
  • ui/src/lib/remark-wikilink.ts
  • ui/src/pages/docs/components/CreateDocModal.tsx
  • ui/src/pages/docs/components/DocBacklinksPanel.tsx
  • ui/src/pages/docs/components/DocEditor.tsx
  • ui/src/pages/docs/components/DocHistoryModal.tsx
  • ui/src/pages/docs/components/DocTreeSidebar.tsx
  • ui/src/pages/docs/components/__tests__/DocEditor.test.tsx
  • ui/src/pages/docs/index.tsx
  • ui/src/pages/docs/lib/doc-path.ts
  • ui/src/pages/docs/lib/doc-templates.ts
  • ui/src/pages/git-sync/DiffModal.tsx
🚧 Files skipped from review as they are similar to previous changes (22)
  • internal/core/docs/link_test.go
  • ui/src/components/docs-live/tests/DaguRunBlock.test.tsx
  • internal/gitsync/git.go
  • internal/core/docs/link.go
  • ui/src/components/ui/tests/doc-markdown-preview.test.tsx
  • internal/gitsync/pull_external_test.go
  • ui/src/features/dags/components/dag-details/tests/DAGDetailsContent.test.tsx
  • internal/persis/file/doc/attachment.go
  • internal/service/frontend/api/v1/sync.go
  • internal/service/frontend/api/v1/docs_test.go
  • internal/persis/file/doc/store.go
  • internal/gitsync/service.go
  • ui/src/pages/docs/components/DocBacklinksPanel.tsx
  • ui/src/pages/docs/components/DocTreeSidebar.tsx
  • ui/src/components/docs-live/tests/DocLiveProvider.test.tsx
  • ui/src/pages/docs/components/CreateDocModal.tsx
  • ui/src/pages/git-sync/DiffModal.tsx
  • ui/src/pages/docs/lib/doc-templates.ts
  • ui/src/pages/docs/components/DocEditor.tsx
  • ui/src/pages/docs/index.tsx
  • ui/src/pages/docs/components/DocHistoryModal.tsx
  • ui/src/lib/remark-wikilink.ts

Comment thread ui/src/features/dags/components/dag-details/DAGDocsTab.tsx Outdated

yohamta0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ui/src/features/dags/components/dag-details/__tests__/DAGDocsTab.test.tsx (1)

4-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reorder imports by dependency group.

Place the external imports before @/contexts/AppBarContext and ../DAGDocsTab. Add a blank line between the external and internal groups.

As per coding guidelines, keep imports organized with external packages first, then internal modules.

Proposed import order
-import { AppBarContext } from '`@/contexts/AppBarContext`';
 import { render, screen } from '`@testing-library/react`';
 import React from 'react';
 import { MemoryRouter } from 'react-router-dom';
 import { describe, expect, it, vi } from 'vitest';
+
+import { AppBarContext } from '`@/contexts/AppBarContext`';
 import DAGDocsTab from '../DAGDocsTab';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-details/__tests__/DAGDocsTab.test.tsx`
around lines 4 - 9, Reorder imports in DAGDocsTab.test.tsx so external packages
come first, followed by a blank line, then the internal AppBarContext and
DAGDocsTab imports.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@ui/src/features/dags/components/dag-details/__tests__/DAGDocsTab.test.tsx`:
- Around line 4-9: Reorder imports in DAGDocsTab.test.tsx so external packages
come first, followed by a blank line, then the internal AppBarContext and
DAGDocsTab imports.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ecafc329-146e-46f8-895e-b2692c7cab04

📥 Commits

Reviewing files that changed from the base of the PR and between ab005ec and 6c27d93.

📒 Files selected for processing (2)
  • ui/src/features/dags/components/dag-details/DAGDocsTab.tsx
  • ui/src/features/dags/components/dag-details/__tests__/DAGDocsTab.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • ui/src/features/dags/components/dag-details/DAGDocsTab.tsx

yohamta0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Addressed the final CodeRabbit import-grouping nitpick in 315838ae8; changed-file ESLint remains clean.

yohamta0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yohamta0
yohamta0 merged commit 866f5ba into main Aug 9, 2026
15 checks passed
@yohamta0
yohamta0 deleted the feat/docs-wiki branch August 9, 2026 02:56
@coderabbitai coderabbitai Bot mentioned this pull request Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant