Skip to content

petry-projects/.github has no duplicate-decl-gate — the #1485 corruption class just recurred unguarded in PR #1024 and left apply-repo-settings.sh unparseable #1025

Closed

Description

@don-petry

Problem

petry-projects/.github-private has a required duplicate-decl-gate check — added by #1520 after the #1485 trunk-corruption incident, and again after PR #1378 re-corrupted trunk on 2026-08-14. petry-projects/.github has no equivalent workflow, and its branch ruleset requires only:

SonarCloud · CodeQL · agent-shield / AgentShield · dependency-audit / Detect ecosystems

So the guard built specifically to block this corruption class protects one org-infra repo and not the other.

It just recurred, in the unguarded repo

PR #1024 (implementing #1023) reached review with duplicated content and nothing blocked it:

DUP scripts/canary-rollout.sh      2× _watched_paths()
DUP scripts/compliance-audit.sh    3× ensure_required_labels()
AGENTS.md: 23 top-level headings vs 12 on main

Intended scope was ~4 files; the PR is 15 files, +2054/-30, with the excess appearing as pure +X/-0 additions across unrelated files (AGENTS.md +611, standards/ci-standards.md +318, standards/canary-rings.json +315, scripts/compliance-audit.sh +62, …).

It also left scripts/apply-repo-settings.sh unparseable — a duplicated source-guard block produced an unmatched brace:

$ bash -n scripts/apply-repo-settings.sh
line 498: syntax error near unexpected token `}'

That script drives the fleet-wide apply-repo-settings workflow, so merging it would have broken repo-settings self-heal everywhere — the very capability #984/#985 just delivered.

What did catch it: the manual duplicate-declaration sweep (the standing session-start habit), plus CodeRabbit independently flagging the brace as 🔴 Critical. Neither is a merge gate in this repo. Existing lint checks did not catch the duplication — ShellCheck and Lint and bats failed for other reasons, and a duplicated-but-valid function definition is not a shellcheck error at all.

Why this matters more than one bad PR

#1520's own rationale was that two green-checked corruptions proved advisory detection is insufficient — hence a required gate. That reasoning applies identically to .github, which hosts the reusables the whole fleet pins: apply-repo-settings, agent-shield, dependency-audit, auto-rebase, add-to-project, canary-rollout, and the standards themselves. A corrupted reusable there propagates to every consumer on the next channel promotion.

Acceptance criteria

  • Port the duplicate-decl-gate workflow from petry-projects/.github-private to petry-projects/.github (same detection: a top-level declaration appearing more than once in a shell file).
  • Add it to .github's branch ruleset as a required status check, matching .github-private.
  • Extend detection beyond scripts/*.sh where cheap — the AGENTS.md duplication (23 vs 12 top-level headings) would not be caught by a shell-only sweep, and markdown/JSON standards files are equally load-bearing here.
  • Test: a PR that duplicates a function declaration fails the gate; a clean PR passes.
  • Audit .github's current main for pre-existing duplication that landed while unguarded — the gate only prevents new cases.
  • Confirm no other org-infra repo hosting reusables lacks the gate.

Related: #1485 (original corruption), #1520 (the gate, private repo), PR #1378 (second corruption), PR #1024 (this recurrence), petry-projects/.github#1023.

Activity

  1. don-petry commented on Aug 31, 2026

    @don-petry
    ContributorAuthor

    Dev-Lead Implementation Plan

    Issue: #1025 — port the duplicate-decl-gate from .github-private to .github

    Scope

    Port the required duplicate-decl-gate CI check (top-level duplicate-declaration detector for the #1485 corruption class) into petry-projects/.github, extend detection cheaply to markdown top-level headings and JSON keys, and codify the required status check as a targeted ruleset scoped to the reusable-hosting meta-repos (matching the release-channel-tags precedent) so it does not brick fleet repos that lack the workflow.

    Implementation Checklist

    • scripts/check-duplicate-decls.sh — pure, self-contained detector. Shell: duplicate top-level function declarations (detection logic identical to .github-private's conflict-integrity.sh). Markdown: duplicate top-level (H1/H2) headings, fence-aware. JSON: duplicate keys / parse failure. Excludes node_modules, .git, test, tests, .dev-lead.
    • .github/workflows/duplicate-decl-gate.yml — required gate. Runs on every PR (no paths filter, so the required check always reports) + push to main. Pinned checkout, permissions: contents: read.
    • .github/workflows/duplicate-decl-gate-tests.yml — shellcheck + bats runner (path-filtered), matching the repo's *-tests.yml convention.
    • standards/rulesets/duplicate-decl-gate.json — targeted branch ruleset adding {"context": "duplicate-decl-gate"} as a required status check on ~DEFAULT_BRANCH, bypass actors matching code-quality. Applied by name to the meta-repos only (not in FLEET_RULESETS).
    • standards/rulesets/README.md — document the new targeted ruleset (table + scope boundary).

    Tests to Write

    • test/scripts/duplicate-decl-gate/duplicate-decl-gate.bats:
      • repo's own tree is clean (green) — the audit guard
      • fails + names the function on a duplicated top-level shell function (single-line and multiline name()\n{ syntax)
      • duplicated top-level VAR alone does not fail (functions only)
      • fails on a duplicated top-level markdown heading; ignores duplicate #-comments inside code fences; ignores duplicate sub-headings (H3+)
      • fails on duplicate JSON keys and on unparseable JSON; clean JSON passes
      • scans nested subdirectories; excluded dirs (tests/fixtures) are skipped

    Test Command

    bats --print-output-on-failure test/scripts/duplicate-decl-gate/ and bash .dev-lead/scripts/dev-lead-lint.sh

    Audit result (AC: audit main)

    Ran the detector's logic against current main under the ship scope: shell function dups — clean; markdown top-level headings — clean; JSON keys — clean. No pre-existing corruption to remediate.

  2. don-petry commented on Aug 31, 2026

    @don-petry
    ContributorAuthor

    Dev-Lead: Implementation Complete

    Ported the duplicate-decl-gate from petry-projects/.github-private into this repo, extended detection to markdown/JSON, codified the required status check, and audited main. All acceptance criteria addressed.

    Plan Execution

    • scripts/check-duplicate-decls.sh — pure, self-contained detector. Shell dup detection is byte-identical to .github-private's conflict-integrity.sh awk (extract_top_level_symbols, fn arms). Markdown: fence-aware duplicate top-level (H1/H2) heading detection. JSON: duplicate object keys + unparseable-file detection (fail loud). Excludes .git, node_modules, test, tests, .dev-lead.
    • .github/workflows/duplicate-decl-gate.yml — required gate; runs on every PR (no paths filter, so the required check always reports) + push to main; pinned checkout, permissions: contents: read.
    • .github/workflows/duplicate-decl-gate-tests.yml — shellcheck + bats runner, path-filtered (matches the repo's *-tests.yml convention).
    • standards/rulesets/duplicate-decl-gate.json — targeted branch ruleset adding required context duplicate-decl-gate, bypass actors matching code-quality. Scoped to the reusable-hosting meta-repos only (not in FLEET_RULESETS), mirroring the release-channel-tags precedent, so fleet repos lacking the workflow are not bricked.
    • standards/rulesets/README.md — documented the new targeted ruleset (table row + scope-boundary + apply commands).
    • test/scripts/duplicate-decl-gate/duplicate-decl-gate.bats — 17 tests.

    Acceptance criteria

    • Port the gate (same shell detection): ✅ awk copied verbatim from the private lib.
    • Required status check matching .github-private: ✅ codified as standards/rulesets/duplicate-decl-gate.json (context duplicate-decl-gate). The applier (apply-rulesets.sh) needs no code change — a targeted ruleset is applied by name. Maintainer action (outside this PR's scope — I hold no admin token and don't touch live settings): GH_TOKEN=<admin> bash scripts/apply-rulesets.sh --repo petry-projects/.github duplicate-decl-gate. Verified via the compliance-audit bats that a repo carrying an extra required check beyond code-quality produces no drift finding (subset semantics), so this is compatible.
    • Extend beyond scripts/*.sh: ✅ markdown top-level headings + JSON keys (the AGENTS.md 23-vs-12 and unparseable-file signatures from PR feat: implement issue #1023 — canary autocut: scope bump signals to watched-path commits, paginate the range, and persist failed promotions #1024 would both fail).
    • Test dup fails / clean passes: ✅ 17 bats (shell single-line/multiline/function-keyword forms, markdown fence-awareness + sub-heading exemption, JSON dup-key + parse-failure, scope exclusions).
    • Audit main: ✅ clean on all three detectors — shell functions, markdown top-level headings, JSON keys. No pre-existing corruption to remediate.
    • No other reusable-hosting repo lacks the gate: ✅ only .github and .github-private host reusable workflows (checked all non-archived org repos); .github-private already carries the gate, .github now does.

    Test Results

    $ bats test/scripts/duplicate-decl-gate/
    1..17  — all ok (shell/markdown/JSON detection, scope exclusions, audit guard)
    
    $ bash scripts/check-duplicate-decls.sh          # the real CI invocation, over main
    duplicate-decl-gate: no duplicate top-level declarations under <repo root>
    
    $ bash .dev-lead/scripts/dev-lead-lint.sh        # shellcheck + CODEOWNERS
    [lint] all checks passed
    $ shellcheck --severity=warning -x scripts/check-duplicate-decls.sh   # clean
    
    # Regression guards over the surfaces this change touches — all green:
    $ bats test/scripts/apply-rulesets/              # 24 ok (fleet-allowlist unchanged)
    $ bats test/workflows/dependency-hardening.bats  # 4 ok (new workflows are hardened)
    $ bats test/scripts/compliance-audit/ruleset-{contents-drift,targeting}.bats  # all ok
    

    Files Changed

    • scripts/check-duplicate-decls.sh (new): the pure detector.
    • .github/workflows/duplicate-decl-gate.yml (new): the required gate.
    • .github/workflows/duplicate-decl-gate-tests.yml (new): the test runner.
    • standards/rulesets/duplicate-decl-gate.json (new): the codified required check (targeted).
    • standards/rulesets/README.md: documents the targeted ruleset.
    • test/scripts/duplicate-decl-gate/duplicate-decl-gate.bats (new): 17 tests.

    Notes

    • Scope choice: the private gate scans only scripts/; this one defaults to the repo root (minus excluded dirs) so it also covers AGENTS.md and standards/** per the AC. Intentional-duplicate fixtures under test//tests/ and vendored .dev-lead tooling are excluded so the gate never trips on its own fixtures.
    • JSON detection requires python3 (present on ubuntu-latest); if absent while JSON files exist, the gate exits 2 (fail-closed) rather than silently skipping.
    • Bypass actors on the ruleset match code-quality (OrganizationAdmin + the dependabot-automerge-petry app) for consistency; the gate still runs and passes on Dependabot PRs.
  3. added a commit that references this issue on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    automationAutomation improvements and gapsdev-leadFor dev-lead agent pickup

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions