From 7f3531ac4c0f25960e929598ecd1afeafe7d881e Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Fri, 13 Feb 2026 12:22:54 -0500 Subject: [PATCH] docs(agents): add claim audit utility for scheduler exclusions --- docs/agents/prompts/META_PROMPTS.md | 50 ++--- docs/agents/prompts/daily-scheduler.md | 30 +-- docs/agents/prompts/weekly-scheduler.md | 30 +-- scripts/agents/claim-audit.mjs | 259 ++++++++++++++++++++++++ 4 files changed, 311 insertions(+), 58 deletions(-) create mode 100755 scripts/agents/claim-audit.mjs diff --git a/docs/agents/prompts/META_PROMPTS.md b/docs/agents/prompts/META_PROMPTS.md index 78b9f44a..9d550c5d 100644 --- a/docs/agents/prompts/META_PROMPTS.md +++ b/docs/agents/prompts/META_PROMPTS.md @@ -31,24 +31,21 @@ COMMAND 2 — Check for in-progress task logs: ls docs/agents/task-logs/daily/ | sort -Run both commands and PASTE THE COMPLETE RAW OUTPUT of each command into your -response. Do not summarize. Do not paraphrase. Paste the actual terminal output. -If a command returns nothing, write: "OUTPUT: (empty — no results)" +COMMAND 3 — Run claim audit utility (authoritative exclusion source): -STOP HERE. Do not proceed until both outputs are pasted. + node scripts/agents/claim-audit.mjs --cadence daily ---- +Paste the full raw output, including the JSON block between +`JSON_OUTPUT_START` and `JSON_OUTPUT_END`. -Now analyze the output: -- Any PR that maps to a daily-cadence agent is EXCLUDED (branch parsing first, title fallback second). -- If any PR agent cannot be derived from metadata, treat as GLOBAL LOCK warning and do not schedule this cadence. -- Any agent with a "_started.md" log file that has no matching "_completed.md" - or "_failed.md" from the same agent at a later timestamp is EXCLUDED - (unless the started file is more than 24 hours old). -- Write your exclusion list. Format: "EXCLUDED AGENTS: agent-a, agent-b" - or "EXCLUDED AGENTS: (none)" +Use script output exactly: +- `excludedAgents` is the exclusion list. +- `globalLockWarning=true` means cadence is locked. +- `exclusionListResolved=false` means stop immediately (fail-closed). ---- +If COMMAND 3 fails (non-zero exit, missing script, malformed JSON, network error), +do not execute any task. Mark scheduler run failed with summary: +`Claim audit unavailable; exclusion list unresolved`. Now proceed with the scheduler: @@ -111,24 +108,21 @@ COMMAND 2 — Check for in-progress task logs: ls docs/agents/task-logs/weekly/ | sort -Run both commands and PASTE THE COMPLETE RAW OUTPUT of each command into your -response. Do not summarize. Do not paraphrase. Paste the actual terminal output. -If a command returns nothing, write: "OUTPUT: (empty — no results)" +COMMAND 3 — Run claim audit utility (authoritative exclusion source): -STOP HERE. Do not proceed until both outputs are pasted. + node scripts/agents/claim-audit.mjs --cadence weekly ---- +Paste the full raw output, including the JSON block between +`JSON_OUTPUT_START` and `JSON_OUTPUT_END`. -Now analyze the output: -- Any PR that maps to a weekly-cadence agent is EXCLUDED (branch parsing first, title fallback second). -- If any PR agent cannot be derived from metadata, treat as GLOBAL LOCK warning and do not schedule this cadence. -- Any agent with a "_started.md" log file that has no matching "_completed.md" - or "_failed.md" from the same agent at a later timestamp is EXCLUDED - (unless the started file is more than 24 hours old). -- Write your exclusion list. Format: "EXCLUDED AGENTS: agent-a, agent-b" - or "EXCLUDED AGENTS: (none)" +Use script output exactly: +- `excludedAgents` is the exclusion list. +- `globalLockWarning=true` means cadence is locked. +- `exclusionListResolved=false` means stop immediately (fail-closed). ---- +If COMMAND 3 fails (non-zero exit, missing script, malformed JSON, network error), +do not execute any task. Mark scheduler run failed with summary: +`Claim audit unavailable; exclusion list unresolved`. Now proceed with the scheduler: diff --git a/docs/agents/prompts/daily-scheduler.md b/docs/agents/prompts/daily-scheduler.md index 583a697d..9fc1535a 100644 --- a/docs/agents/prompts/daily-scheduler.md +++ b/docs/agents/prompts/daily-scheduler.md @@ -104,25 +104,25 @@ ls docs/agents/task-logs/daily/ | sort Look for any `_started.md` files that do NOT have a corresponding `_completed.md` or `_failed.md` file from the same agent at a later timestamp. Those agents are **OFF LIMITS** (unless the started file is more than 24 hours old — check the date in the filename). -### Build your exclusion list +### COMMAND 3 — Run claim audit (authoritative exclusion source) -Combine results from Commands 1 and 2: -- Agents with open/draft PRs → EXCLUDED -- PRs whose agent cannot be derived from metadata → GLOBAL LOCK (stop scheduling this cadence) -- Agents with `started` status less than 24 hours old (no matching `completed`/`failed`) → EXCLUDED - -Write your exclusion list explicitly: -``` -EXCLUDED AGENTS: agent-a, agent-b -``` -or: -``` -EXCLUDED AGENTS: (none) +Run this command: +```bash +node scripts/agents/claim-audit.mjs --cadence daily ``` -**If Command 1 failed** (network error, API rate limit, `curl`/`jq` unavailable): you MUST still check the task log directory (Command 2). Log a warning in your summary that PR-based claim checking was unavailable. +**Paste the complete raw output.** This script is now the authoritative source for exclusions. -**Do not proceed to Step 1 until you have pasted command outputs and written your exclusion list.** +Use the script output exactly: +- `excludedAgents` (JSON field) is the only valid exclusion list. +- If `globalLockWarning` is `true`, treat cadence as locked. +- If `exclusionListResolved` is `false`, stop immediately (fail-closed). + +Do not manually rebuild or edit the exclusion list after the script runs. + +**Fail-closed fallback:** If Command 3 fails for any reason (non-zero exit, missing script, malformed JSON, network error), do not execute any daily task. Create a `failed` scheduler log entry with summary: `Claim audit unavailable; exclusion list unresolved`. + +**Do not proceed to Step 1 until you have pasted outputs for Commands 1, 2, and 3 and confirmed exclusion resolution.** --- diff --git a/docs/agents/prompts/weekly-scheduler.md b/docs/agents/prompts/weekly-scheduler.md index ac0f5a83..0c7281b6 100644 --- a/docs/agents/prompts/weekly-scheduler.md +++ b/docs/agents/prompts/weekly-scheduler.md @@ -104,25 +104,25 @@ ls docs/agents/task-logs/weekly/ | sort Look for any `_started.md` files that do NOT have a corresponding `_completed.md` or `_failed.md` file from the same agent at a later timestamp. Those agents are **OFF LIMITS** (unless the started file is more than 24 hours old — check the date in the filename). -### Build your exclusion list +### COMMAND 3 — Run claim audit (authoritative exclusion source) -Combine results from Commands 1 and 2: -- Agents with open/draft PRs → EXCLUDED -- PRs whose agent cannot be derived from metadata → GLOBAL LOCK (stop scheduling this cadence) -- Agents with `started` status less than 24 hours old (no matching `completed`/`failed`) → EXCLUDED - -Write your exclusion list explicitly: -``` -EXCLUDED AGENTS: agent-a, agent-b -``` -or: -``` -EXCLUDED AGENTS: (none) +Run this command: +```bash +node scripts/agents/claim-audit.mjs --cadence weekly ``` -**If Command 1 failed** (network error, API rate limit, `curl`/`jq` unavailable): you MUST still check the task log directory (Command 2). Log a warning in your summary that PR-based claim checking was unavailable. +**Paste the complete raw output.** This script is now the authoritative source for exclusions. -**Do not proceed to Step 1 until you have pasted command outputs and written your exclusion list.** +Use the script output exactly: +- `excludedAgents` (JSON field) is the only valid exclusion list. +- If `globalLockWarning` is `true`, treat cadence as locked. +- If `exclusionListResolved` is `false`, stop immediately (fail-closed). + +Do not manually rebuild or edit the exclusion list after the script runs. + +**Fail-closed fallback:** If Command 3 fails for any reason (non-zero exit, missing script, malformed JSON, network error), do not execute any weekly task. Create a `failed` scheduler log entry with summary: `Claim audit unavailable; exclusion list unresolved`. + +**Do not proceed to Step 1 until you have pasted outputs for Commands 1, 2, and 3 and confirmed exclusion resolution.** --- diff --git a/scripts/agents/claim-audit.mjs b/scripts/agents/claim-audit.mjs new file mode 100755 index 00000000..c18c73a1 --- /dev/null +++ b/scripts/agents/claim-audit.mjs @@ -0,0 +1,259 @@ +#!/usr/bin/env node + +import { readdir } from 'node:fs/promises'; +import { join } from 'node:path'; +import { execFile as execFileCb } from 'node:child_process'; +import { promisify } from 'node:util'; + +const VALID_CADENCES = new Set(['daily', 'weekly']); +const DAY_MS = 24 * 60 * 60 * 1000; + +function parseArgs(argv) { + const args = { cadence: null }; + for (let i = 0; i < argv.length; i += 1) { + const value = argv[i]; + if (value === '--cadence' || value === '-c') { + args.cadence = argv[i + 1] ?? null; + i += 1; + continue; + } + if (value.startsWith('--cadence=')) { + args.cadence = value.split('=')[1] ?? null; + } + } + return args; +} + + +function isClaimCandidate(pr, cadence) { + const headRef = String(pr?.head?.ref ?? '').toLowerCase(); + const title = String(pr?.title ?? '').toLowerCase(); + + const branchHints = [ + `agents/${cadence}/`, + `${cadence}/`, + `agent/${cadence}/`, + ]; + if (branchHints.some((hint) => headRef.includes(hint))) { + return true; + } + + if (title.includes(cadence) && title.includes('-agent')) { + return true; + } + + return false; +} + +function deriveAgentFromPr(pr, cadence) { + const headRef = String(pr?.head?.ref ?? ''); + const title = String(pr?.title ?? ''); + const branchMatcher = new RegExp(`^agents/${cadence}/(?[^/]+)/`); + const branchMatch = headRef.match(branchMatcher); + if (branchMatch?.groups?.agent) { + return { agent: branchMatch.groups.agent, source: 'branch' }; + } + + const legacyBranchMatcher = new RegExp(`^(?:agent/)?${cadence}/(?[^/]+)$`); + const legacyMatch = headRef.match(legacyBranchMatcher); + if (legacyMatch?.groups?.tail) { + const tail = legacyMatch.groups.tail; + const agentMatch = tail.match(/^(?(?:[A-Za-z0-9-]+-agent|docs-code-investigator))(?:[-_/].*)?$/); + if (agentMatch?.groups?.agent) { + return { agent: agentMatch.groups.agent, source: 'branch-legacy' }; + } + } + + const titleMatch = title.match(/(?[A-Za-z0-9-]+-agent|docs-code-investigator)/); + if (titleMatch?.groups?.agent) { + return { agent: titleMatch.groups.agent, source: 'title' }; + } + + return { agent: null, source: 'none' }; +} + +function parseTaskLogFilename(fileName) { + const match = fileName.match( + /^(?\d{4}-\d{2}-\d{2})_(?