fix(packaging): ship the LICENSE @loopover/miner declares, and assert it everywhere - #9787
Conversation
… it everywhere packages/loopover-miner declares "license": "AGPL-3.0-only" and is published, yet ships no LICENSE file. Every published sibling carries one. Distributing a copyleft package without its license text is a licensing defect, not packaging tidiness. (discovery-index has none either, but it is private: true and declares no license -- correctly excluded, not a gap.) It could not simply be added: check-miner-package.ts's ALLOWED list had no /^LICENSE$/ entry, so dropping the file in would have failed test:miner-pack with "Unexpected file in miner package: LICENSE". The omission was actively enforced. The wider class is that NO published package's checker ever asserted the file. engine and ui-kit allowed it without requiring it; check-mcp-package.ts had no required-files concept at all, only an allowlist. LICENSE could therefore drop silently out of any of them -- miner is simply where it happened. So this requires it in all four, and gives the MCP checker the required-files assertion it was missing (package.json is asserted alongside LICENSE there, so a pathologically empty file list cannot pass every other check by vacuous truth). Same discipline check-miner-package.ts already applies to DEPLOYMENT.md and the Dockerfile -- "asserted present so they can never silently drop out of the package again" -- and more warranted here: a missing operational doc is an inconvenience, a missing license is a distribution defect. Verified non-vacuous rather than assumed: removing the file makes test:miner-pack fail with "Miner package is missing required file: LICENSE", and each checker gains a negative test pinning that message. Three existing fixtures modelled a valid package without a LICENSE and were made faithful instead of the assertion being relaxed -- two of them assert OTHER failures (missing docs/*.md, missing dist/components), and were masked by the new check firing first. @loopover/contract needs nothing: it has a LICENSE, and publish-contract.yml already validates its tarball inline against an allowlist that includes it. Closes #9786
|
Warning ⏸️ LoopOver review result - manual review recommendedReview updated: 2026-07-29 10:08:58 UTC
Review summary Nits — 7 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Decision record
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
loopover-ui | 86de616 | Commit Preview URL Branch Preview URL |
Jul 29 2026, 09:24 AM |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9787 +/- ##
==========================================
+ Coverage 90.33% 95.57% +5.24%
==========================================
Files 917 814 -103
Lines 113904 62930 -50974
Branches 26966 21930 -5036
==========================================
- Hits 102894 60145 -42749
+ Misses 9681 1474 -8207
+ Partials 1329 1311 -18
Flags with carried forward coverage won't be shown. Click here to find out more. |
…eckers now require The clean-content case in forbidden-content.test.ts exits 1 on "Missing required file in MCP package: LICENSE" instead of reaching the content read, because this change gave the MCP checker a required-file guard it never had. REACHABLE_FILES documents itself as "a minimal file list that passes each checker's path/allowlist/required-file guards, so the run reaches the shared secret-content read" -- LICENSE now belongs in it. Added to the miner list too, so the list stays honest about the guards it claims to satisfy rather than depending on that checker reading content before it checks required files.
… it is (#9799) * fix(ci): normalize committed CRLF to LF and name the failure for what it is Twenty files were committed with CRLF and the repo had no .gitattributes. The `changes` job runs `git diff --check`, and git's default core.whitespace is `blank-at-eol` with `cr-at-eol` off, so a carriage return at end-of-line counts as trailing whitespace. Any PR adding a line to one of those files failed CI pointing at lines whose visible content is spotless, with nothing in the log saying "CRLF" — it hit #9787 (run 30436384202) on two lines of inline-suggestion-anchor.ts. Convert all twenty to LF via `git add --renormalize`, byte-identical otherwise (`git diff -w` reports only the two new files below), and pin the repo with `* text=auto eol=lf`. `text=auto` rather than a bare `text` is load-bearing: five .ts files embed NUL bytes as untrusted-text and sanitizer fixtures, and auto-detection classifies them binary and passes them through untouched. The whitespace step now names CRLF before falling through to the generic check. .gitattributes stops CRLF entering through `git add`, but checkin filters don't run on blobs written directly (web editor, Contents API) or on a merge of a branch cut earlier, so the diagnostic still has a job. It is scoped to added lines, so it fires on exactly what `git diff --check` already flagged — a relabel, not a new failure mode. Closes #9798 * test(engine): cover the package-local buildIssueQualityReport in the engine suite `buildIssueQualityReport` is re-exported from the engine barrel (src/index.ts) but this package's own node:test suite never called it. `npm run engine:coverage` therefore saw the module load — top-level constants only — and reported it LF:313 LH:96 with BRF:0, i.e. no function-level data at all, while the root vitest suite covered the same file 87/87 lines and 143/143 branches. Two uploads disagreeing about the same file is invisible while patch coverage only reads changed lines, because nothing changes all 313 at once. Renormalizing the file's line endings did, and the merged report capped at ~57%: of the 217 lines the engine flag called uncovered, 84 were rescued by vitest and 133 were function-signature and closing-brace lines v8 never lists as statements, so nothing could rescue them. Cover it where this package is actually graded rather than leaning on the vitest duplicate — the outcome scripts/engine-coverage.ts (#9064) was written to encourage. The file now reports 313/313 lines and 163/163 branches under the engine model. 17 cases covering the lane arms (issue_discovery / direct_pr / split / unknown), every bounty lifecycle, duplicate and invalid labelling, self-solved loops, maintainer-authored vs maintainer-WIP, linkedPrs back-references for both open and merged PRs, collision risk tiers, sort order, the lifecycle and report caps, and the null-repo / unparseable-date degradation paths. --------- Co-authored-by: JSONbored <aetherealdev@gmail.com>
Summary
packages/loopover-minerdeclares"license": "AGPL-3.0-only"and is published — and ships no LICENSE file. Every published sibling carries one. Distributing a copyleft package without its license text is a licensing defect, not packaging tidiness.(
discovery-indexhas none either, but it isprivate: trueand declares no license — correctly excluded, not a gap.)Closes #9786
Why it was missing
It could not simply be added.
check-miner-package.ts'sALLOWEDlist had no/^LICENSE$/entry, so dropping the file in would have failedtest:miner-packwith "Unexpected file in miner package: LICENSE". The omission was actively enforced.The wider class
No published package's checker ever asserted the file.
engineandui-kitallowed it without requiring it;check-mcp-package.tshad no required-files concept at all, only an allowlist. LICENSE could therefore drop silently out of any of them — miner is simply where it happened.So this requires it in all four, and gives the MCP checker the required-files assertion it lacked.
package.jsonis asserted alongside LICENSE there, so a pathologically empty file list cannot pass every other check by vacuous truth.Same discipline
check-miner-package.tsalready applies toDEPLOYMENT.mdand theDockerfile— "asserted present so they can never silently drop out of the package again" — and more warranted here: a missing operational doc is an inconvenience, a missing license is a distribution defect.Validation
Verified non-vacuous rather than assumed. Removing the file makes the real check fail:
test:mcp-pack·test:miner-pack·test:engine-pack·test:ui-kit-pack(realnpm packdry-runs)typecheck·validate:no-hand-written-js·coverage-boltons:check·release-linked-versions:check·git diff --checkThree existing fixtures were made faithful rather than the assertion relaxed. They modelled a valid published package without a LICENSE, which is no longer valid. Two of them assert other failures —
ui-kit's "nodist/components/*.jsartifacts" and miner's "at least onedocs/*.md" — and were masked because the new check fired first and changed which error surfaced. Adding LICENSE to those fixtures restores each test to failing for its own reason.@loopover/contractneeds nothing: it has a LICENSE, andpublish-contract.ymlalready validates its tarball inline against an allowlist that includes it.Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Safety
UI Evidencesection below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.No runtime code, no
src/**change, no UI output — packaging checks and one license file, hence no coverage obligation and no UI Evidence table. The change only ever adds a required artifact; every existing forbidden-path and secret-content check is untouched and still passes.npm packincludes LICENSE automatically regardless of thefilesarray, which is exactly why the checker — notfiles— is where this has to be enforced.