Skip to content

orb(content-lane): assessSubnetDocument accepts null/""/true as a valid netuid #9665

Description

@JSONbored

⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.

Context

assessSubnetDocument (src/review/content-lane/registry-logic.ts:546 onward) is the content lane's
document-shape validator for a registry subnet file. Its root-netuid check is:

if (!Number.isInteger(Number(doc.netuid))) {
  return fail("unsupported-shape", "Subnet document netuid must be an integer.");   // :555-556
}
const netuid = Number(doc.netuid); // normalize once; thread the canonical integer to entry + (future) grounding

Number() coerces before the integer test, so the check passes for values the message promises it
rejects: Number(null) === 0, Number("") === 0, Number([]) === 0, Number(true) === 1,
Number([5]) === 5, Number("0x10") === 16, Number(" 7 ") === 7. A document with
"netuid": null is therefore accepted as subnet 0.

That fabricated value is load-bearing downstream. assessSurfaceEntry
(src/review/content-lane/registry-logic.ts:500-510) compares each appended surface against it via
Number(surface.netuid) !== netuid, and its own comment explicitly relies on the contract the check
above does not enforce ("the document validator already proved the root netuid is an integer"). So a
submission with a null/blank/boolean root netuid and surfaces declaring netuid: 0 (or null, which
also coerces to 0) passes the consistency check and can reach a decisive merge verdict on the
surface lane — which, per src/review/content-lane-wire.ts's applySurfaceGate, can override an
AI-judgment-only generic failure.

Requirements

  • The root-netuid check must reject any doc.netuid that is not already a JavaScript number which is
    an integer — i.e. validate the raw value's type before any coercion, not Number(raw).
  • A numeric string (e.g. "7") must ALSO be rejected, and the failure summary must stay
    "Subnet document netuid must be an integer." with reason code "unsupported-shape" (the string
    is asserted by existing tests and rendered into the public close comment).
  • A negative integer must be rejected (a netuid is a non-negative index); 0 must remain valid.
  • const netuid = Number(doc.netuid) at :558 must become a direct read of the already-validated
    number, so no coercion remains on this path.
  • No change to assessSurfaceEntry's comparison or to any other assessment branch.

⚠️ Required pattern: the type-first shape of the sibling check three lines below —
if (!Array.isArray(doc.surfaces)) at src/review/content-lane/registry-logic.ts:559 — which tests
the raw value's type and never coerces. What does NOT satisfy this issue: keeping Number() and
adding a typeof doc.netuid !== "object" style patch on top; accepting numeric strings "for
leniency"; changing the failure summary text or reason code; or adding a new exported validator
helper instead of fixing this branch in place.

Deliverables

  • assessSubnetDocument in src/review/content-lane/registry-logic.ts returns
    fail("unsupported-shape", …) for each of null, "", true, [], [5], "7", "0x10",
    1.5, -1, and undefined as doc.netuid, asserted by a new table-driven named case in
    test/unit/content-lane-registry-logic.test.ts.
  • The same test asserts netuid: 0 and netuid: 64 still produce a non-unsupported-shape
    outcome (the check is not over-tightened).
  • A named regression test asserts a document with "netuid": null and a surface declaring
    "netuid": 0 no longer reaches a merged verdict — it fails on unsupported-shape.
  • const netuid at src/review/content-lane/registry-logic.ts:558 no longer calls Number().

All Deliverables above are required in a single PR. A PR that satisfies only some of them — for
example tightening the check (Deliverable 1) while leaving the Number() normalization at
:558 in place — does not resolve this issue.

Test Coverage Requirements

This repo enforces 99%+ Codecov patch coverage, branch-counted, and vitest.config.ts's
coverage.include covers src/**/*.ts — this file is measured. Both arms of the new condition need
tests (valid integer, and each rejected shape). The end-to-end netuid: null + surface netuid: 0
regression test in Deliverable 3 is required by name.

Expected Outcome

A registry subnet document whose root netuid is not a real integer is rejected with the message the
code already prints, instead of being silently normalized to subnet 0 and threaded into the per-surface
consistency check as if it had been validated.

Links & Resources

  • src/review/content-lane/registry-logic.ts:546-560 (the defect), :500-510 (the downstream consumer)
  • src/review/content-lane/orchestrator.ts:371-383 (where the assessment becomes the verdict)
  • test/unit/content-lane-registry-logic.test.ts

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