Skip to content

ci(config): check the manifest field list against what the parser reads - #9980

Merged
loopover-orb[bot] merged 1 commit into
mainfrom
ci/guard-focus-manifest-field-list-9979
Jul 31, 2026
Merged

ci(config): check the manifest field list against what the parser reads#9980
loopover-orb[bot] merged 1 commit into
mainfrom
ci/guard-focus-manifest-field-list-9979

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Item 4 of #9860, scoped to its one currently-unverified claim. Filed and shipped separately because #9860 explicitly asks for one independently-checkable change per PR.

The claim nothing was checking

// Every top-level key `parseFocusManifest` below actually reads. Single source of truth for "unknown
// top-level field" detection (#9065) ...
export const FOCUS_MANIFEST_TOP_LEVEL_FIELDS = [ ... 28 entries ... ] as const;

That first sentence is a fact about code twenty lines further down. It is exactly the shape #9860 calls out as the tell — a snapshot written as though it were a guarantee.

Why drift is silent, and worse in one direction

This list is the single source of truth for unknown-field detection, so neither direction surfaces anywhere:

Drift What an operator sees
Declared but never read The parser accepts the field, warns about nothing, and ignores it. They set it in .loopover.yml, get no error, and it does nothing. It looks configured.
Read but not declared The parser consumes the field while warning "unknown top-level field" about it, and config-lint's recognizedFieldsFor omits it from the recognized count. A working field reported as a mistake.

Adding a top-level field means editing two places twenty lines apart — and #9813 and #9821 each shipped a bug from missing one touchpoint of a multi-touchpoint field.

Computed, not restated

There is deliberately no second list. Declared names are read out of the array literal; used names out of the function body. The checker holds nothing to keep in sync and cannot itself go stale — the bar #9853 set.

On using a regex rather than the AST

A real tradeoff, stated rather than glossed. The access pattern is uniform and mechanical (record.<field>, inside one function). The risk with any regex guard is that it silently matches nothing and reports success, so every extractor throws instead:

  • constant renamed or deleted → could not find the FOCUS_MANIFEST_TOP_LEVEL_FIELDS declaration
  • signature moved → could not find export function parseFocusManifest
  • refactored to destructuring (const { gate } = record) → the access pattern this checker relies on has changed

The body is also bounded at the next top-level export, because focus-manifest.ts declares many sibling parsers that all destructure a local named record; reading past that boundary would pull their field names in and report permanent phantom drift. Both are pinned by tests.

It holds today

28 declared, 28 read, empty in both directions — so this lands green and guards forward, rather than arriving after the next drift.

Mutation testing

Mutation Result
Declare ghostField, never read it fails — names ghostField, tells you to read or remove it
Read record.orphanField, never declare it fails — names orphanField, tells you to add it
Remove publicProof while the parser still reads it fails — names publicProof

Baseline restored: 28 top-level field(s) declared and read; no drift.

Plus 15 unit tests, including the two "guard the guard" cases: that both extractors return a non-trivial number of fields, so the real-file invariant cannot pass on an empty set.

Verification

  • typecheck, checkers-wired:check, dead-source-files:check, dead-exports:check, import-specifiers:check, coverage-boltons:check, validate:no-hand-written-js green
  • Wired into test:ci; checkers-wired:check confirms it actually runs

Closes #9979

@loopover-orb

loopover-orb Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-31 02:45:08 UTC

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

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
Adds a standalone checker that extracts declared top-level fields from FOCUS_MANIFEST_TOP_LEVEL_FIELDS via regex and compares them against record.<field>/record["<field>"] reads inside parseFocusManifest, wiring it into test:ci. The extraction logic looks sound: it fails loudly (throws) on a missing declaration, missing function signature, or zero matched reads rather than silently passing, which avoids the vacuous-pass failure mode the PR explicitly calls out. Tests cover both drift directions, the function-boundary stop logic, bracket-access reads, and assert the invariant against the real focus-manifest.ts file, and CI is green on this exact commit.

Nits — 6 non-blocking
  • scripts/check-focus-manifest-fields.ts:44-45 — the DECLARATION regex captures everything between the first `[` and the last `] as const;` in the file (dotall), so if a second `as const` array literal is ever added above FOCUS_MANIFEST_TOP_LEVEL_FIELDS in the same file, the match could grab an unintended span; worth anchoring more tightly (e.g. requiring the match starts at a line beginning) if that's a real risk in this file.
  • scripts/check-focus-manifest-fields.ts:97 — the self-execution guard block is flagged as depth 5 against a stated threshold of 4; consider extracting the drift-reporting branch into a small helper to flatten it, though this is purely a style/complexity nit and the block is v8-ignored.
  • The regex-over-AST approach is a stated tradeoff with fail-loud guards, which is reasonable, but it will still silently miss a field accessed via a non-`record.` alias (e.g. destructured or renamed local) inside parseFocusManifest — the PR acknowledges destructuring is covered by the 'yields nothing' throw, but a partial alias wouldn't trigger that check; worth a one-line caveat in the comment.
  • Consider tightening the DECLARATION regex to be non-greedy across multiple similarly-shaped `as const` arrays if focus-manifest.ts is expected to grow more such lists (scripts/check-focus-manifest-fields.ts:44).
  • The PR is well-scoped to a single checkable claim per its own description and issue ci: FOCUS_MANIFEST_TOP_LEVEL_FIELDS claims to match what the parser reads, and nothing checks it #9979/Generate or guard the remaining hand-maintained lists — three shipped red-main incidents traced to one class #9860 item 4 conventions — no action needed, just noting the scope discipline is followed correctly.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.

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 #9979
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low 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: 9 registered-repo PR(s), 8 merged, 274 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 9 PR(s), 274 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Linked issue satisfaction

Addressed
The PR adds a checker that computes declared fields from the array literal and read fields from parseFocusManifest's body via regex, compares them bidirectionally with named field errors, wires it into package.json and test:ci, and includes tests including a live invariant check against the real file.

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 9 PR(s), 274 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
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.

Decision record
  • action: hold · clause: success
  • config: 564b0523debd9342ae25d6cf528f8e5d9b8d6b38b9bfb3fe227e15a02ba917ac · pack: oss-anti-slop · ci: passed
  • record: 0ceb48a4d1625c45f907ab75f3f2f0eb5cfc8e1f59e0db7c436b75454a36709b (schema v6, head 598f2ab)

🟩 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

@superagent-security

Copy link
Copy Markdown
Contributor

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

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
loopover-ui cef3a55 Commit Preview URL

Branch Preview URL
Jul 31 2026, 02:31 AM

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

@JSONbored JSONbored self-assigned this Jul 31, 2026
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.88%. Comparing base (910fa59) to head (cef3a55).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #9980   +/-   ##
=======================================
  Coverage   91.88%   91.88%           
=======================================
  Files         928      928           
  Lines      113722   113722           
  Branches    27436    27436           
=======================================
  Hits       104489   104489           
  Misses       7936     7936           
  Partials     1297     1297           
Flag Coverage Δ
backend 95.67% <ø> (ø)

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

FOCUS_MANIFEST_TOP_LEVEL_FIELDS' own header says "Every top-level key
parseFocusManifest below actually reads." That is a statement about code twenty
lines further down, and nothing enforced it -- the same shape as the turbo.json
inputs comment #9860 calls out as the tell: a snapshot written as a guarantee.

The list is the single source of truth for unknown-field detection (#9065), so
drift is silent in both directions and asymmetrically bad:

  DECLARED BUT NEVER READ -- the parser accepts the field, warns about nothing,
  and ignores it. An operator sets it in .loopover.yml, sees no error, and the
  setting does nothing. This is the worse direction: it looks configured.

  READ BUT NOT DECLARED -- the parser consumes the field while warning "unknown
  top-level field" about it, and config-lint's recognizedFieldsFor leaves it out
  of the recognized count. A working field reported as a mistake.

Adding a field means editing two places twenty lines apart, and #9813 and #9821
each shipped a bug from missing one touchpoint of a multi-touchpoint field.

Computed, not restated: the declared names come out of the array literal and the
used names out of the function body, so this file holds no second list and
cannot itself go stale.

It is a regex over source rather than the TS AST, which is a real tradeoff. The
access pattern is uniform and mechanical, and every extractor THROWS when the
shape it depends on is missing -- a renamed constant, a moved signature, or a
refactor to destructuring all fail loudly instead of matching nothing and
reporting "no drift". A guard that passes vacuously is worse than none, because
its presence reads as coverage.

Holds today at 28 declared and 28 read, empty both ways, so this lands green and
guards forward. Mutation-tested: declaring an unread field, reading an
undeclared one, and removing a still-read declaration each fail with the field
named.

Closes #9979
@JSONbored
JSONbored force-pushed the ci/guard-focus-manifest-field-list-9979 branch from 598f2ab to cef3a55 Compare July 31, 2026 02:26

@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 870cfcc into main Jul 31, 2026
9 checks passed
@loopover-orb
loopover-orb Bot deleted the ci/guard-focus-manifest-field-list-9979 branch July 31, 2026 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: FOCUS_MANIFEST_TOP_LEVEL_FIELDS claims to match what the parser reads, and nothing checks it

1 participant