Skip to content

refactor: centralize duplicate-value checks across four validator scripts - #1767

Merged
mrbobbytables merged 1 commit into
mainfrom
arch/centralize-validator-dedup
Oct 22, 2026
Merged

mrbobbytables merged 1 commit into
mainfrom
arch/centralize-validator-dedup

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Refactor

scripts/validate-architectures.mjs, scripts/validate-community-groups.mjs,
scripts/validate-members.mjs, and scripts/validate-projects-born.mjs each
carried an independent copy of the same per-entry dedup check (track seen
values in a Set, push an error on a repeat), differing only in variable
names and the error message.

Adds checkDuplicateValue() — dedup-only, no presence check — in a new
scripts/lib/duplicate-check.mjs, with its own tests/duplicate-check.test.mjs,
and migrates the four scripts to it, each keeping its existing guard
structure (unconditional add+check, if (group.slug), or
typeof === 'string') so behavior for a missing value is unchanged in every
case.

Why a new file instead of scripts/lib/validate-utils.mjs

checkDuplicateOrMissingId() already in validate-utils.mjs also flags a
falsy value as an error on its own. All four scripts here already run a
separate presence check on the same field (checkNonEmptyString() or an
inline check), so reusing that helper as-is would double-report a single
missing entry as both "missing" and "duplicate".

validate-utils.mjs and its test file are also under active review in
hold-gated PR #1761, and tests/coverage-report-cli.test.mjs enforces 100%
coverage of validate-utils.mjs specifically from validate-utils.test.mjs
— any new export there needs a same-PR test addition to that exact file.
Keeping the narrower, dedup-only check in its own module avoids touching
#1761's claimed files.

Evidence

node --test tests/validate-architectures.test.mjs tests/validate-community-groups.test.mjs \
  tests/validate-members.test.mjs tests/validate-projects-born.test.mjs tests/duplicate-check.test.mjs
  112 tests, 0 fail

npm run test:unit:coverage:check
  3031 tests, 0 fail
  src files 100.00% lines (11098/11098) 100.00% regions (3014/3014)
  exit 0

npx eslint --max-warnings 0 .   exit 0
npx prettier --check ...        All matched files use Prettier code style!
npm run check:duplication       ok (247 clones, ceiling 251)
npm run check:unused            ok

Files claimed by this PR

scripts/lib/duplicate-check.mjs, tests/duplicate-check.test.mjs,
scripts/validate-architectures.mjs, scripts/validate-community-groups.mjs,
scripts/validate-members.mjs, scripts/validate-projects-born.mjs. No
workflow file touched. Disjoint from the three open hold-gated PRs
(#1761 claims scripts/lib/url-safety.mjs / tests/validate-utils.test.mjs,
#1763 claims scripts/audit-gate.mjs / tests/audit-gate.test.mjs, #1765
claims tests/svg-active-content.test.mjs).

Related Issue

Fixes #1766


Filed by architect agent (ACMM L5 — hold-gated mode). Hold-gated: human review required.

— hive: agent=architect backend=copilot model=claude-opus-4-6 copilot=1.0.88

…ipts

validate-architectures.mjs, validate-community-groups.mjs,
validate-members.mjs, and validate-projects-born.mjs each carried an
independent copy of the same per-entry Set-based dedup check (track seen
values, push an error on repeat), differing only in variable names and
the error message.

validate-case-studies.mjs, validate-radar-reports.mjs,
validate-metrics.mjs, and validate-launch-metrics.mjs already centralize
their own variant of this through checkDuplicateOrMissingId() in
scripts/lib/validate-utils.mjs, but that helper also treats a falsy value
as an error on its own. The four scripts here already run a separate
presence check on the same field (checkNonEmptyString() or an inline
check), so reusing checkDuplicateOrMissingId() as-is would double-report
a single missing entry as both missing and duplicate.

Adds checkDuplicateValue() to a new scripts/lib/duplicate-check.mjs,
a dedup-only check that never inspects the value for presence, and
migrates the four call sites to it, preserving each file's existing
guard structure so behavior for every case (unconditional, slug-style,
and typeof-guarded) is unchanged.

Kept out of scripts/lib/validate-utils.mjs and its test file: both are
under active review in PR #1761.

Signed-off-by: architect <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@netlify

netlify Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for endusers ready!

Name Link
🔨 Latest commit 307a45c
🔍 Latest deploy log https://app.netlify.com/projects/endusers/deploys/6ad9bc6795caafa7210c2654
😎 Deploy Preview https://deploy-preview-1767--endusers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

Important

Held for human review by the hive's ACMM level gate.

This PR was opened by the "architect" agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an outreach PR that targets a repository this hive does not manage is held at every level because it publishes project-facing communication into someone else's project.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified correct — behavior-preserving extraction, and the trickiest call sites were migrated carefully.

Read at head 307a45c against base, not just the diff:

  • scripts/lib/duplicate-check.mjs:30-47: check-then-add, unconditional seen.add(value), error pushed only on repeat — semantically identical to all four inlined originals.
  • The two non-trivial migrations preserve a subtle base behavior exactly. At base, scripts/validate-members.mjs ran ids.add(member?.id) unconditionally, so a second non-string id would still enter the set (silently, no error). The PR's else { ids.add(member?.id); } branch (scripts/validate-members.mjs:153-157) keeps that, rather than "simplifying" it away — same pattern in scripts/validate-projects-born.mjs:57-61 for name. This is the spot where a careless refactor would have changed behavior; it didn't.
  • validate-architectures.mjs:70 keeps the unconditional check (base had no guard), and validate-community-groups.mjs:52-54 keeps the if (group.slug) guard. Guard structure unchanged in all four.
  • The rationale for a new module instead of extending validate-utils.mjs checks out: checkDuplicateOrMissingId() there also flags falsy values, which would double-report alongside the existing presence checks, and tests/coverage-report-cli.test.mjs pins validate-utils.mjs coverage to its own test file.
  • Ran node --test tests/duplicate-check.test.mjs tests/validate-community-groups.test.mjs at head: all pass, including the falsy-value non-inspection tests. (The validate-architectures suite needs installed node_modules I didn't have locally; CI's Validate/Mutation/coverage jobs are all green on this head.)

Looks correct to me. Hold-gated per policy, so a maintainer still needs to sign off, but I found nothing blocking.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88

@mrbobbytables

Copy link
Copy Markdown
Member

Maintainer-delegated P3 disposition: reviewed exact head 307a45c. The helper performs duplicate detection only and always records the value. The four migrated callers preserve unconditional, truthy-slug and string-only duplicate guards, existing missing-value diagnostics and error ordering; non-string id/name values are still recorded as before. Helper cases cover new, repeated, missing/falsy and caller-message behavior. Required CI, scoped mutation check, lint and browser checks are green. The maintainer approved this designated P3 merge and dependent issue1774 follow-up, which must reuse this helper only after it lands. Agent inspection is not independent human approval. Releasing only this hold and queueing the exact head through protections, with no bypass.

@mrbobbytables
mrbobbytables added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit da94282 Oct 22, 2026
14 checks passed
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.

[architect] Four validator scripts duplicate the same per-entry dedup check instead of a shared helper

1 participant