Skip to content

feat(mcp): validate .loopover.yml offline by extracting buildFocusManifestValidation into @loopover/engine - #6425

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
davion-knight:feat-mcp-validate-offline-v2
Jul 16, 2026
Merged

feat(mcp): validate .loopover.yml offline by extracting buildFocusManifestValidation into @loopover/engine#6425
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
davion-knight:feat-mcp-validate-offline-v2

Conversation

@davion-knight

Copy link
Copy Markdown
Contributor

What & why

loopover_validate_config's result builder, buildFocusManifestValidation, lived app-only in src/services/focus-manifest-validation.ts, so the local stdio server had to apiPost to /v1/validate/focus-manifest to validate a manifest — unusable offline. Its parsing core (parseFocusManifestContent) was already engine-side, but the result builder and its unknownTopLevelWarnings dependency (src/selfhost/config-lint.ts) were not.

This extracts both into @loopover/engine, following the established extraction pattern (a re-export shim left at each original src/ location), and rewires the local handler to compute in-process.

Changes

  • New packages/loopover-engine/src/focus-manifest-validation.ts and packages/loopover-engine/src/config-lint.ts — the extracted builders, importing the manifest core engine-relative.
  • Shims at src/services/focus-manifest-validation.ts and src/selfhost/config-lint.ts re-export the engine surface, so the remote server (src/mcp/server.ts) and API (src/api/routes.ts) — and every existing config-lint caller — keep working unchanged (no behavior change).
  • Exports added to packages/loopover-engine/package.json (./config-lint, ./focus-manifest-validation) and the barrel.
  • Local handler loopover_validate_config now calls buildFocusManifestValidation(input) directly instead of apiPost — fully offline.

The extraction necessarily brings unknownTopLevelWarnings (and its config-lint module) engine-side too, since the engine cannot import from src/; config-lint is self-contained (only yaml + engine symbols), so it moves cleanly with a shim for its other callers.

Tests

  • All existing focus-manifest-validation (13), selfhost-config-lint (22), loopover-config-lint-script (12), and config-templates tests pass against the new location.
  • Adds test/unit/mcp-cli-validate-config-offline.test.ts — drives the real stdio loopover_validate_config with a black-holed API URL (http://127.0.0.1:1) to prove it validates in-process (well-formed → ok, unknown field → warn, unparseable → error); a residual round-trip would fail these.
  • Both new engine files are at 100% line + branch coverage via the migrated tests.

Closes #6269

@davion-knight
davion-knight requested a review from JSONbored as a code owner July 16, 2026 07:04
@superagent-security

Copy link
Copy Markdown
Contributor

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

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 16, 2026
…ifestValidation into @loopover/engine

loopover_validate_config's result builder, buildFocusManifestValidation, lived app-only in
src/services/focus-manifest-validation.ts, so the local stdio server had to POST to
/v1/validate/focus-manifest to validate a manifest -- unusable offline. Its parsing core
(parseFocusManifestContent) was already engine-side, but the result builder and its
unknownTopLevelWarnings dependency (src/selfhost/config-lint.ts) were not.

Extract both into @loopover/engine (packages/loopover-engine/src/{focus-manifest-validation,config-lint}.ts),
leaving re-export shims at the original src/ locations so the remote server (src/mcp/server.ts) and
API (src/api/routes.ts) keep working unchanged. Add the two exports-map entries and barrel re-exports.
Rewire the local loopover_validate_config handler to call buildFocusManifestValidation in-process
instead of apiPost, so a user validates a .loopover.yml fully offline.

All existing focus-manifest-validation and config-lint tests pass against the new location; adds a
stdio test that drives loopover_validate_config with an unreachable API URL to prove offline behavior.

Closes JSONbored#6269
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.61%. Comparing base (a2d8306) to head (787d1cd).
⚠️ Report is 9 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6425   +/-   ##
=======================================
  Coverage   95.61%   95.61%           
=======================================
  Files         600      600           
  Lines       47346    47354    +8     
  Branches    15067    15068    +1     
=======================================
+ Hits        45268    45276    +8     
  Misses       1291     1291           
  Partials      787      787           
Flag Coverage Δ
shard-1 44.13% <5.55%> (+0.10%) ⬆️
shard-2 36.65% <5.55%> (-0.11%) ⬇️
shard-3 32.26% <83.33%> (-0.09%) ⬇️
shard-4 34.60% <5.55%> (+0.07%) ⬆️
shard-5 30.80% <82.22%> (-0.76%) ⬇️
shard-6 45.30% <38.88%> (+0.31%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-engine/src/config-lint.ts 100.00% <100.00%> (ø)
...s/loopover-engine/src/focus-manifest-validation.ts 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

@loopover-orb

loopover-orb Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-16 07:39:40 UTC

8 files · 1 AI reviewer · no blockers · readiness 88/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This is a clean, mechanical extraction: the two builders (`buildFocusManifestValidation`, `lintManifestText`/`unknownTopLevelWarnings`) move verbatim from `src/` into `@​loopover/engine`, with shims left behind for existing callers, matching the repo's established extraction pattern (referenced as #6269 in comments). The MCP CLI handler is rewired from an `apiPost` round-trip to a direct in-process call, and the new offline test deliberately points at an unreachable API URL to prove no network round-trip occurs. The diffs are byte-for-byte moves (confirmed against full file content) with no logic changes, so behavior parity is very likely intact.

Nits — 5 non-blocking

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #6269
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
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: 157 registered-repo PR(s), 103 merged, 0 issue(s).
Contributor context ✅ Confirmed Gittensor contributor davion-knight; Gittensor profile; 157 PR(s), 0 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Review context
  • Author: davion-knight
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 157 PR(s), 0 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Add a concise scope and risk note.
  • Then work through the remaining 1 step 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://loopover.ai/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 22faecf into JSONbored:main Jul 16, 2026
17 checks passed
This was referenced Jul 16, 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(mcp): extract buildFocusManifestValidation into @loopover/engine so loopover_validate_config can work offline

1 participant