Skip to content

feat(selfhost): add a --json output mode to loopover-config-lint (#5931) - #5979

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
nickmopen:feat/config-lint-json-output
Jul 15, 2026
Merged

feat(selfhost): add a --json output mode to loopover-config-lint (#5931)#5979
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
nickmopen:feat/config-lint-json-output

Conversation

@nickmopen

Copy link
Copy Markdown
Contributor

Summary

Adds a --json output mode to scripts/loopover-config-lint.ts (npm run selfhost:config-lint -- [path] [--json]) — closing #5931. It's the one config-validation entrypoint in the repo without a machine-readable output mode, even though the SelfHostConfigLintResult it already computes (ok / warnings / recognizedFields / summary) is trivially JSON-serializable. Every sibling CLI (loopover-mcp validate-config --json, doctor --json, status --json) already supports it, so a self-hoster wiring config-lint into a CI/pre-deploy check had to regex-parse the human-readable report.

With --json, the command prints { path, ...result } pretty-printed to stdout instead of the text report, and keeps the same exit-code behavior (1 when the manifest fails validation). The default text output and the file-read error paths are unchanged.

$ npm run selfhost:config-lint -- .loopover.yml --json
{
  "path": ".loopover.yml",
  "ok": true,
  "warnings": [],
  "recognizedFields": ["wantedPaths"],
  "summary": "Manifest parsed 1 recognized field."
}   # exit 0

$ npm run selfhost:config-lint -- bad.yml --json
{ "path": "bad.yml", "ok": false, "warnings": ["...unknown top-level field: unknownSecretKey."], ... }   # exit 1

What changed

  • scripts/loopover-config-lint.ts: a pure formatLintJson(path, result) export (alongside the existing formatLintReport, so the serialization is directly unit-tested rather than only reached through CLI glue); main() parses --json and picks the first non-flag arg as the path (so --json may appear before or after it); usage() documents the flag.
  • test/unit/loopover-config-lint-script.test.ts: direct formatLintJson unit tests (clean + unknown-field, incl. the same secret-redaction contract the text report has), plus a real subprocess CLI test invoking tsx scripts/loopover-config-lint.ts <manifest> --json — asserting valid JSON with ok/warnings/recognizedFields/summary and the correct exit code (0 clean, 1 on warnings), so a future edit can't silently break the --json wiring in main()'s I/O block.

Scope

  • Conventional Commit title.
  • Focused: one flag on one CLI, mirroring the repo's existing --json convention.
  • Follows CONTRIBUTING.md; no site//CNAME/lovable.
  • Closes #5931.

Validation

  • git diff --check
  • npm run typecheck (0 errors)
  • npx vitest run test/unit/loopover-config-lint-script.test.ts — 12 pass (incl. the 4 new tests)
  • Full vitest run suite green
  • npm run docs:drift-check green
  • Manual CLI check for both clean (exit 0) and failing (exit 1) manifests

scripts/** is excluded from vitest.config.ts coverage.include and listed in codecov.yml's ignore, so this isn't numerically gated by codecov/patch; the required regression coverage is provided via the real subprocess/CLI test above, and the new formatLintJson logic (a pure export outside main()'s /* v8 ignore */ block) is directly unit-tested.

Safety

  • No secrets/wallets/trust-scores/reward terms; JSON output carries only the lint result, and the unknown-field test pins that the raw supplied value is never echoed (same redaction contract as the text report).
  • Auth/CORS/API/OpenAPI/UI — N/A (a standalone dev CLI script; no runtime, binding, schema, or apps/loopover-ui change).

Closes #5931

…Nbored#5931)

scripts/loopover-config-lint.ts was the only config-validation entrypoint in the
repo without a machine-readable output mode, even though the
SelfHostConfigLintResult it already computes (ok/warnings/recognizedFields/summary)
is trivially JSON-serializable — and every sibling CLI (loopover-mcp
validate-config/doctor/status) already supports --json.

Add a --json flag: main() prints `{ path, ...result }` as pretty JSON instead of
the text report, keeping the same exit code (1 when the manifest fails). The
serialization is a pure formatLintJson export (directly unit-tested alongside
formatLintReport), and a real subprocess CLI test invokes the script with --json
for a clean and an unknown-field manifest so the main() wiring can't silently
regress. Default text output and the file-read error paths are unchanged.
@nickmopen
nickmopen requested a review from JSONbored as a code owner July 15, 2026 05:30
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.67%. Comparing base (4749ff7) to head (1738d95).
⚠️ Report is 5 commits behind head on main.

❗ There is a different number of reports uploaded between BASE (4749ff7) and HEAD (1738d95). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (4749ff7) HEAD (1738d95)
shard-6 1 0
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5979      +/-   ##
==========================================
- Coverage   95.16%   85.67%   -9.50%     
==========================================
  Files         589      589              
  Lines       46790    46790              
  Branches    14943    14943              
==========================================
- Hits        44528    40087    -4441     
- Misses       1511     5292    +3781     
- Partials      751     1411     +660     
Flag Coverage Δ
shard-1 43.91% <ø> (ø)
shard-2 36.21% <ø> (ø)
shard-3 31.98% <ø> (ø)
shard-4 31.95% <ø> (ø)
shard-5 32.49% <ø> (-0.01%) ⬇️
shard-6 ?

Flags with carried forward coverage won't be shown. Click here to find out more.
see 119 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 15, 2026
@loopover-orb

loopover-orb Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-15 05:39:10 UTC

2 files · 1 AI reviewer · no blockers · readiness 82/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR adds a `--json` output mode to `loopover-config-lint.ts`, mirroring the existing pattern from sibling CLIs (`loopover-mcp validate-config --json`). The implementation is straightforward: a pure `formatLintJson` export serializes `{ path, ...result }`, `main()` picks the first non-flag argument as the path (allowing `--json` before or after it), and exit-code behavior is preserved. Test coverage is solid, including a real subprocess CLI test that exercises the v8-ignored `main()` I/O block, which is the only place the flag/path parsing logic actually lives.

Nits — 4 non-blocking
  • scripts/loopover-config-lint.ts: `args.find((arg) => !arg.startsWith("-"))` will silently treat a legitimate manifest filename that starts with a hyphen (e.g. `-config.yml`) as a flag and fall back to the default path instead of erroring or using it — worth a one-line doc caveat or at least noting it's an accepted edge case.
  • test/unit/loopover-config-lint-script.test.ts: the subprocess test spawns `tsx` via `execFileSync` with no explicit timeout, so a hang in `main()` would stall the whole suite rather than failing fast.
  • Consider validating/rejecting unrecognized flags (anything starting with `-` that isn't `--json`/`--help`) instead of silently ignoring them, to catch typos like `--jsno`.
  • The JSDoc-style comment in scripts/loopover-config-lint.ts:49-52 is a bit verbose for a two-line function; could be trimmed to the non-obvious part (why it's kept as a separate export) per repo conventions.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #5931
Related work ⚠️ 2 scoped overlaps Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 141 registered-repo PR(s), 87 merged, 9 issue(s).
Contributor context ✅ Confirmed Gittensor contributor nickmopen; Gittensor profile; 141 PR(s), 9 issue(s).
Gate result ✅ Passing No configured blocker found.
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The PR adds a --json flag to main() that outputs JSON.stringify({path, ...result}) via a new formatLintJson export, preserves exit-code behavior, updates usage() text, and leaves default text output and error handling unchanged, matching all stated requirements.

Review context
Contributor next steps
  • Start here: Review top overlaps.
  • Then work through the remaining 2 steps in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask 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.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 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.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

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.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 78df1a1 into JSONbored:main Jul 15, 2026
15 checks passed
@nghetienhiep nghetienhiep mentioned this pull request Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(selfhost): scripts/loopover-config-lint.ts has no --json output mode, unlike sibling validators

1 participant