Skip to content

config-lint's recognizedFieldsFor lacks the YAML-fallback-on-JSON-failure its sibling unknownTopLevelWarnings has #7244

Description

@JSONbored

Context

packages/loopover-engine/src/config-lint.ts has two independent top-level-object parsers for the same manifest text, and they disagree on JSON/YAML fallback behavior:

  • parseTopLevelObject (line 111-126, used by unknownTopLevelWarnings, line 79): when the text looks like JSON (starts with {/[) but JSON.parse throws, it falls back to parseYaml(text) in a second try. The code comments why: "YAML flow mappings can start with { or [ while still being valid manifest syntax."
  • parseCanonicalTopLevelObject (line 99-109, used by recognizedFieldsFor, line 65): does the same looksLikeJson branch, but on a JSON.parse failure it does NOT fall back to YAML — the whole thing is one try/catch that returns null on any failure:
try {
  return topLevelObjectOrNull(looksLikeJson ? JSON.parse(trimmed) : parseYaml(trimmed));
} catch {
  return null;
}

Concretely: a manifest that is a valid YAML flow mapping starting with { (e.g. {settings: {reviewMode: strict}} without JSON-quoted keys) is real, parseable manifest syntax per unknownTopLevelWarnings's own comment. For that exact text, unknownTopLevelWarnings correctly falls back to YAML and evaluates unknown-field warnings against the real parsed object. But recognizedFieldsFor — called from buildConfigLintReport (line 44) to build the "Manifest parsed N recognized fields" report — hits the JSON.parse failure, catches it, and returns null[], silently reporting zero recognized fields for a manifest that actually parses and is fully valid. The two functions produce internally inconsistent results (unknownTopLevelWarnings sees real fields and emits real warnings about them; recognizedFieldsFor sees nothing) for the identical input text within the same buildConfigLintReport call.

Requirements

  • parseCanonicalTopLevelObject must apply the same JSON→YAML fallback parseTopLevelObject already applies: on a JSON.parse failure when looksLikeJson is true, retry with parseYaml before giving up and returning null.
  • After the fix, recognizedFieldsFor and unknownTopLevelWarnings must agree on whether a given manifest text parses, for every input — de-duplicate the fallback logic into one shared helper used by both functions rather than hand-maintaining two copies, so this can't drift again.

Deliverables

  • parseCanonicalTopLevelObject (or its replacement shared helper) applies the JSON→YAML fallback for looksLikeJson text, matching parseTopLevelObject's existing behavior
  • Shared parsing helper used by both recognizedFieldsFor and unknownTopLevelWarnings (eliminate the duplicate looksLikeJson/try-catch logic between parseCanonicalTopLevelObject and parseTopLevelObject)
  • Regression test: a manifest text that is a valid YAML flow mapping starting with { (invalid as strict JSON, e.g. unquoted keys) produces a non-empty recognizedFieldsFor result consistent with what unknownTopLevelWarnings already reports for the same text

Test Coverage Requirements

This repo's Codecov patch gate is 99%+ hard (branch-counted) on every changed line/branch in src/**/packages/**. The regression test above must reproduce the exact silent-empty-result failure mode described and assert it's fixed.

Expected Outcome

recognizedFieldsFor and unknownTopLevelWarnings parse the same manifest text consistently — a YAML-flow-mapping manifest starting with { is recognized by both, and buildConfigLintReport's "recognized N fields" summary no longer silently under-reports for valid manifests.

Links & Resources

packages/loopover-engine/src/config-lint.ts:65-71 (recognizedFieldsFor), :79-97 (unknownTopLevelWarnings, the correct fallback), :99-109 (parseCanonicalTopLevelObject, the gap), :111-126 (parseTopLevelObject, the sibling with the fallback already applied).

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions