Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,32 @@ jobs:
- name: Run audit-section-33-migration-xrefs (--enforce)
run: bun tools/hygiene/audit-section-33-migration-xrefs.ts --enforce

lint-backlog-id-uniqueness:
# Fail if any B-NNNN ID is claimed by more than one backlog row file.
# Cross-agent ID-allocation collisions (Otto-CLI vs Otto-Desktop on
# B-0444 2026-05-13; Lior vs Otto-CLI on B-0532+B-0533 2026-05-15) cost
# ~15 min coordination effort each at observed ~20% rate. The
# duplicate-ID detection logic was added to audit-backlog-items.ts
# 2026-05-14 (PR #3249, Copilot caught two files claiming B-0329 on
# PR #3247) but ran detect-only — this job is the CI gate that turns
Comment on lines +769 to +774
# codified-but-not-enforced into a control.
#
# B-0535 — sibling of lint-section-33-migration-xrefs + lint-archive-
# header-section33: catch-once-then-lint pattern at ID-allocation scope.
name: lint (backlog ID uniqueness)
timeout-minutes: 2
runs-on: ubuntu-24.04

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install toolchain via three-way-parity script (GOVERNANCE §24)
run: ./tools/setup/install.sh

- name: Run audit-backlog-items (--enforce-duplicate-ids)
run: bun tools/hygiene/audit-backlog-items.ts --enforce-duplicate-ids

lint-no-empty-dirs:
# Fail if a committed directory has no files — almost always a
# forgotten artefact (an agent-created skill folder without a
Expand Down
25 changes: 22 additions & 3 deletions tools/hygiene/audit-backlog-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@
// PR #3247; PR #3249 added this audit class).
//
// Usage:
// bun tools/hygiene/audit-backlog-items.ts
// bun tools/hygiene/audit-backlog-items.ts # detect-only
// bun tools/hygiene/audit-backlog-items.ts --enforce-duplicate-ids
// # exit non-zero on duplicate-ID groups (B-0535 CI gate)
//
// Exit codes:
// 0 -- survey ran (findings reported in body)
// 1 -- fatal invocation error (e.g., backlog dir missing)
// 0 -- survey ran (findings reported in body); detect-only mode
// 1 -- fatal invocation error (e.g., backlog dir missing) OR
// duplicate-ID groups found AND --enforce-duplicate-ids set

import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
Expand Down Expand Up @@ -601,6 +604,15 @@ async function main(): Promise<number> {
return 1;
}

const argv = process.argv.slice(2);
const enforceDuplicateIds = argv.includes("--enforce-duplicate-ids");
for (const arg of argv) {
if (arg !== "--enforce-duplicate-ids") {
process.stderr.write(`error: unknown argument: ${arg}\n`);
return 1;
}
}

const today = nowIso();
const nowEpoch = Math.floor(Date.now() / 1000);

Expand Down Expand Up @@ -652,6 +664,13 @@ async function main(): Promise<number> {
);
console.log(" (typed-edge backlog graph).");

if (enforceDuplicateIds && duplicateIdGroups > 0) {
process.stderr.write(
`\nerror: ${duplicateIdGroups} duplicate-ID group(s) found; --enforce-duplicate-ids set (B-0535 gate)\n`,
);
return 1;
}

return 0;
}

Expand Down
Loading