Fix all false positives, false negatives, warnings and errors in CI/CD - #97
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #96
… warnings
NamedLinksDecorator and SimpleLinksDecorator opened memory-mapped file
handles for both the data and the names database but were not disposable,
so callers had no way to release them. On POSIX an unlink of a still-mapped
file succeeds, which hid the leak; on Windows the same delete fails with
IOException. Both decorators now implement IDisposable.
The reflection-based facade-chain disposal previously living inside
NamedTypesDecorator is extracted into the shared LinksFacadeDisposer so all
three decorators release handles identically.
Also escapes Link<uint> as Link{uint} in the ChangesSimplifier doc comment,
which removes the only two CS1570 warnings in the build.
Reproduces and fixes the 114 Windows test failures (226 IOExceptions at System.IO.FileSystem.DeleteFile) that csharp.yml was hiding behind continue-on-error. Every affected helper now scopes its decorator with `using` so the memory-mapped handles are released before the finally block deletes the backing files: AdvancedMixedQueryProcessor, NamedTypesDecoratorTests, NamedLinksDecoratorTests, LinoDatabaseOutputTests, SimpleLinksDecoratorTests, LinoDatabaseInputTests, PersistentTransformationDecoratorTests and Issue62ReviewCoverageTests -- the exact eight classes in the failure list. DecoratorDisposalTests pins the contract: each decorator is IDisposable, its databases can be deleted after Dispose, and Dispose is idempotent. Two further fixes in the same area: - MakeNamesDatabaseFilename_CorrectlyGeneratesFilename hard-coded '/' in its expectations while the implementation builds paths with Path.Combine, so it failed on Windows only. It now compares the file name and the directory separately, and a new theory asserts all three decorators agree. - RunTestWithLinks capped every test body at one second of wall-clock time, which made a loaded macOS runner fail SwapSourceAndTargetForAllLinksUsing- VariablesTest with TimeoutException. The guard is now 60 seconds and overridable via LINK_CLI_TEST_TIMEOUT_SECONDS. Measurable on Linux too: a full run used to leave 104 orphaned *.names.links files in /tmp, now it leaves none.
Adds csharp/Directory.Build.props with TreatWarningsAsErrors and .NET analyzers enabled, plus csharp/.editorconfig promoting the four disposal-safety rules (CA1001, CA1063, CA1816, CA2000) to errors. Fixes everything they surfaced: - seals the three link decorators (CA1063/CA1816), - documents the deliberate ownership transfers in MakeLinks and in the constructors with justified CA2000 suppressions, - makes TransactionsDecorator and VersionControlDecorator disposable (CA1001); Dispose delegates to the existing Shutdown and rolls back a still-open transaction respectively, - disposes the decorators created in the transactions/version-control tests instead of leaking their background workers. Without this, warnings accumulated silently and CI still reported success - the false-negative class of issue #96.
Mechanical, whitespace-only pass (verified with 'git diff -w', which shows nothing but brace placement) so that 'dotnet format --verify-no-changes' can be enforced in CI as the csharp template does. Build and all 222 tests are unchanged.
- removes 'continue-on-error: windows-latest' from the test matrix: the file-locking failures it hid are fixed, so a Windows regression is now a red build instead of a green one (the false negative of issue #96), - adds 'dotnet format --verify-no-changes' and the file-size check to the lint job, matching csharp-ai-driven-development-pipeline-template, - adds per-job timeout-minutes so a hung job fails instead of burning the 6h default, - adds workflow-level least-privilege 'permissions: contents: read', - replaces the redundant 'always() && !cancelled()' with '!cancelled()', - keeps cancel-in-progress for PR runs but disables it on main and gives the publishing jobs a non-cancellable writer concurrency group.
…or files Both were over the 1000-line limit enforced by csharp/scripts/check-file-size.mjs, which is why the check had never been wired into CI. Splitting them into partial classes is a pure move of existing code - no member was added, removed or edited: - Library: matching, mutations and reference validation each move into their own partial file (1678 -> 484/425/483/330 lines), - Tests: the suite splits into two test partials plus a helpers partial (1848 -> 704/897/277 lines). All 222 tests still pass and check-file-size.mjs now exits 0.
…loys Applies the same hardening as the C# workflow to rust.yml: per-job timeout-minutes, workflow-level 'permissions: contents: read', a non-cancellable writer concurrency group for the publishing jobs, cancel-in-progress disabled on main, and '!cancelled()' in place of the redundant 'always() && !cancelled()'. docs.yml and wasm.yml both deploy to GitHub Pages, which accepts only one deployment per repository at a time, so a push touching both would make the second deploy fail. They now share a non-cancellable writer group.
…plates All three ai-driven-development-pipeline templates ship security.yml and links.yml; link-cli had neither, so dependency vulnerabilities and dead documentation links went unnoticed - the false-negative class of #96. - security.yml merges the C#, Rust and JS template jobs: CodeQL over csharp/rust/javascript-typescript/actions, dependency-review on PRs, cargo audit over both Cargo.lock files and npm audit over js/, - links.yml is the C# template's lychee checker with the Wayback Machine fallback (scripts/check-web-archive.mjs reused verbatim), extended to exclude dev/log alongside docs/case-studies, - 'npm audit fix' in js/ clears the three pre-existing high-severity advisories (nanoid, postcss, vite) that the new job would have failed on.
dev/log was swallowed by the '[Ll]og/' rule inherited from the standard .NET .gitignore, so the collected CI logs, the downloaded template workflows and the root-cause analysis were never part of the PR. The rule is now negated for dev/log specifically.
'cargo audit' reported RUSTSEC-2026-0190 (anyhow) and RUSTSEC-2026-0186 (memmap2) as unsoundness warnings for rust/ and rust/wasm/. Both are fixed in semver-compatible releases, so a plain 'cargo update -p' clears them: anyhow 1.0.102 -> 1.0.104, memmap2 0.9.10 -> 0.9.11. cargo fmt, clippy with -Dwarnings and the full test suite stay green.
…olicy tests The C# pipeline offered a 'changeset-pr' release mode in its workflow_dispatch input that no job implemented: selecting it produced a green run that did nothing. Port the changeset-pr job from the C# pipeline template, and mirror it in the Rust pipeline as changelog-pr (with the matching release_mode input the Rust template ships). Add scripts/workflow-policy.test.mjs, which fails on the pre-fix workflows for every defect fixed in this pull request: missing timeout-minutes, missing top-level permissions, continue-on-error masking failures, unwrapped 'if: !cancelled()' and dead release modes. It runs from both the C# and the Rust lint jobs.
…runs js/test/*.test.mjs was never invoked by any workflow, so its repository layout test had been failing unnoticed on a tracked root .gitkeep. Run 'npm run test:js' from the WebAssembly workflow, delete the stray .gitkeep, and move the repository-wide CI helpers under .github/scripts so they respect the same layout rule (a root scripts/ directory is forbidden by that test). Also drop 'issue-*' from the wasm push trigger: combined with the pull_request trigger it ran the whole workflow twice for every push to an issue branch. Both invariants are now asserted by .github/scripts/workflow-policy.test.mjs.
A Cargo.toml dependency bump without a matching Cargo.lock update used to pass CI while every job re-resolved the dependency graph on the fly. 'cargo metadata --locked' turns that drift into an explicit failure for both the CLI crate and the WebAssembly crate.
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
GitHub Pages serves a single site per repository. docs.yml and wasm.yml both uploaded a Pages artifact, so whichever finished last replaced the other one's files; the API reference URLs advertised in README.md answered 404: https://link-foundation.github.io/link-cli/ -> 200 https://link-foundation.github.io/link-cli/csharp/ -> 404 https://link-foundation.github.io/link-cli/rust/link_cli/ -> 404 docs.yml is now the only publisher: it builds the WebAssembly workbench (site root) together with the DocFX and rustdoc output (/csharp/, /rust/) and an API landing page (/docs/). wasm.yml keeps only its test job. Two policy tests pin the single-publisher invariant. check-web-archive.mjs scanned the whole lychee report, so bullets under "## Redirects per input" were escalated as broken links: run 32145481148 reported 9 unrecoverable links while lychee itself reported 4 errors. It now parses only the "Errors per input" section. Conversely, lychee errors that are not http URLs (a missing DocFX file, an unresolvable root-relative link) were dropped and the step reported all_archived=true, turning a real failure green; those are now reported and fail the job. Both defects are covered by check-web-archive.test.mjs against a report captured from that run. Refs #96
Three false negatives, all of which let a broken tree report success: * `cargo clippy` was invoked without `-- -D warnings`, so it printed its findings and exited 0. Both Rust workspaces are now gated; both are clean today, so the gate is added at zero cost. * `rust/wasm` was never formatted or linted - the lint job only pointed at `rust/Cargo.toml`. * Every job tested the pull request head. A pull request can be green on its own head and still break `main`, because a clean textual merge is not necessarily a compiling one. `.github/scripts/simulate-fresh-merge.sh` (ported from the Rust pipeline template) merges the head into the current tip of the base branch and re-runs the fast checks there; rust.yml and csharp.yml each gained a pull-request-only job that uses it, parameterised through FRESH_MERGE_CHECKS because this repository builds three stacks from one tree. Policy tests pin all three invariants. Refs #96
repositoryLayout.test.mjs asserted that wasm.yml deploys GitHub Pages, which is exactly the duplicate-publisher arrangement that made the API reference URLs answer 404. Run 32146391570 caught it, which is the point of running these tests in CI. The guard now asserts that docs.yml publishes the site (including the workbench it serves at the root) and that wasm.yml uploads no Pages artifact of its own. test:js also runs .github/scripts/*.test.mjs now, so `npm test` covers the workflow policy and lychee report parsers locally, not only in CI. Refs #96
security.yml checked code (CodeQL) and dependencies (cargo audit, npm audit) but never the literal contents of the tree. This repository commits CI evidence under dev/log, which is exactly where a token copied out of a workflow log would land unnoticed. Adds the templates' secretlint job and .secretlintrc.json; the current tree scans clean. .pre-commit-config.yaml mirrors the cheap gates locally (formatting, clippy with -D warnings, the workflow policy and layout tests), adapted to this monorepo's per-stack manifests. Evidence for the audit jobs, collected under dev/log/issues/96/pulls/97/local: main's js/package-lock.json fails `npm audit --audit-level=high` with 3 high findings (vite GHSA-fx2h-pf6j-xcff, postcss GHSA-r28c-9q8g-f849) - the four open Dependabot alerts on the default branch. There was no Security workflow at all before this branch, which is why they went unnoticed; this branch's lockfile is already on vite 8.2.1 / postcss 8.5.26 and audits clean. Refs #96
Three warnings were present in every run and none of them failed anything, so they had been accumulating (issue #96, requirement "fix all warnings"): * "Node.js 20 is deprecated ... actions/github-script@60a0d83 ... forced to run on Node.js 24" in the C# test job. codecov/codecov-action@v5 pins github-script v7.0.1 (node20); v6 and v7 pin v8.0.0 (node24). Bumped to v7; the action's inputs we use are unchanged. * "Cannot build an overlay database because build-mode is set to 'undefined'" plus the DEPRECATED autobuild inputs, on all four CodeQL languages. build-mode is now declared per language (autobuild for C#, none for Rust, JavaScript/TypeScript and Actions) and the deprecated standalone autobuild step is gone. * "rust/src/query_processor.rs has 994 lines (approaching limit of 1000)". The pattern-matching helpers moved to rust/src/query_processor/matching.rs, following the split already applied to transactions and version_control; query_processor.rs is now 794 lines and no tracked .rs file exceeds the 900-line warning threshold. cargo fmt, cargo clippy -D warnings and cargo test --all-features are clean after the extraction. Refs #96
Working session summaryAll six checks are green on
Working tree is clean and The PR title dropped One thing to flag explicitly, since it's the user's call rather than mine: a few template features are still not ported and I listed them nowhere in the PR body — the JS lint stack ( This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $24.553342📊 Context and tokens usage:Claude Opus 5: (6 sub-sessions)
Total: (15.6K new + 522.2K cache writes + 27.4M cache reads) input tokens, 223.5K output tokens, $24.553342 cost 🤖 Models used:
📎 Log file uploaded as Gist (8785KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🎉 Auto-mergedThis pull request has been automatically merged by hive-mind.
Auto-merged by hive-mind with --auto-merge flag |
Closes #96.
What was wrong
mainhad no security workflow and no link checker, three of six pipelines could report success while a job had actually failed, two workflows fought over the same GitHub Pages site, and the wholejs/test suite was never executed by CI. Every finding below is backed by a log or a command indev/log/issues/96/pulls/97/.False negatives — CI reported success on a broken tree
continue-on-error: truemasked the Windows C# test failures; the pipeline stayed green whiledotnet testfailedTransactionsDecorator/VersionControlDecoratornever released their memory-mapped databases, so Windows could not delete the test filesIDisposable; CA1001/CA1063/CA1816/CA2000 enabled,TreatWarningsAsErrorsoncsharp.ymladvertised achangeset-prrelease mode that no job implemented — selecting it produced a green run that did nothingworkflow_dispatchinputs vs. job listrust.ymlgained the matchingchangelog-prmodeCargo.tomlwithout the matchingCargo.lockupdate passed CI while every job silently re-resolved the graphcargo metadata --lockedexits 101 on drift (verified by temporarily bumpingthiserror)js/test/*.test.mjswas never run by any workflownpm run test:jsstep existedwasm.yml; it immediately caught defect 8cargo clippyran without-- -D warnings, so it printed findings and exited 0;rust/wasmwas never formatted or linted at all.github/workflows/rust.ymlexperiments/semantic-merge-conflict.shreproduces it: head green, merged tree red.github/scripts/simulate-fresh-merge.sh+ a pull-request-only job inrust.ymlandcsharp.ymlcheck-web-archive.mjsdropped every lychee error that is not an http URL (missing file, unresolvable root-relative link) and then setall_archived=true, skipping the failure gatecheck-web-archive.test.mjsmain, which is why 4 Dependabot alerts sat unnoticednpm audit --audit-level=highonmain's lockfile exits 1 with 3 high findings (dev/log/.../local/npm-audit-main.log); this branch's lockfile audits cleansecurity.yml(CodeQL, dependency review,cargo audit,npm audit, secretlint)dev/log.secretlintrc.json; the tree scans cleanFalse positives — CI failed on a healthy tree
check-web-archive.mjsscanned the whole lychee report, so bullets under## Redirects per inputwere escalated as broken links: lychee reported 4 errors, the script failed the job over 9 links## Errors per inputsection; regression test over the captured reportjs/index.html's root-relative links (/favicon.svg,/src/main.jsx) were unresolvable to lychee--root-dirpassed to lycheecsharp/docs/api/*.ymlinto the build output and the files are deliberately not committed, so the link could never resolve from a source checkout.lycheeignorewasm.ymltriggered on bothpull_requestandpushto pull-request branches, running every pull request twice.github/workflows/wasm.ymlmainErrors
https://link-foundation.github.io/link-cli/csharp/and/rust/link_cli/returned 404 — bothdocs.ymlandwasm.ymluploaded a Pages artifact, and GitHub Pages serves one site per repository, so the last deployer replaced the other's filescurlagainst the live site: root 200, both sub-paths 404docs.ymlis the only publisher and assembles the workbench (root) plus both API references (/csharp/,/rust/) and a landing page (/docs/) into one artifactCargo.lockfilescargo auditanyhowandmemmap2refreshed.gitkeepat the repository root violatedjs/test/repositoryLayout.test.mjsWarnings
Node.js 20 is deprecated ... actions/github-script@60a0d83 ... forced to run on Node.js 24—codecov/codecov-action@v5pins github-script v7.0.1 (node20); v6/v7 pin v8.0.0 (node24)codecov/codecov-action@v7Cannot build an overlay database because build-mode is set to "undefined"and theDEPRECATEDautobuild inputs, on all four CodeQL languagesbuild-modedeclared per language (autobuildfor C#,noneelsewhere); deprecated standalone autobuild step removedrust/src/query_processor.rs has 994 lines (approaching limit of 1000)rust/src/query_processor/matching.rs(794 lines now; no tracked.rsfile exceeds the 900-line threshold)CS1570warningsHardening applied across every workflow
Every job now declares
timeout-minutes; every workflow declares a top-level least-privilegepermissions:; every job is covered by a concurrency group, with release/Pages jobs in non-cancellable writer groups so a deployment is never killed mid-flight.How this is prevented from regressing
.github/scripts/workflow-policy.test.mjs— 49 assertions run byrust.yml,csharp.yml,wasm.ymlandnpm test:permissions:;continue-on-error, no unwrappedif: !...(a YAML tag, not a negation);release_modeoption is handled by a job;pull_requestand a non-mainpushbranch;cargo clippyinvocation denies warnings;rust.ymlandcsharp.ymlsimulate the fresh merge;Run against the pre-fix tree (
e4a5085) the suite fails 8 assertions, so it is a genuine regression test rather than a description of the current state..github/scripts/check-web-archive.test.mjscovers the lychee parser against a report captured from the failing run, asserting that redirects are not reported as broken and that the parsed error count matches the count lychee itself reports..pre-commit-config.yamlmirrors the cheap gates locally.Reproducing
Reported upstream (issue requirement: "if the same issue is found in template report issue also in templates")
The
check-web-archive.mjsdefects were inherited from the pipeline templates, so both were reported there with reproducible examples, workarounds and suggested code fixes:Evidence
dev/log/issues/96/pulls/97/holds the downloaded CI logs, the local build/test/audit output and the analysis that produced the table above.