-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreviews.txt
More file actions
20 lines (20 loc) · 24.2 KB
/
reviews.txt
File metadata and controls
20 lines (20 loc) · 24.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"_⚠️ Potential issue_ | _🔴 Critical_\n\n**Restore `actions: write` permissions for artifact uploads.**\n\nGranting only `contents: read` removes the default `actions: write`, so each `actions/upload-artifact` step will fail with a permission error. Please reinstate `actions: write` (alongside `contents: read`) so the workflow can publish artefacts successfully.\n\n```diff\n permissions:\n contents: read\n+ actions: write\n```\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Clarify or remove redundant comment.**\n\nThe comment suggests this section handles test file exclusions, but that's actually accomplished by the `exclude-rules` section (lines 14-17). Consider removing this comment or clarifying that the exclusions are handled above.\n\nApply this diff to clarify the comment:\n\n```diff\n linters-settings:\n errcheck:\n- # Be pragmatic: don't require checking of Close for defer patterns in tests/examples.\n- # (Keep defaults; exclusions above handle test files.)\n+ # Using default settings; test file exclusions are handled by exclude-rules above.\n```\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Format URLs as markdown links.**\n\nThe bare URLs should be formatted as proper markdown links for better accessibility and to comply with markdown best practices.\n\nApply this diff to format the URLs properly:\n\n```diff\n-- Version: https://www.contributor-covenant.org/version/2/1/code_of_conduct/\n-- FAQ: https://www.contributor-covenant.org/faq\n-- Translations: https://www.contributor-covenant.org/translations\n+- Version: [Contributor Covenant v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/)\n+- FAQ: [Contributor Covenant FAQ](https://www.contributor-covenant.org/faq)\n+- Translations: [Available Translations](https://www.contributor-covenant.org/translations)\n```\n\n"
"_⚠️ Potential issue_ | _🔴 Critical_\n\n<details>\n<summary>🧩 Analysis chain</summary>\n\n**Verify Go version requirement consistency.**\n\nThe documentation states \"Go 1.22+ (1.23 preferred)\", but the enriched summary indicates that `go.mod` was updated to Go 1.23. Please ensure this requirement matches the actual minimum Go version specified in `go.mod`.\n\n---\n\n🏁 Script executed:\n\n```shell\n#!/bin/bash\n# Check the Go version requirement in go.mod\ngrep -E '^go [0-9.]+' go.mod\n```\n\nLength of output: 7\n\n---\n\n\n\n</details>\n\n**Update CONTRIBUTING.md to reflect the actual minimum Go version.**\n\nThe `go.mod` requires Go 1.23, but CONTRIBUTING.md states \"Go 1.22+ (1.23 preferred)\". Update line 7 to read \"Go 1.23+\" to match the enforced minimum version.\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn CONTRIBUTING.md around line 7, update the Go version string to match go.mod\nby replacing \"Go 1.22+ (1.23 preferred)\" with \"Go 1.23+\" so the documented\nminimum Go version matches the enforced version; ensure no other lines reference\n1.22 and run a quick search to update any remaining mentions of the older\nversion.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Fix markdown formatting issues.**\n\nThe heading and code fence lack proper blank line separation as flagged by markdownlint.\n\n\n\nApply this diff to fix the formatting:\n\n```diff\n )\n ```\n-\n+\n #### Example (2D)\n+\n ```go\n // Compute stats once over your baseline set\n```\n\n<details>\n<summary>🧰 Tools</summary>\n\n<details>\n<summary>🪛 markdownlint-cli2 (0.18.1)</summary>\n\n473-473: Headings should be surrounded by blank lines\nExpected: 1; Actual: 0; Below\n\n(MD022, blanks-around-headings)\n\n---\n\n474-474: Fenced code blocks should be surrounded by blank lines\n\n(MD031, blanks-around-fences)\n\n</details>\n\n</details>\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n````\nIn docs/api.md around lines 473-474, the heading \"#### Example (2D)\" and the\nfollowing code fence are missing the required blank-line separation; insert a\nsingle blank line after the heading so the file reads: the heading line, a blank\nline, then the ```go code fence (and ensure the code content follows the fence\non the next line) to satisfy markdownlint.\n````\n\n</details>\n\n"
"_🛠️ Refactor suggestion_ | _🟠 Major_\n\n**Add blank lines before the third-level headings**\n\nThe fenced code block needs a blank line before each subsequent `###` heading; otherwise markdownlint (MD022) fails. Please insert empty lines so the headings are surrounded by blanks.\n\n\n```diff\n@@\n-```\n-### Why does querying with `[0]` work?\n+```\n+\n+### Why does querying with `[0]` work?\n@@\n-We use Euclidean distance in 1D, so `distance = |ping - target|`. With target `0`, minimizing the distance is equivalent to minimizing the ping itself.\n-### Extending the metric/space\n+We use Euclidean distance in 1D, so `distance = |ping - target|`. With target `0`, minimizing the distance is equivalent to minimizing the ping itself.\n+\n+### Extending the metric/space\n@@\n-- Normalization: when mixing units (ms, hops, km), normalize or weight dimensions so the metric reflects your priority.\n--### Notes\n+- Normalization: when mixing units (ms, hops, km), normalize or weight dimensions so the metric reflects your priority.\n+\n+### Notes\n```\n\n\n> Committable suggestion skipped: line range outside the PR's diff.\n\n<details>\n<summary>🧰 Tools</summary>\n\n<details>\n<summary>🪛 LanguageTool</summary>\n\n[uncategorized] ~110-~110: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).\nContext: ...ops, km), normalize or weight dimensions so the metric reflects your priority. ###...\n\n(COMMA_COMPOUND_SENTENCE_2)\n\n---\n\n[misspelling] ~113-~113: This word is normally spelled as one.\nContext: ...patial/kdtree` under the hood later for sub-linear queries on large datasets. - IDs are op...\n\n(EN_COMPOUNDS_SUB_LINEAR)\n\n</details>\n<details>\n<summary>🪛 markdownlint-cli2 (0.18.1)</summary>\n\n101-101: Headings should be surrounded by blank lines\nExpected: 1; Actual: 0; Below\n\n(MD022, blanks-around-headings)\n\n---\n\n104-104: Headings should be surrounded by blank lines\nExpected: 1; Actual: 0; Below\n\n(MD022, blanks-around-headings)\n\n---\n\n112-112: Headings should be surrounded by blank lines\nExpected: 1; Actual: 0; Below\n\n(MD022, blanks-around-headings)\n\n</details>\n\n</details>\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn docs/dht-best-ping.md around lines 100 to 113, several third-level headings\n(### Why does querying with `[0]` work?, ### Extending the metric/space, ###\nNotes) are missing blank lines before them which trips markdownlint MD022;\ninsert a single blank line immediately before each of these `###` heading lines\n(and ensure there's a blank line after the preceding paragraph) so each heading\nis surrounded by blank lines and the file passes the lint rule.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**LGTM!**\n\nThe new example links provide helpful next steps for users. Note: \"multi-dimensional\" could be written as \"multidimensional\" (one word) for consistency with common technical writing style, though both forms are acceptable.\n\n<details>\n<summary>🧰 Tools</summary>\n\n<details>\n<summary>🪛 LanguageTool</summary>\n\n[misspelling] ~126-~126: This word is normally spelled as one.\nContext: ...) DHT peer](dht-best-ping.md) - Explore multi-dimensional KDTree over ping/hops/geo/score: [Multi...\n\n(EN_COMPOUNDS_MULTI_DIMENSIONAL)\n\n</details>\n\n</details>\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn docs/getting-started.md around lines 125 to 126, update the link text\n\"Multi-Dimensional KDTree (DHT)\" to use the single-word \"Multidimensional\" for\nconsistency (i.e., \"Multidimensional KDTree (DHT)\"); leave the URL unchanged and\nkeep the surrounding list items intact.\n```\n\n</details>\n\n"
"_⚠️ Potential issue_ | _🟠 Major_\n\n**Re-use normalisation stats when inserting new peers**\n\n`Build2D` normalises every slice against that slice’s own min/max. When you call it with `[]Peer{newPeer}`, both axes collapse to zero, so the inserted point is always `[0,0]` and becomes “best” regardless of its real metrics. Reuse the original normalisation stats (or rebuild the whole tree) so inserts share the same scale.\n\n\n```diff\n func main() {\n- // Initial 2‑D build (ping + hops)\n- weights2 := [2]float64{1.0, 1.0}\n- invert2 := [2]bool{false, false}\n- pts, _ := poindexter.Build2D(\n- peers,\n- func(p Peer) string { return p.ID },\n- func(p Peer) float64 { return p.PingMS },\n- func(p Peer) float64 { return p.Hops },\n- weights2, invert2,\n- )\n+ // Initial 2‑D build (ping + hops)\n+ weights2 := [2]float64{1.0, 1.0}\n+ invert2 := [2]bool{false, false}\n+ stats := poindexter.ComputeNormStats2D(\n+ peers,\n+ func(p Peer) float64 { return p.PingMS },\n+ func(p Peer) float64 { return p.Hops },\n+ )\n+ pts, _ := poindexter.Build2DWithStats(\n+ peers,\n+ func(p Peer) string { return p.ID },\n+ func(p Peer) float64 { return p.PingMS },\n+ func(p Peer) float64 { return p.Hops },\n+ weights2, invert2, stats,\n+ )\n tree, _ := poindexter.NewKDTree(pts)\n@@\n- addPts, _ := poindexter.Build2D(\n+ addPts, _ := poindexter.Build2DWithStats(\n []Peer{newPeer},\n func(p Peer) string { return p.ID },\n func(p Peer) float64 { return p.PingMS },\n func(p Peer) float64 { return p.Hops },\n- weights2, invert2,\n+ weights2, invert2, stats,\n )\n```\n\n\n> Committable suggestion skipped: line range outside the PR's diff.\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn docs/kdtree-multidimensional.md around lines 237 to 266, the example calls\nBuild2D for a single new peer which recomputes min/max and collapses the point\nto [0,0]; update the example to reuse the original normalization stats so the\ninserted point is on the same scale as the tree (either by using a Build2D\noverload or helper that accepts the prior min/max/scale from the first Build2D,\nor by normalizing the new peer’s raw metrics with the original stats before\ncalling tree.Insert), or explicitly note and demonstrate rebuilding the whole\ntree from the full peer list; ensure the instructions show reusing the\npreviously computed normalization stats when creating addPts so Insert receives\ncorrectly scaled coordinates.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**LGTM!**\n\nComprehensive documentation for the WebAssembly build and integration. The examples and API reference are clear and helpful.\n\nOptional nitpicks:\n- Line 30: In British English, \"licence\" (noun) vs \"license\" (verb) - consider \"licence\" for the noun usage.\n- Lines 46 & 56: Markdown list numbering could restart at \"1)\" for consistency with some formatters.\n\n<details>\n<summary>🧰 Tools</summary>\n\n<details>\n<summary>🪛 LanguageTool</summary>\n\n[locale-violation] ~30-~30: license must be spelled with a “c” when used as a noun in British English. Use “licence”.\nContext: ...es `npm/poindexter-wasm/` with `dist/`, license and readme files. You can then create a...\n\n(LICENCE_LICENSE_NOUN_SINGULAR)\n\n</details>\n<details>\n<summary>🪛 markdownlint-cli2 (0.18.1)</summary>\n\n46-46: Ordered list item prefix\nExpected: 1; Actual: 2; Style: 1/1/1\n\n(MD029, ol-prefix)\n\n---\n\n56-56: Ordered list item prefix\nExpected: 1; Actual: 3; Style: 1/1/1\n\n(MD029, ol-prefix)\n\n</details>\n\n</details>\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn docs/wasm.md around lines 1–104, update the noun \"license\" at approx line 30\nto British English \"licence\" and change the ordered list numbering at lines ~46\nand ~56 so each example section restarts numbering at \"1)\" (i.e., make the list\nmarkers for the Angular usage steps and the import/initialize snippet both begin\nat 1) rather than continuing the prior sequence); edit the two lines accordingly\nand run a quick markdown preview to ensure numbering renders as intended.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider more precise distance validation.**\n\nThe test correctly identifies the minimum ping peer, but the distance assertion could be more explicit and precise.\n\n\nApply this diff for clearer validation:\n\n```diff\n \tbest, d, ok := kdt.Nearest([]float64{0})\n \tif !ok {\n \t\tt.Fatalf(\"no nearest\")\n \t}\n \t// Expect the minimum ping (35ms)\n \tif best.Value.Ping != 35 {\n \t\tt.Fatalf(\"expected best ping 35ms, got %d\", best.Value.Ping)\n \t}\n-\tif d <= 0 {\n-\t\tt.Fatalf(\"expected positive distance, got %v\", d)\n+\t// Distance from [0] to [35] should be 35\n+\tif d != 35 {\n+\t\tt.Fatalf(\"expected distance 35, got %v\", d)\n \t}\n```\n\n"
"_⚠️ Potential issue_ | _🟠 Major_\n\n**Handle errors instead of ignoring them.**\n\nAll errors and the `ok` return value from these operations are silently ignored. If `Build2D` or `NewKDTree` fail, the program will likely panic on the next line. If `Nearest` returns `ok=false`, accessing `best` may cause issues. Examples should demonstrate proper error handling.\n\n\n\nApply this diff to add error handling:\n\n```diff\n-\tpts, _ := poindexter.Build2D(\n+\tpts, err := poindexter.Build2D(\n \t\tpeers,\n \t\tfunc(p Peer2) string { return p.ID },\n \t\tfunc(p Peer2) float64 { return p.PingMS },\n \t\tfunc(p Peer2) float64 { return p.Hops },\n \t\tweights, invert,\n \t)\n+\tif err != nil {\n+\t\tpanic(fmt.Sprintf(\"Build2D failed: %v\", err))\n+\t}\n-\ttr, _ := poindexter.NewKDTree(pts, poindexter.WithMetric(poindexter.ManhattanDistance{}))\n+\ttr, err := poindexter.NewKDTree(pts, poindexter.WithMetric(poindexter.ManhattanDistance{}))\n+\tif err != nil {\n+\t\tpanic(fmt.Sprintf(\"NewKDTree failed: %v\", err))\n+\t}\n-\tbest, _, _ := tr.Nearest([]float64{0, 0.3})\n+\tbest, _, ok := tr.Nearest([]float64{0, 0.3})\n+\tif !ok {\n+\t\tpanic(\"no nearest neighbour found\")\n+\t}\n \tfmt.Println(\"2D best:\", best.ID)\n```\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider adding assertions to validate the example's behaviour.**\n\nThis smoke test only verifies that `main()` doesn't panic. Consider capturing output or adding basic assertions to validate that the example produces expected results, improving test coverage and making failures more informative.\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn examples/kdtree_3d_ping_hop_geo/main_test.go around lines 5 to 7, the test\nonly calls main() to ensure no panic; update it to capture and assert expected\nbehavior by redirecting stdout/stderr (or modifying main to return results) and\nasserting on known output values or side-effects—e.g., run main(), read the\ncaptured output, and add assertions that specific strings or numeric results\nappear and that exit code/state is correct; keep the test deterministic and\nrestore original stdout/stderr after the check.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider adding assertions to validate the example's behaviour.**\n\nThis smoke test only verifies that `main()` doesn't panic. Consider capturing output or adding basic assertions to validate that the example produces expected results, improving test coverage and making failures more informative.\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn examples/kdtree_4d_ping_hop_geo_score/main_test.go around lines 5 to 7, the\ntest only calls main() and doesn't assert any behavior; update the test to\ncapture and inspect program output and/or side effects: redirect stdout (and\nstderr if needed) to a buffer before calling main(), run main(), restore\noutputs, then use t.Fatalf/t.Errorf or testify assertions to check that the\nbuffer contains expected strings or values (or that expected files/metrics were\nproduced) so the test fails with informative messages when behaviour changes.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider handling errors for demonstration purposes.**\n\nWhilst the example works correctly, explicitly handling the error from `Build4D` would demonstrate best practices to users learning from this code.\n\n\nApply this diff to improve error handling:\n\n```diff\n-\tpts, _ := poindexter.Build4D(\n+\tpts, err := poindexter.Build4D(\n \t\tpeers,\n \t\tfunc(p Peer4) string { return p.ID },\n \t\tfunc(p Peer4) float64 { return p.PingMS },\n \t\tfunc(p Peer4) float64 { return p.Hops },\n \t\tfunc(p Peer4) float64 { return p.GeoKM },\n \t\tfunc(p Peer4) float64 { return p.Score },\n \t\tweights, invert,\n \t)\n+\tif err != nil {\n+\t\tpanic(err)\n+\t}\n```\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider handling errors for demonstration purposes.**\n\nSimilarly to the Build4D call, handling errors from `NewKDTree` and `Nearest` would demonstrate best practices.\n\n\nApply this diff:\n\n```diff\n-\ttr, _ := poindexter.NewKDTree(pts, poindexter.WithMetric(poindexter.EuclideanDistance{}))\n-\tbest, _, _ := tr.Nearest([]float64{0, weights[1] * 0.2, weights[2] * 0.3, 0})\n+\ttr, err := poindexter.NewKDTree(pts, poindexter.WithMetric(poindexter.EuclideanDistance{}))\n+\tif err != nil {\n+\t\tpanic(err)\n+\t}\n+\tbest, _, ok := tr.Nearest([]float64{0, weights[1] * 0.2, weights[2] * 0.3, 0})\n+\tif !ok {\n+\t\tpanic(\"no nearest neighbour found\")\n+\t}\n \tfmt.Println(\"4D best:\", best.ID)\n```\n\n"
"_⚠️ Potential issue_ | _🟠 Major_\n\n**Propagate stats dimensionality errors instead of returning nil silently**\n\n`Build2DWithStats`, `Build3DWithStats`, and `Build4DWithStats` return `(nil, nil)` when the supplied stats slice has the wrong length. That hides misconfiguration and drops all points without warning. Please surface `ErrStatsDimMismatch` so callers can detect and handle the issue. Based on review\n\n```diff\n- if len(stats.Stats) != 2 {\n- return nil, nil\n- }\n+ if len(stats.Stats) != 2 {\n+ return nil, ErrStatsDimMismatch\n+ }\n...\n- if len(stats.Stats) != 3 {\n- return nil, nil\n- }\n+ if len(stats.Stats) != 3 {\n+ return nil, ErrStatsDimMismatch\n+ }\n...\n- if len(stats.Stats) != 4 {\n- return nil, nil\n- }\n+ if len(stats.Stats) != 4 {\n+ return nil, ErrStatsDimMismatch\n+ }\n```\n\n\n> Committable suggestion skipped: line range outside the PR's diff.\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn kdtree_helpers.go around lines 244 to 429, the three functions\nBuild2DWithStats, Build3DWithStats and Build4DWithStats currently return (nil,\nnil) when stats.Stats has the wrong length; change those early-return paths to\nreturn (nil, ErrStatsDimMismatch) so callers can detect the mismatch; ensure\nErrStatsDimMismatch is defined and exported in this package (or referenced from\nits package) and update any tests/usage to expect the error instead of a nil\nresult.\n```\n\n</details>\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider stricter assertions for more precise validation.**\n\nThe test correctly validates deletion behaviour, but the final assertion could be more precise. Since query `[0]` should find point A and query `[2]` should find point C, we can assert both individually.\n\n\nApply this diff for stricter validation:\n\n```diff\n \t// Ensure B is gone and A/C remain reachable\n \tids := make(map[string]bool)\n \tfor _, q := range [][]float64{{0}, {2}} {\n \t\tp, _, ok := tr.Nearest(q)\n \t\tif ok {\n \t\t\tids[p.ID] = true\n \t\t}\n \t}\n \tif ids[\"B\"] {\n \t\tt.Fatalf(\"B should not be present after delete\")\n \t}\n-\tif !ids[\"A\"] && !ids[\"C\"] {\n-\t\tt.Fatalf(\"expected either A or C to be nearest for respective queries: %v\", ids)\n+\tif !ids[\"A\"] || !ids[\"C\"] {\n+\t\tt.Fatalf(\"expected both A and C to be found after deleting B, got: %v\", ids)\n \t}\n```\n\n"
"_🧹 Nitpick_ | _🔵 Trivial_\n\n**Consider adding a clean target.**\n\nThe Makefile is missing a `clean` target, which is a standard phony target for build systems. This would allow users to remove generated artifacts like `dist/`, `coverage.out`, `coverage.html`, and `bench.txt`.\n\n\n\n```diff\n+.PHONY: clean\n+clean: ## Remove generated files and directories\n+\trm -rf $(DIST_DIR) $(COVEROUT) $(COVERHTML) $(BENCHOUT)\n+\n```\n\n"
"_⚠️ Potential issue_ | _🔴 Critical_\n\n<details>\n<summary>🧩 Analysis chain</summary>\n\n**Fix the golangci-lint configuration version mismatch.**\n\nThe pipeline failure indicates: \"configuration file is for golangci-lint v2 but the installed binary is v1\". This is blocking CI and must be resolved by either:\n1. Updating `.golangci-lint.yml` (or equivalent config) to v1 format, or\n2. Installing golangci-lint v2 in the CI environment.\n\n\n\n\nCheck the golangci-lint configuration version:\n\n---\n\n🏁 Script executed:\n\n```shell\n#!/bin/bash\n# Find and examine golangci-lint configuration\nfd -t f '^\\.golangci' | while read -r config; do\n echo \"==> $config\"\n head -20 \"$config\"\ndone\n```\n\nLength of output: 207\n\n---\n\n🏁 Script executed:\n\n```shell\n#!/bin/bash\n# Find and examine golangci-lint configuration with hidden file support\necho \"=== Searching for golangci-lint configuration files ===\"\nfd -H -t f '\\.golangci' \n\necho -e \"\\n=== Examining configuration file contents ===\"\nfd -H -t f '\\.golangci' | while read -r config; do\n echo \"==> $config\"\n cat \"$config\"\n echo \"\"\ndone\n\necho -e \"\\n=== Searching for CI pipeline configuration ===\"\nfd -H -t f '(\\.gitlab-ci\\.yml|\\.travis\\.yml|\\.github/workflows)' | head -20\n```\n\nLength of output: 621\n\n---\n\n🏁 Script executed:\n\n```shell\n#!/bin/bash\n# Search for CI/workflow files and Makefile details\necho \"=== CI/Workflow files ===\"\nfind . -name \"*.yml\" -o -name \"*.yaml\" | grep -E '(workflow|ci|\\.github|gitlab)' | head -20\n\necho -e \"\\n=== Makefile content related to lint ===\"\ngrep -A 10 -B 5 'GOLANGCI_LINT\\|golangci-lint' Makefile 2>/dev/null || echo \"No Makefile or no golangci-lint references found\"\n\necho -e \"\\n=== Scripts directory ===\"\nfind . -type f -name \"*.sh\" | head -10\n\necho -e \"\\n=== Looking for Docker or version installation ===\"\nfd -H -t f '(Dockerfile|\\.dockerignore|go\\.mod)' | head -5\n```\n\nLength of output: 1090\n\n---\n\n🏁 Script executed:\n\n```shell\n#!/bin/bash\n# Examine CI workflow files for golangci-lint setup\necho \"=== Contents of .github/workflows/ci.yml ===\"\ncat .github/workflows/ci.yml\n\necho -e \"\\n=== Contents of .github/workflows/test.yml ===\"\ncat .github/workflows/test.yml\n\necho -e \"\\n=== Check go.mod for golang and tool versions ===\"\nhead -30 go.mod\n```\n\nLength of output: 2504\n\n---\n\n🌐 Web query:\n\n```web\ngolangci-lint v2 latest version 2024 2025\n```\n\n💡 Result:\n\nThe latest golangci-lint v2 release is v2.5.0 (released Sep 21, 2025). [1]\n\nSources:\n[1] GitHub — golangci/golangci-lint releases.\n\n---\n\n\n\n</details>\n\n**Pin golangci-lint to v2 in the CI workflow.**\n\nThe `.golangci.yml` configuration correctly specifies `version: \"2\"`, but `.github/workflows/ci.yml` installs golangci-lint using `@latest`, which pulled v1. Update the installation command to explicitly pin to v2:\n\nIn `.github/workflows/ci.yml`, change:\n```\ngo install github.com/golangci/golangci-lint/cmd/golangci-lint@latest\n```\n\nto:\n```\ngo install github.com/golangci/golangci-lint/cmd/golangci-lint@v2.5.0\n```\n\nThis resolves the version mismatch and allows the linter to correctly parse the v2 configuration format.\n\n<details>\n<summary>🤖 Prompt for AI Agents</summary>\n\n```\nIn Makefile around lines 123 to 125: CI currently installs golangci-lint with\n@latest which pulls v1 and mismatches .golangci.yml v2 config; open\n.github/workflows/ci.yml and replace the go install line that uses @latest with\na v2-pinned version (for example @v2.5.0) so the CI installs golangci-lint v2\nand the linter can parse the v2 configuration.\n```\n\n</details>\n\n\n\n✅ Addressed in commit 8e62b4e"
"_⚠️ Potential issue_ | _🔴 Critical_\n\n**Do not await `go.run` because it never resolves**\n\n`go.run` only settles once the Go program exits, but the wasm `main` ends with `select {}` to stay alive, so this `await` prevents `init()` from ever resolving. Kick off the runtime without awaiting (optionally handle errors via `.catch(...)`) so callers can actually obtain the API. Based on review\n\n```diff\n- // Run the Go program (it registers globals like pxNewTree, etc.)\n- await go.run(result.instance);\n+ // Run the Go program (it registers globals like pxNewTree, etc.)\n+ go.run(result.instance);\n```\n\n"