LearnNewsExamplesServices
Frontmatter
title>-
authorneo-opus-grace
stateMerged
createdAtAug 4, 2026, 7:27 PM
updatedAtAug 5, 2026, 12:05 AM
closedAtAug 5, 2026, 12:05 AM
mergedAtAug 5, 2026, 12:05 AM
branchesdevgrace/16505-predicate-contract-and-home
urlhttps://github.com/neomjs/neo/pull/16509
contentTrust
projected
quarantined0
signals[]
Merged
neo-opus-grace
neo-opus-grace commented on Aug 4, 2026, 7:27 PM

Resolves #16505

Follow-up from PR #16489's approval, deferred by @neo-gpt-emmy rather than bought with another review cycle. Documentation and one deleted line; no runtime change.

The @param was arguing against the contract, not just imprecise

evaluateCohortAdmissibility was annotated @param {Object} options.cohortData. The function is specified to accept undefined, null, a scalar, an array and a descriptor-free tree, and to refuse each through sourceError — that acceptance is the source guard's deliverable.

{Object} tells a caller to pre-validate, and both ways they would do that are wrong:

  • a duplicate upstream guard reimplements this one, less carefully
  • throwing on a non-object lets one unreadable candidate abort a whole selection pass, instead of being skipped and recorded — exactly what the review's fork resolution ruled out

Evidence: assessCohortSource in the same file already typed its own input {*}, so the module contradicted itself at two adjacent entry points.

sourceError was invisible to the consumer it exists for

Absent from the documented return shape. Now stated, including the half that carries the meaning: it is null on every successfully-observed evaluation, including inadmissible ones.

So admissible: false with sourceError: null is a fact about the target; a non-null sourceError is a fault upstream of it. A consumer that never learns the field exists collapses both into a bare boolean — the exact conflation the guard was built to prevent, reappearing one layer down.

Placement: settled, and the answer is smaller than the ticket predicted

The ticket asserted ai/scripts/setup/ holds only one-shot CLIs, so a consumed library sits wrong there. Checking falsified my own premise: initServerConfigs.mjs and seedAgentIdentities.mjs carry no shebang and are libraries. The folder is not CLI-only, and the module is already at home beside migrateConfigOverlay.mjs — the sibling covering the config-overlay half of the same problem while stating it never handles env-resolved values, which is precisely the half this covers. Relocating would have churned a just-merged file to solve a problem that was not there. Ticket body corrected in place.

The real defect was one line. The file carried #!/usr/bin/env node with no argv handling, no import.meta.url entry guard and no main() — ten exports and nothing else. Its mode is -rw-r--r--, so the shebang could not have functioned even if something had tried to run it, and nothing does. A shebang announces "runnable as a program"; on a pure library it misdeclares the file to every reader and to any census that sorts scripts from libraries. Removed rather than made true, with the reasoning recorded in the module header where the next reader meets it.

Test Evidence

120 passed across ai/scripts/setup/, spec unmodified — which is the point: a documentation change that altered behaviour would show up as a spec edit, and there is none. The 24-case cohortAdmissibility suite already pins every input shape the widened @param now documents, so the annotation is describing tested behaviour rather than asserting new behaviour.

No mutation receipts: nothing executable changed. The one runtime-adjacent edit is the shebang deletion, and its falsifier is that the file has no exec bit and no invoker — git grep cohortAdmissibility -- package.json ai/ returns only the module itself.

Deltas

  • ai/scripts/setup/cohortAdmissibility.mjs@param widened to {*} with the accepted shapes named; sourceError added to @returns with its null-on-success contract; placement rationale recorded in the module header; false shebang removed.
  • No other file touched. No spec change, no behaviour change, no relocation.

Post-Merge Validation

Closes every #16505 AC. The two items @neo-gpt-emmy scoped onto #16451 are correctly split: the ineligibility-record half stays there because that record is selection's own data structure, and only the module-facing half landed here.

Watch for one thing after #16451 wires a consumer: this documents sourceError as the discriminator, and the value of that only realises if the consumer branches on it rather than on admissible alone. If the ineligibility record ends up carrying a bare boolean, the annotation was accurate and still failed to do its job.

Authored by @neo-opus-grace (Claude Opus 5)

tobiu
tobiu APPROVED reviewed on Aug 5, 2026, 12:04 AM

No review body provided.