Skip to content

docs: c4 architecture diagrams#7

Merged
yacosta738 merged 2 commits into
mainfrom
docs/c4-architecture-diagrams
Feb 16, 2026
Merged

docs: c4 architecture diagrams#7
yacosta738 merged 2 commits into
mainfrom
docs/c4-architecture-diagrams

Conversation

@yacosta738
Copy link
Copy Markdown
Contributor

This pull request contains several changes across the iOS, Rust backend, Kotlin Compose, and web documentation projects. The most significant updates include improvements to atomic config file replacement in the Rust backend, code style cleanups in the Kotlin Compose chat UI, a visual update to the onboarding banner, and enhancements to the documentation structure for the web client. Additionally, there are removals of iOS Xcode project files, likely as part of a migration or cleanup.

Rust Backend Improvements:

  • Improved atomic config file replacement logic in schema.rs: Now, if the atomic rename fails due to certain OS errors (e.g., EBUSY or EXDEV), the code falls back to an in-place file write, increasing robustness when dealing with bind-mounted files. Includes new helper functions and tests for this behavior. [1] [2] [3]
  • Updated onboarding banner in wizard.rs to a more concise and visually appealing ASCII art.

Kotlin Compose UI Cleanups:

  • Refactored the ChatWorkspace.kt file for improved code readability by collapsing multi-line expressions into single lines and simplifying function calls, without changing functionality. [1] [2] [3] [4] [5] [6]

Web Documentation Enhancements:

  • Updated the Astro documentation config to restructure the "Architecture" section into a group with sub-items, improving navigation and translation support. [1] [2]
  • Updated .gitignore to include Astro build artifacts, preventing unnecessary files from being tracked.

iOS Project Cleanup:

  • Removed iosApp.xcodeproj/project.pbxproj and iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata, possibly due to project restructuring or migration. [1] [2]

@github-actions
Copy link
Copy Markdown
Contributor

Thank you for contributing to this project with this PR, welcome to the community and the amazing world of open source!

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 16, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added comprehensive C4 architecture diagrams (Context, Container, Component, and Module Dependencies) for system visualization.
  • Documentation

    • Expanded architecture guides with detailed system overview and high-level components.
    • Reorganized documentation structure and enhanced module dependency documentation.
  • Bug Fixes

    • Improved configuration file save reliability with automatic fallback mechanism.
    • Enhanced build system symlink handling.

Walkthrough

This PR removes iOS Xcode project configuration, enhances build system ignore patterns, adds resilient config file handling with platform-specific fallback logic, refactors UI component formatting, significantly expands architectural documentation with C4-model diagrams (Mermaid and PlantUML formats) in English and Spanish, and implements docs directory symlink management in the web build.

Changes

Cohort / File(s) Summary
iOS Project Removal
apps/iosApp/iosApp.xcodeproj/project.pbxproj, apps/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
Entirely removes Xcode project configuration including PBX file references, build phases, targets, and workspace metadata.
.gitignore Updates
.gitignore, clients/web/.gitignore
Adds ignore patterns for Astro/Vite artifacts, Gradle-generated docs symlink, and Spotless Prettier build artifacts with nested dependencies.
Agent Runtime Configuration
clients/agent-runtime/src/config/schema.rs
Adds platform-specific fallback logic for atomic file rename failures, including in-place write helper, errno-based decision logic (Unix-only), backup/rollback handling, and conditional unit tests.
UI Component Updates
clients/agent-runtime/src/onboard/wizard.rs, clients/composeApp/src/commonMain/kotlin/.../ChatWorkspace.kt
Replaces ASCII banner text and reformats multiline data structures to single-line constructors without altering control flow or logic.
Architecture Documentation (English & Spanish)
clients/web/apps/docs/src/content/docs/en/guides/architecture.md, clients/web/apps/docs/src/content/docs/en/guides/structure.md, clients/web/apps/docs/src/content/docs/es/guides/architecture.md, clients/web/apps/docs/src/content/docs/es/guides/structure.md
Substantially expands architectural descriptions with high-level pillars, build logic conventions, dependency management details, reorganizes project structure from apps/ to clients/, and adds module dependency diagrams.
C4 Architecture Diagrams (English)
clients/web/apps/docs/src/content/docs/en/guides/architecture/index.md, clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/context/system-context.mmd, clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/container/system-containers.mmd, clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/container/system-containers.puml, clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/component/agent-core-kmp.mmd, clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/module-dependencies.mmd
Introduces comprehensive C4-model diagrams (Mermaid and PlantUML) documenting system context, containers, components, and module dependencies with styling and relationship definitions.
C4 Architecture Diagrams (Spanish)
clients/web/apps/docs/src/content/docs/es/guides/architecture/index.md, clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/context/system-context.mmd, clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/container/system-containers.mmd, clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/container/system-containers.puml, clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/component/agent-core-kmp.mmd, clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/module-dependencies.mmd
Spanish translation of C4-model architecture diagrams with equivalent content structure and diagram definitions as English versions.
Web Build Configuration
clients/web/apps/docs/astro.config.mjs, clients/web/build.gradle.kts
Updates Astro navigation to restructure Architecture guide with subsections, and adds Gradle logic for docs directory symlink verification/creation with fallback to empty directory on failure.

Sequence Diagram

sequenceDiagram
    participant Caller as Caller
    participant Schema as Config Schema
    participant FS as File System
    participant Backup as Backup System
    
    Caller->>Schema: save_config(path, contents)
    Schema->>FS: atomic_rename(temp, target)
    
    alt Atomic Rename Success
        FS-->>Schema: Ok()
        Schema-->>Caller: Success
    else Atomic Rename Fails
        FS-->>Schema: Err(errno)
        Schema->>Schema: should_fallback?<br/>(check errno)
        
        alt Should Fallback (EBUSY/EXDEV)
            Schema->>FS: write_config_in_place(target)
            
            alt In-Place Write Success
                FS-->>Schema: Ok()
                Schema-->>Caller: Success (Fallback)
            else In-Place Write Fails
                FS-->>Schema: Err(io_error)
                Schema->>Backup: restore_from_backup(target)
                Backup-->>Schema: restored
                Schema-->>Caller: Err(combined_error)
            end
        else No Fallback (Other errno)
            Schema-->>Caller: Err(original_error)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Poem

🐰 Hops with glee through architectural dreams,
C4 diagrams flow like rabbit streams!
With fallback logic, symlinks precise,
Config writes bundled, documentation nice.
iOS gone, docs expanded wide,
This little rabbit's bursting with pride!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'docs: c4 architecture diagrams' directly reflects the main purpose of the PR, which is to add C4 architecture diagrams to the documentation.
Description check ✅ Passed The PR description is comprehensive and well-organized, covering all major changes across multiple projects (Rust backend, Kotlin Compose, Web docs, and iOS). However, it lacks some template sections like explicit 'Related Issues', 'Tested Information', and 'Breaking Changes' declarations, though the description content itself is substantial and informative.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch docs/c4-architecture-diagrams

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 and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

✅ Contributor Report

User: @yacosta738
Status: Passed (12/13 metrics passed)

Metric Description Value Threshold Status
PR Merge Rate PRs merged vs closed 89% >= 30%
Repo Quality Repos with ≥100 stars 0 >= 0
Positive Reactions Positive reactions received 9 >= 1
Negative Reactions Negative reactions received 0 <= 5
Account Age GitHub account age 3034 days >= 30 days
Activity Consistency Regular activity over time 108% >= 0%
Issue Engagement Issues with community engagement 0 >= 0
Code Reviews Code reviews given to others 362 >= 0
Merger Diversity Unique maintainers who merged PRs 3 >= 0
Repo History Merge Rate Merge rate in this repo 67% >= 0%
Repo History Min PRs Previous PRs in this repo 4 >= 0
Profile Completeness Profile richness (bio, followers) 90 >= 0
Suspicious Patterns Spam-like activity detection 1 N/A

Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-02-16 to 2026-02-16

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 26

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt (3)

232-240: 🛠️ Refactor suggestion | 🟠 Major

Reduce parameter count in ChatPanel to satisfy Detekt.
Detekt flags LongParameterList here. Group related inputs into a ChatPanelState + ChatPanelHandlers.

♻️ Proposed refactor (parameter grouping)
+data class ChatPanelState(
+  val modelName: String,
+  val inputPlaceholder: String,
+  val messages: List<ChatMessage>,
+  val query: String,
+)
+
+data class ChatPanelHandlers(
+  val onQueryChange: (String) -> Unit,
+  val onSend: () -> Unit,
+)
+
 private fun ChatPanel(
-  modelName: String,
-  inputPlaceholder: String,
-  messages: List<ChatMessage>,
-  query: String,
-  onQueryChange: (String) -> Unit,
-  onSend: () -> Unit,
+  state: ChatPanelState,
+  handlers: ChatPanelHandlers,
   modifier: Modifier = Modifier,
 ) {
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`
around lines 232 - 240, The ChatPanel function has too many parameters and
triggers Detekt's LongParameterList; refactor by introducing two data holder
types: ChatPanelState (containing modelName, inputPlaceholder, messages, query)
and ChatPanelHandlers (containing onQueryChange and onSend), then update the
ChatPanel signature to accept (state: ChatPanelState, handlers:
ChatPanelHandlers, modifier: Modifier = Modifier) and update all call sites to
construct/pass the new objects; ensure ChatPanel internals reference
state.modelName etc. and preserve existing behavior and visibility.

151-165: 🛠️ Refactor suggestion | 🟠 Major

Reduce parameter count in ChatWorkspaceScreen to satisfy Detekt.
Detekt flags LongParameterList here. Consider grouping callbacks and UI state into data classes.

♻️ Proposed refactor (parameter grouping)
+data class ChatWorkspaceUi(
+  val state: ChatWorkspaceState,
+  val messages: List<ChatMessage>,
+  val query: String,
+  val showConfig: Boolean,
+  val gatewayConfig: AgentGatewayConfig,
+)
+
+data class ChatWorkspaceHandlers(
+  val onQueryChange: (String) -> Unit,
+  val onSend: () -> Unit,
+  val onToggleConfig: () -> Unit,
+  val onBaseUrlChange: (String) -> Unit,
+  val onPairingCodeChange: (String) -> Unit,
+  val onBearerTokenChange: (String) -> Unit,
+  val onWebhookSecretChange: (String) -> Unit,
+)
+
 private fun ChatWorkspaceScreen(
-  state: ChatWorkspaceState,
-  messages: List<ChatMessage>,
-  query: String,
-  showConfig: Boolean,
-  gatewayConfig: AgentGatewayConfig,
-  onQueryChange: (String) -> Unit,
-  onSend: () -> Unit,
-  onToggleConfig: () -> Unit,
-  onBaseUrlChange: (String) -> Unit,
-  onPairingCodeChange: (String) -> Unit,
-  onBearerTokenChange: (String) -> Unit,
-  onWebhookSecretChange: (String) -> Unit,
+  ui: ChatWorkspaceUi,
+  handlers: ChatWorkspaceHandlers,
   modifier: Modifier = Modifier,
 ) {
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`
around lines 151 - 165, The ChatWorkspaceScreen function has too many parameters
(ChatWorkspaceState, messages, query, showConfig, gatewayConfig and many
callbacks like onQueryChange, onSend, onToggleConfig, onBaseUrlChange,
onPairingCodeChange, onBearerTokenChange, onWebhookSecretChange) which triggers
Detekt's LongParameterList; refactor by creating small data-holder classes such
as ChatWorkspaceUiState (wrapping state, messages, query, showConfig,
gatewayConfig) and ChatWorkspaceCallbacks (wrapping onQueryChange, onSend,
onToggleConfig, onBaseUrlChange, onPairingCodeChange, onBearerTokenChange,
onWebhookSecretChange) and replace the long parameter list with these two
objects plus an optional Modifier, updating call sites and tests accordingly to
pass the grouped objects instead of individual params.

281-388: 🛠️ Refactor suggestion | 🟠 Major

Split ConfigPanel to fix Detekt LongParameterList + LongMethod.
Detekt flags parameter count and method length. Extract endpoint cards and field groups into helpers.

♻️ Proposed refactor (extract sections)
 private fun ConfigPanel(
   gatewayConfig: AgentGatewayConfig,
   onBaseUrlChange: (String) -> Unit,
   onPairingCodeChange: (String) -> Unit,
   onBearerTokenChange: (String) -> Unit,
   onWebhookSecretChange: (String) -> Unit,
   modifier: Modifier = Modifier,
 ) {
-  val healthUrl = endpointUrl(gatewayConfig.baseUrl, "/health")
-  val pairUrl = endpointUrl(gatewayConfig.baseUrl, "/pair")
-  val webhookUrl = endpointUrl(gatewayConfig.baseUrl, "/webhook")
-
   Surface( ... ) {
     LazyColumn( ... ) {
-      item { ... baseUrl field ... }
-      item { ... pairingCode field ... }
-      item { ... bearerToken field ... }
-      item { ... webhookSecret field ... }
-      item { EndpointCard(... health ...) }
-      item { EndpointCard(... pair ...) }
-      item { EndpointCard(... webhook ...) }
+      item { ConfigFields(gatewayConfig, onBaseUrlChange, onPairingCodeChange, onBearerTokenChange, onWebhookSecretChange) }
+      item { EndpointCards(gatewayConfig.baseUrl) }
     }
   }
 }
+
+@Composable
+private fun ConfigFields(
+  gatewayConfig: AgentGatewayConfig,
+  onBaseUrlChange: (String) -> Unit,
+  onPairingCodeChange: (String) -> Unit,
+  onBearerTokenChange: (String) -> Unit,
+  onWebhookSecretChange: (String) -> Unit,
+) { ... }
+
+@Composable
+private fun EndpointCards(baseUrl: String) { ... }
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`
around lines 281 - 388, ConfigPanel is flagged by Detekt for too many parameters
and being too long; split it into smaller composable helpers to reduce parameter
count and method size. Extract the input fields into a new composable (e.g.,
ConfigFields) that accepts gatewayConfig and the four onXChange callbacks and
renders the OutlinedTextField items, and extract the endpoint UI into another
composable (e.g., EndpointCardsSection or EndpointList) that builds the
EndpointCard calls using endpointUrl(gatewayConfig.baseUrl, ...). Keep
ConfigPanel thin: compute healthUrl/pairUrl/webhookUrl as needed or pass only
gatewayConfig to the helpers, remove unrelated formatting logic into those
helpers, and call them from ConfigPanel so function length and parameter list
are reduced.
🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In @.gitignore:
- Line 147: Remove the redundant gitignore entry
"clients/web/apps/**/node_modules/" because it is already covered by the broader
"**/node_modules/" pattern; delete the specific pattern line and keep only the
global "**/node_modules/" entry to avoid duplication.
- Line 149: The comment "# Symlinks auto-generados por Gradle" in the .gitignore
is in Spanish while the rest of the file is English; update that comment to
English for consistency (e.g., change the line containing "Symlinks
auto-generados por Gradle" to "Gradle auto-generated symlinks" or similar),
preserving the comment marker and placement.

In `@clients/agent-runtime/src/config/schema.rs`:
- Around line 1085-1105: The fallback in write_config_in_place can leave the
target file truncated if the process dies mid-write; update load_or_init to
detect and recover from this by checking after open/read whether the current
config file is empty or fails to deserialize and, if so, look for the existing
backup (backup_path/.bak) and atomically restore it before proceeding (or return
a clear descriptive error if restore fails); reference load_or_init,
write_config_in_place, self.config_path, and backup_path in your changes and
ensure the backup is restored prior to any further config parsing so startup can
automatically recover from a truncated config file.
- Around line 1151-1155: Replace the magic errno integers in
should_fallback_to_in_place_write with named constants: update the matches!
check to compare against descriptive constants rather than raw 16 and 18. You
can either reference libc::EBUSY and libc::EXDEV (add libc dependency), use
std::io::ErrorKind variants if MSRV permits, or define local const EBUSY and
EXDEV integers at the top of the module and use those; ensure the function still
matches error.raw_os_error() against Some(EBUSY | EXDEV) equivalents and keep
the #[cfg(unix)] attribute on should_fallback_to_in_place_write.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`:
- Around line 232-240: The ChatPanel function has too many parameters and
triggers Detekt's LongParameterList; refactor by introducing two data holder
types: ChatPanelState (containing modelName, inputPlaceholder, messages, query)
and ChatPanelHandlers (containing onQueryChange and onSend), then update the
ChatPanel signature to accept (state: ChatPanelState, handlers:
ChatPanelHandlers, modifier: Modifier = Modifier) and update all call sites to
construct/pass the new objects; ensure ChatPanel internals reference
state.modelName etc. and preserve existing behavior and visibility.
- Around line 151-165: The ChatWorkspaceScreen function has too many parameters
(ChatWorkspaceState, messages, query, showConfig, gatewayConfig and many
callbacks like onQueryChange, onSend, onToggleConfig, onBaseUrlChange,
onPairingCodeChange, onBearerTokenChange, onWebhookSecretChange) which triggers
Detekt's LongParameterList; refactor by creating small data-holder classes such
as ChatWorkspaceUiState (wrapping state, messages, query, showConfig,
gatewayConfig) and ChatWorkspaceCallbacks (wrapping onQueryChange, onSend,
onToggleConfig, onBaseUrlChange, onPairingCodeChange, onBearerTokenChange,
onWebhookSecretChange) and replace the long parameter list with these two
objects plus an optional Modifier, updating call sites and tests accordingly to
pass the grouped objects instead of individual params.
- Around line 281-388: ConfigPanel is flagged by Detekt for too many parameters
and being too long; split it into smaller composable helpers to reduce parameter
count and method size. Extract the input fields into a new composable (e.g.,
ConfigFields) that accepts gatewayConfig and the four onXChange callbacks and
renders the OutlinedTextField items, and extract the endpoint UI into another
composable (e.g., EndpointCardsSection or EndpointList) that builds the
EndpointCard calls using endpointUrl(gatewayConfig.baseUrl, ...). Keep
ConfigPanel thin: compute healthUrl/pairUrl/webhookUrl as needed or pass only
gatewayConfig to the helpers, remove unrelated formatting logic into those
helpers, and call them from ConfigPanel so function length and parameter list
are reduced.

In `@clients/web/.gitignore`:
- Around line 40-43: The .gitignore contains a redundant pattern: remove the
duplicate `.astro/` entry so only the recursive pattern `**/.astro/` remains
(keep `**/.astro/` and delete the separate `.astro/` line) to avoid duplication
while preserving the same ignore behavior.

In `@clients/web/apps/docs/astro.config.mjs`:
- Around line 119-133: The two sidebar entries use colliding slugs
('guides/architecture' and 'guides/architecture/index') which both resolve to
the same page; fix by giving the "C4 Diagrams" item a unique slug and matching
content file: rename the content file guides/architecture/index.md (or create a
new file) to guides/architecture/c4-diagrams.md and update the sidebar entry
slug from 'guides/architecture/index' to 'guides/architecture/c4-diagrams' (keep
label/translations the same) so Starlight/Astro resolves each page separately.

In `@clients/web/apps/docs/src/content/docs/en/guides/architecture.md`:
- Around line 59-119: Remove the duplicated "Build Logic (Convention Plugins)"
and "Dependency Management" sections (including the Kotlin dependencies example
code block) that appear a second time in the file so only the original headings
and content remain; search for the headings "Build Logic (Convention Plugins)"
and "Dependency Management" and delete the later copy (the repeated dependencies
{ implementation(libs.kotlin.stdlib) ... } example and the repeated explanatory
text) while keeping the C4 diagrams and Architecture Index links intact.

In
`@clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/component/agent-core-kmp.mmd`:
- Line 56: The file defines a CSS class "classDef domain" but never applies it
to any node, so either remove that unused definition or apply it to the
domain-layer nodes to create visual differentiation; locate the "classDef domain
fill:`#85bbf0`,stroke:`#5d8fc9`,stroke-width:2px,color:`#000`" line and either delete
it or add "class <NodeName> domain" statements for the nodes that represent the
domain layer (currently all nodes use the "component" class), ensuring you
replace <NodeName> with the actual node identifiers you want styled.

In
`@clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/container/system-containers.mmd`:
- Around line 9-10: The two actor nodes currently use the same Mermaid node type
ID ("actor(Developer)" and "actor(EndUser)") causing duplicate IDs; change them
to use distinct explicit node IDs/labels (e.g., Developer(("Developer")) and
EndUser(("EndUser"))) so each actor has a unique identifier, updating the actor
node declarations that currently read actor(Developer) and actor(EndUser) to the
suggested unique forms.
- Line 64: The classDef currently uses an invalid `shape:cylinder`; remove
`shape:cylinder` from the `classDef database` definition and instead define the
GRAPH_DB node using the Mermaid cylinder node syntax (e.g., [("label")]) so the
database appears as a cylinder; update the node named GRAPH_DB to use the
`[("GRAPH_DB")]`-style label and leave `classDef database
fill:`#438dd5`,stroke:`#2e6299`,stroke-width:2px,color:`#fff`` without
`shape:cylinder`.

In
`@clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/container/system-containers.puml`:
- Line 6: Replace the remote PlantUML include that currently references the
repository default branch in system-containers.puml (the line starting with
"!include
https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml")
with a pinned release URL pointing to the stable tag (e.g., v2.13.0) so the
diagram uses a specific, immutable version of C4_PlantUML and avoids silent
breakage from upstream changes.

In
`@clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/context/system-context.mmd`:
- Around line 9-10: Both actor lines reuse the literal node id "actor" and the
later relationships refer to undefined IDs "Developer" and "EndUser"; change
each actor definition to a unique node id and apply the :::person class to those
ids (e.g., replace actor(Developer) with DeveloperActor(Developer):::person and
actor(EndUser) with EndUserActor(EndUser):::person) and then update any
relationship references that use Developer or EndUser to use DeveloperActor and
EndUserActor so the styled nodes are the ones referenced.

In
`@clients/web/apps/docs/src/content/docs/en/guides/architecture/diagrams/module-dependencies.mmd`:
- Line 12: The legend node ID EXTERNAL (from the node declaration
EXTERNAL["External"]:::external) conflicts with the subgraph ID EXTERNAL (the
subgraph defined around lines 32-39); rename the legend node ID to a unique
identifier (e.g., EXTERNAL_LEGEND or LEGEND_EXTERNAL) and update any internal
references/styles for that node so the node declaration and the subgraph ID are
distinct.

In `@clients/web/apps/docs/src/content/docs/en/guides/architecture/index.md`:
- Around line 45-65: Add missing blank lines around headings and fenced code
blocks to satisfy MD022/MD031: ensure there is an empty line before and after
the "### Option 3: Mermaid CLI" and its triple-backtick bash block, and add an
empty line before the "### Option 4: PlantUML" heading, an empty line between
that heading and the "For `.puml` files:" paragraph, and an empty line before
and after the triple-backtick bash block for PlantUML; update the sections
referenced by "### Option 3: Mermaid CLI" and "### Option 4: PlantUML"
accordingly.

In `@clients/web/apps/docs/src/content/docs/es/guides/architecture.md`:
- Line 119: The link text `Ver [Índice de Diagramas](./architecture/index.md)
(en inglés)` points to the Spanish index but is labeled as English; fix by
either updating the link target to the English index file (replace the
`./architecture/index.md` target with the English index) or changing the label
to reflect Spanish (e.g., replace “(en inglés)” with “(en español)”) so the link
label and destination match.
- Around line 86-106: Update the fenced ASCII diagram block in the docs file by
adding a language specifier ``text`` to the opening code fence so markdownlint
MD040 is satisfied; locate the ASCII diagram block in the architecture.md
content and change the opening "```" to "```text" (leave the closing "```"
unchanged) to preserve rendering while fixing the lint error.

In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/component/agent-core-kmp.mmd`:
- Around line 16-37: Translate the node labels inside the Mermaid diagram to
Spanish to match the subgraph titles: update ENTITIES, VALUE_OBJECTS,
DOMAIN_EVENTS, TASK_MGMT, AGENT_ORCH, KNOWLEDGE, REPOS, SERVICES, REPO_IMPL,
SERVICE_IMPL, and DTOS labels (currently English like "Entities", "Value
Objects", "Task Management", "Repository Implementations", etc.) to their
Spanish equivalents (e.g., "Entidades", "Objetos de Valor", "Eventos de
Dominio", "Gestión de Tareas", "Orquestación de Agentes", "Recuperación de
Conocimiento", "Interfaces de Repositorio", "Interfaces de Servicio",
"Implementaciones de Repositorio", "Implementaciones de Servicio", "DTOs /
Modelos" or similar) so the node text matches the Spanish subgraph titles.

In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/container/system-containers.mmd`:
- Line 64: The classDef line currently uses an invalid property "shape:cylinder"
(see classDef database), so remove "shape:cylinder" from the classDef and
instead define the database node using Mermaid's cylinder node syntax in the
node declaration (e.g., use the [("label")] form for the database node name you
want to style) while keeping the remaining CSS-like styles in classDef database;
update the node line that references the database class to use the cylinder node
syntax and assign it the class.
- Around line 9-10: The two Mermaid actor nodes use the same implicit ID because
both lines use the actor(...) shorthand, causing one to overwrite the other;
update the declarations to give each actor a unique explicit ID (e.g., actor
DeveloperActor as "Developer" and actor EndUserActor as "EndUser", or use the
explicit node syntax with unique IDs) so that the nodes `actor(Developer)` and
`actor(EndUser)` no longer collide and both render correctly.

In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/container/system-containers.puml`:
- Line 6: The PlantUML include currently references the remote C4_Container.puml
via the master branch URL (!include
https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml),
which is brittle; update that include to point to a specific stable release tag
(e.g., replace "master" with a release like "v2.13.0") so the file referenced by
the include remains reproducible and won't break if the default branch name or
trunk changes.

In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/context/system-context.mmd`:
- Around line 1-6: The Spanish diagram file contains an extra metadata line "#
Git SHA: (current)" that is not present in the English counterpart; either
remove that metadata line from system-context.mmd in the Spanish locale or add
the same "# Git SHA: (current)" metadata line to the English diagram file so
both locales are consistent. Locate the line "# Git SHA: (current)" in
system-context.mmd and apply one of the two changes, then run a quick locale
diff to confirm parity.
- Around line 10-11: The diagram uses the generic node id "actor" twice
(actor(Developer) and actor(EndUser)), causing ID collisions and leaving
references to Developer/EndUser undefined; update those actor declarations to
explicitly set unique IDs that match the later references (e.g., change
actor(Developer):::person to "actor Developer as \"Developer\":::person" or the
equivalent mermaid form that yields id Developer, and similarly change
actor(EndUser):::person to set id EndUser) so the later references to Developer
and EndUser resolve correctly.

In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/module-dependencies.mmd`:
- Line 12: Rename one of the conflicting Mermaid IDs so they are unique: change
either the node ID "EXTERNAL" (the EXTERNAL["Externo"] node) or the subgraph
named "EXTERNAL" to a distinct identifier (e.g., "EXTERNAL_LEGEND" or
"EXTERNAL_SUBGRAPH"), and update any references/edges and class/stylesheet
mentions (such as :::external or any links to EXTERNAL) to the new name to keep
all IDs consistent.

In `@clients/web/build.gradle.kts`:
- Around line 11-35: The log messages and comments around the symlink setup
(variables rootProjectDir, docsSymlink, docsTarget and the
Files.createSymbolicLink block) are in Spanish; change all comments and logger
messages (logger.lifecycle, logger.warn) to English to match the rest of the
build file (e.g., "Create symlink: docs →
clients/web/apps/docs/src/content/docs", "Could not create docs symlink:
${e.message}", "Creating docs directory as fallback...", "Target does not exist:
$docsTarget", "Symlink docs already exists → $target", "Docs directory already
exists (not a symlink)"). Ensure the code logic and message content remain
identical aside from language so only message strings and comments are updated.
- Around line 18-26: The catch block for Files.createSymbolicLink is too generic
(causing Detekt TooGenericExceptionCaught); replace the broad catch(Exception)
with explicit catches for the exceptions that createSymbolicLink can throw
(e.g., java.io.IOException, java.nio.file.FileAlreadyExistsException,
java.lang.UnsupportedOperationException, java.lang.SecurityException) around the
Files.createSymbolicLink(docsSymlink, docsTarget) call, handling each case
similarly to the current fallback (logger.warn + create fallback
docsSymlink.toFile().mkdirs()) or consolidating the specific exceptions into a
multi-catch to satisfy Detekt while preserving the existing logging and fallback
behavior.
- Around line 16-29: The current check uses Files.exists(docsSymlink) which
follows symlinks and misses broken symlinks, causing
Files.createSymbolicLink(docsSymlink, docsTarget) to throw if a broken link
entry already exists; update the logic around docsSymlink/docsTarget to first
check Files.exists(docsSymlink, LinkOption.NOFOLLOW_LINKS) or
Files.isSymbolicLink(docsSymlink) to detect an existing symlink, and if a
symlink exists but points to a missing target remove the broken symlink (or skip
creation) before calling Files.createSymbolicLink; ensure all references to
docsSymlink and docsTarget are adjusted to use LinkOption.NOFOLLOW_LINKS where
appropriate and keep the existing fallback behavior if creation still fails.

Comment thread .gitignore
# Astro cache/build directories
**/.astro/
clients/web/apps/**/dist/
clients/web/apps/**/node_modules/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Redundant pattern: already covered by **/node_modules/ on line 92.

The global **/node_modules/ pattern already matches all node_modules/ directories at any depth, making this more specific pattern unnecessary.

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In @.gitignore at line 147, Remove the redundant gitignore entry
"clients/web/apps/**/node_modules/" because it is already covered by the broader
"**/node_modules/" pattern; delete the specific pattern line and keep only the
global "**/node_modules/" entry to avoid duplication.

Comment thread .gitignore
clients/web/apps/**/dist/
clients/web/apps/**/node_modules/

# Symlinks auto-generados por Gradle
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent comment language.

This comment is in Spanish while the rest of the file uses English. Consider aligning for consistency:

Proposed fix
-# Symlinks auto-generados por Gradle
+# Symlinks auto-generated by Gradle
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Symlinks auto-generados por Gradle
# Symlinks auto-generated by Gradle
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In @.gitignore at line 149, The comment "# Symlinks auto-generados por Gradle"
in the .gitignore is in Spanish while the rest of the file is English; update
that comment to English for consistency (e.g., change the line containing
"Symlinks auto-generados por Gradle" to "Gradle auto-generated symlinks" or
similar), preserving the comment marker and placement.

Comment on lines +1085 to 1105
if should_fallback_to_in_place_write(&e) {
if let Err(write_err) =
write_config_in_place(&self.config_path, toml_str.as_bytes())
{
let _ = fs::remove_file(&temp_path);
if had_existing_config && backup_path.exists() {
let _ = fs::copy(&backup_path, &self.config_path);
}
anyhow::bail!(
"Failed to replace config file after atomic fallback: {write_err} \
(rename error: {e})"
);
}
let _ = fs::remove_file(&temp_path);
} else {
let _ = fs::remove_file(&temp_path);
if had_existing_config && backup_path.exists() {
let _ = fs::copy(&backup_path, &self.config_path);
}
anyhow::bail!("Failed to atomically replace config file: {e}");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fallback logic is sound, but note the non-atomic window for in-place writes.

When the in-place fallback path is taken, the target file is opened with truncate(true) before the new contents are written. If the process is killed between truncation and the completed write_all + sync_all, the config file will be left empty or partially written. The backup file (.bak) does survive past this point (it's only cleaned up at Line 1111), so manual recovery is possible — but there's no automatic recovery on next startup.

Consider documenting this risk or adding a brief note in load_or_init to check for a .bak file and offer recovery if the config is empty/corrupt.

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@clients/agent-runtime/src/config/schema.rs` around lines 1085 - 1105, The
fallback in write_config_in_place can leave the target file truncated if the
process dies mid-write; update load_or_init to detect and recover from this by
checking after open/read whether the current config file is empty or fails to
deserialize and, if so, look for the existing backup (backup_path/.bak) and
atomically restore it before proceeding (or return a clear descriptive error if
restore fails); reference load_or_init, write_config_in_place, self.config_path,
and backup_path in your changes and ensure the backup is restored prior to any
further config parsing so startup can automatically recover from a truncated
config file.

Comment on lines +1151 to +1155
#[cfg(unix)]
fn should_fallback_to_in_place_write(error: &std::io::Error) -> bool {
// Bind-mounted files can reject replace-style renames with EBUSY/EXDEV.
matches!(error.raw_os_error(), Some(16 | 18))
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🌐 Web query:

std::io::ErrorKind::ResourceBusy and CrossesDevices Rust stabilization version

💡 Result:

  • std::io::ErrorKind::ResourceBusy was stabilized in Rust 1.83.0. [2][1]
  • std::io::ErrorKind::CrossesDevices was stabilized in Rust 1.85.0. [1]

Sources:
[1] Rust standard library docs: std::io::ErrorKind (shows per-variant stabilization versions) https://doc.rust-lang.org/std/io/enum.ErrorKind.html
[2] Rust 1.83.0 release post (lists ErrorKind::ResourceBusy as stabilized) https://blog.rust-lang.org/2024/11/28/Rust-1.83.0/


🏁 Script executed:

# Check if libc is already a dependency
find . -name "Cargo.toml" -type f -exec grep -l "libc" {} \;

Repository: dallay/corvus

Length of output: 39


🏁 Script executed:

# Check the project's Rust MSRV/version requirements in Cargo.toml
fd "Cargo.toml" --maxdepth 3 | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && head -20 "{}"'

Repository: dallay/corvus

Length of output: 812


🏁 Script executed:

# Verify errno values - check if there's any documentation in the codebase about this
rg "EBUSY|EXDEV" --type rust -A 3 -B 3

Repository: dallay/corvus

Length of output: 572


🏁 Script executed:

# Check for rust-version (MSRV) in Cargo.toml
rg "rust-version|edition" clients/agent-runtime/Cargo.toml

Repository: dallay/corvus

Length of output: 73


🏁 Script executed:

# Also check root Cargo.toml for workspace-level MSRV
rg "rust-version|edition" Cargo.toml

Repository: dallay/corvus

Length of output: 107


Use named constants instead of magic errno numbers.

Raw 16 and 18 are less readable and potentially fragile. While these values are consistent across Linux and macOS, using named constants is more idiomatic and self-documenting.

Options:

  1. Use libc::EBUSY and libc::EXDEV (add libc as a dependency if not already present).
  2. Use std::io::ErrorKind::ResourceBusy and std::io::ErrorKind::CrossesDevices (stabilized in Rust 1.83.0 and 1.85.0 respectively—only feasible if project's MSRV supports this).
  3. At minimum, define local constants (no new dependency).
♻️ Option 3 — local constants (no new dependency)
 #[cfg(unix)]
 fn should_fallback_to_in_place_write(error: &std::io::Error) -> bool {
-    // Bind-mounted files can reject replace-style renames with EBUSY/EXDEV.
-    matches!(error.raw_os_error(), Some(16 | 18))
+    // Bind-mounted files can reject replace-style renames with EBUSY/EXDEV.
+    const EBUSY: i32 = 16;
+    const EXDEV: i32 = 18;
+    matches!(error.raw_os_error(), Some(EBUSY | EXDEV))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[cfg(unix)]
fn should_fallback_to_in_place_write(error: &std::io::Error) -> bool {
// Bind-mounted files can reject replace-style renames with EBUSY/EXDEV.
matches!(error.raw_os_error(), Some(16 | 18))
}
#[cfg(unix)]
fn should_fallback_to_in_place_write(error: &std::io::Error) -> bool {
// Bind-mounted files can reject replace-style renames with EBUSY/EXDEV.
const EBUSY: i32 = 16;
const EXDEV: i32 = 18;
matches!(error.raw_os_error(), Some(EBUSY | EXDEV))
}
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@clients/agent-runtime/src/config/schema.rs` around lines 1151 - 1155, Replace
the magic errno integers in should_fallback_to_in_place_write with named
constants: update the matches! check to compare against descriptive constants
rather than raw 16 and 18. You can either reference libc::EBUSY and libc::EXDEV
(add libc dependency), use std::io::ErrorKind variants if MSRV permits, or
define local const EBUSY and EXDEV integers at the top of the module and use
those; ensure the function still matches error.raw_os_error() against Some(EBUSY
| EXDEV) equivalents and keep the #[cfg(unix)] attribute on
should_fallback_to_in_place_write.

Comment thread clients/web/.gitignore
Comment on lines +40 to +43

# Astro
**/.astro/
.astro/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Redundant pattern: .astro/ is already covered by **/.astro/.

The glob **/.astro/ matches .astro/ at any depth, including the current directory root. Line 43 is redundant.

Proposed fix
 # Astro
 **/.astro/
-.astro/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Astro
**/.astro/
.astro/
# Astro
**/.astro/
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@clients/web/.gitignore` around lines 40 - 43, The .gitignore contains a
redundant pattern: remove the duplicate `.astro/` entry so only the recursive
pattern `**/.astro/` remains (keep `**/.astro/` and delete the separate
`.astro/` line) to avoid duplication while preserving the same ignore behavior.

Comment on lines +10 to +11
actor(Developer):::person
actor(EndUser):::person
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same node ID collision bug as the English version.

Lines 10–11 both define node id actor, and lines 27–28 reference Developer/EndUser as IDs that were never properly defined. Apply the same fix as described for the English version.

Proposed fix
-  actor(Developer):::person
-  actor(EndUser):::person
+  Developer(["Desarrollador"]):::person
+  EndUser(["Usuario Final"]):::person
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
actor(Developer):::person
actor(EndUser):::person
Developer(["Desarrollador"]):::person
EndUser(["Usuario Final"]):::person
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/context/system-context.mmd`
around lines 10 - 11, The diagram uses the generic node id "actor" twice
(actor(Developer) and actor(EndUser)), causing ID collisions and leaving
references to Developer/EndUser undefined; update those actor declarations to
explicitly set unique IDs that match the later references (e.g., change
actor(Developer):::person to "actor Developer as \"Developer\":::person" or the
equivalent mermaid form that yields id Developer, and similarly change
actor(EndUser):::person to set id EndUser) so the later references to Developer
and EndUser resolve correctly.

direction LR
CLIENT["Cliente"]:::client
CORE["Core Compartido"]:::core
EXTERNAL["Externo"]:::external
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Mermaid ID collision: EXTERNAL is used for both a node (Line 12) and a subgraph (Line 32).

Mermaid requires unique IDs across all nodes and subgraphs. This will cause rendering issues — the legend node will likely be absorbed into the subgraph or the diagram will fail to render. Rename one of them.

Proposed fix
-    EXTERNAL["Externo"]:::external
+    EXT_LEGEND["Externo"]:::external

Also applies to: 32-39

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@clients/web/apps/docs/src/content/docs/es/guides/architecture/diagrams/module-dependencies.mmd`
at line 12, Rename one of the conflicting Mermaid IDs so they are unique: change
either the node ID "EXTERNAL" (the EXTERNAL["Externo"] node) or the subgraph
named "EXTERNAL" to a distinct identifier (e.g., "EXTERNAL_LEGEND" or
"EXTERNAL_SUBGRAPH"), and update any references/edges and class/stylesheet
mentions (such as :::external or any links to EXTERNAL) to the new name to keep
all IDs consistent.

Comment on lines +11 to +35
// Verificar y crear symlink de docs si no existe
val rootProjectDir = isolated.rootProject.projectDirectory.asFile.toPath()
val docsSymlink = rootProjectDir.resolve("docs")
val docsTarget = rootProjectDir.resolve("clients/web/apps/docs/src/content/docs")

if (!Files.exists(docsSymlink)) {
if (Files.exists(docsTarget)) {
try {
Files.createSymbolicLink(docsSymlink, docsTarget)
logger.lifecycle("🔗 Symlink creado: docs → clients/web/apps/docs/src/content/docs")
} catch (e: Exception) {
logger.warn("⚠️ No se pudo crear symlink de docs: ${e.message}")
// Fallback: crear directorio vacío o copiar contenido
logger.lifecycle("📁 Creando directorio docs como fallback...")
docsSymlink.toFile().mkdirs()
}
} else {
logger.warn("⚠️ Target no existe: $docsTarget")
}
} else if (Files.isSymbolicLink(docsSymlink)) {
val target = Files.readSymbolicLink(docsSymlink)
logger.lifecycle("✅ Symlink docs ya existe → $target")
} else {
logger.lifecycle("📁 Directorio docs ya existe (no es symlink)")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Log messages and comments are in Spanish; rest of the build file is in English.

Mixing languages in the same file hurts readability for contributors who don't speak Spanish. Consider using English consistently for code comments and log messages in build scripts, reserving Spanish for user-facing documentation.

🧰 Tools
🪛 GitHub Actions: Scan with Detekt

[error] 21-21: The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled. [TooGenericExceptionCaught]

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@clients/web/build.gradle.kts` around lines 11 - 35, The log messages and
comments around the symlink setup (variables rootProjectDir, docsSymlink,
docsTarget and the Files.createSymbolicLink block) are in Spanish; change all
comments and logger messages (logger.lifecycle, logger.warn) to English to match
the rest of the build file (e.g., "Create symlink: docs →
clients/web/apps/docs/src/content/docs", "Could not create docs symlink:
${e.message}", "Creating docs directory as fallback...", "Target does not exist:
$docsTarget", "Symlink docs already exists → $target", "Docs directory already
exists (not a symlink)"). Ensure the code logic and message content remain
identical aside from language so only message strings and comments are updated.

Comment on lines +16 to +29
if (!Files.exists(docsSymlink)) {
if (Files.exists(docsTarget)) {
try {
Files.createSymbolicLink(docsSymlink, docsTarget)
logger.lifecycle("🔗 Symlink creado: docs → clients/web/apps/docs/src/content/docs")
} catch (e: Exception) {
logger.warn("⚠️ No se pudo crear symlink de docs: ${e.message}")
// Fallback: crear directorio vacío o copiar contenido
logger.lifecycle("📁 Creando directorio docs como fallback...")
docsSymlink.toFile().mkdirs()
}
} else {
logger.warn("⚠️ Target no existe: $docsTarget")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Broken symlink causes silent failure.

Files.exists(docsSymlink) follows symlinks by default — if a broken symlink already exists at that path, it returns false, but Files.createSymbolicLink on Line 19 will throw because the filesystem entry already exists. Guard against this by checking with LinkOption.NOFOLLOW_LINKS or by checking Files.isSymbolicLink first.

Proposed fix
-if (!Files.exists(docsSymlink)) {
+if (!Files.exists(docsSymlink, java.nio.file.LinkOption.NOFOLLOW_LINKS)) {
🧰 Tools
🪛 GitHub Actions: Scan with Detekt

[error] 21-21: The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled. [TooGenericExceptionCaught]

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@clients/web/build.gradle.kts` around lines 16 - 29, The current check uses
Files.exists(docsSymlink) which follows symlinks and misses broken symlinks,
causing Files.createSymbolicLink(docsSymlink, docsTarget) to throw if a broken
link entry already exists; update the logic around docsSymlink/docsTarget to
first check Files.exists(docsSymlink, LinkOption.NOFOLLOW_LINKS) or
Files.isSymbolicLink(docsSymlink) to detect an existing symlink, and if a
symlink exists but points to a missing target remove the broken symlink (or skip
creation) before calling Files.createSymbolicLink; ensure all references to
docsSymlink and docsTarget are adjusted to use LinkOption.NOFOLLOW_LINKS where
appropriate and keep the existing fallback behavior if creation still fails.

Comment on lines +18 to +26
try {
Files.createSymbolicLink(docsSymlink, docsTarget)
logger.lifecycle("🔗 Symlink creado: docs → clients/web/apps/docs/src/content/docs")
} catch (e: Exception) {
logger.warn("⚠️ No se pudo crear symlink de docs: ${e.message}")
// Fallback: crear directorio vacío o copiar contenido
logger.lifecycle("📁 Creando directorio docs como fallback...")
docsSymlink.toFile().mkdirs()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Catch specific exceptions to fix the Detekt pipeline failure.

The pipeline reports TooGenericExceptionCaught on Line 21. Files.createSymbolicLink throws IOException, UnsupportedOperationException, SecurityException, or FileAlreadyExistsException — catch those explicitly.

Proposed fix
-    } catch (e: Exception) {
+    } catch (e: java.io.IOException) {
+      logger.warn("⚠️ Could not create docs symlink: ${e.message}")
+      logger.lifecycle("📁 Creating docs directory as fallback...")
+      docsSymlink.toFile().mkdirs()
+    } catch (e: UnsupportedOperationException) {
🧰 Tools
🪛 GitHub Actions: Scan with Detekt

[error] 21-21: The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled. [TooGenericExceptionCaught]

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@clients/web/build.gradle.kts` around lines 18 - 26, The catch block for
Files.createSymbolicLink is too generic (causing Detekt
TooGenericExceptionCaught); replace the broad catch(Exception) with explicit
catches for the exceptions that createSymbolicLink can throw (e.g.,
java.io.IOException, java.nio.file.FileAlreadyExistsException,
java.lang.UnsupportedOperationException, java.lang.SecurityException) around the
Files.createSymbolicLink(docsSymlink, docsTarget) call, handling each case
similarly to the current fallback (logger.warn + create fallback
docsSymlink.toFile().mkdirs()) or consolidating the specific exceptions into a
multi-catch to satisfy Detekt while preserving the existing logging and fallback
behavior.

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