Skip to content

feat: hardened Google Jules and Cursor automation control plane - #27

Merged
yansigit merged 4 commits into
devfrom
codex/agent-maintenance-hardening
Aug 25, 2026
Merged

feat: hardened Google Jules and Cursor automation control plane#27
yansigit merged 4 commits into
devfrom
codex/agent-maintenance-hardening

Conversation

@yansigit

Copy link
Copy Markdown
Owner

Summary

Adds a hardened, GitHub-native automation control plane coordinating Google Jules, Cursor Cloud Agent, and Cursor Bugbot:

  • Google Jules Dispatcher & Reconciler: Trusted workflow () and tested helper () for issue implementation () and plan requests () targeting fork .
  • Exact-Head Bugbot Review: Extended PR gating () requiring exact-app and exact-head completed success from Cursor Bugbot, blocking stale/neutral/spoofed checks, with a two-maintainer exact-head waiver ().
  • Bounded Repair Loop: Automated repair digest capped at 10 findings / 12 KB, filtering resolved threads and allowing up to 2 repair cycles before escalating to .
  • Security Boundaries: Default-branch execution guards on , integration-branch filters on , immutable App ID and user ID verification, and immediate escalation on protected surface expansion.
  • Repository Maintenance & Rules: Root rules, fork-targeted , and documentation in .

Verification

  • ▶ agent maintenance workflow
    ✔ uses trusted events, reconciliation, and curated schedules (0.527333ms)
    ✔ checks out only trusted default-branch controller code (0.258ms)
    ✔ keeps dispatch bounded, idempotent, and permission gated (0.215792ms)
    ✔ reconciles exact-head reviews and enforces the repair ceiling (0.578125ms)
    ✔ agent maintenance workflow (2.087542ms)
    ▶ maintenance state marker
    ✔ round-trips v1 and fills fields omitted by an early v1 marker (0.953333ms)
    ✔ fails closed for corrupt or invalid state (2.620291ms)
    ✔ cannot terminate its hidden marker through vendor-controlled strings (0.306ms)
    ✔ maintenance state marker (4.437208ms)
    ▶ Cursor Bugbot evidence
    ✔ accepts only a successful exact-name, exact-app, exact-head check (0.393375ms)
    ✔ blocks pending, neutral, stale, and spoofed checks (0.091083ms)
    ✔ does not let an older success mask a newer neutral rerun (0.060042ms)
    ✔ accepts an outage waiver only after two current maintainers approve the exact head (0.177417ms)
    ✔ Cursor Bugbot evidence (0.910208ms)
    ▶ baseline CI evidence
    ✔ requires latest successful exact-head evidence for every configured check (0.128375ms)
    ✔ baseline CI evidence (0.201417ms)
    ▶ controller fail-closed helpers
    ✔ uses the latest labeled or unlabeled event for an active dispatch label (0.110667ms)
    ✔ rejects truncated or malformed GitHub changed-file lists (3.204ms)
    ✔ classifies every documented Jules state without leaving terminal states running (0.13075ms)
    ✔ counts only durable controller state toward the Jules concurrency ceiling (0.092167ms)
    ✔ accepts only Jules-authored fast-forward head movement (0.179209ms)
    ✔ controller fail-closed helpers (3.874083ms)
    ▶ repair findings
    ✔ keeps current-head immutable-author findings and enforces count and byte limits (0.451458ms)
    ✔ repair findings (0.489541ms)
    ▶ quota exhaustion
    ✔ escalates only after the same Jules 429 has lasted 24 hours (0.099333ms)
    ✔ quota exhaustion (0.132541ms)
    ▶ Jules API boundary
    ✔ builds a fork-main automatic-PR request with explicit plan approval (0.114ms)
    ✔ selects only the exact connected GitHub repository source (0.077166ms)
    ✔ retries reads but never blindly retries a create (19.154ms)
    ✔ honors an HTTP-date Retry-After on read-only retries (0.902208ms)
    ✔ fails closed without retrying terminal read or mutation statuses (1.795792ms)
    ✔ follows Jules pagination tokens (0.848959ms)
    ✔ recovers an uncertain create by exact deterministic title without duplicating (1.242167ms)
    ✔ reconciles ambiguous POST 5xx and successful responses with invalid JSON (0.890834ms)
    ✔ rejects an uncertain-create title match from another source (0.311667ms)
    ✔ polls the resource-name tail rather than the opaque session id (0.17425ms)
    ✔ validates that a session output names the live open fork-main PR (0.609459ms)
    ✔ Jules API boundary (26.430458ms)
    ✔ issue automation streams prompts through the digest-pinned Copilot CLI without tool access (2.843708ms)
    ✔ Copilot failures leave issue enforcement and triage retryable (1.06725ms)
    ▶ enforce-pr-target workflow
    ✔ uses pull_request_target without checking out PR head code (1.439083ms)
    ✔ grants contents:write so draft GraphQL mutations work with GITHUB_TOKEN (0.785167ms)
    ✔ fails the required check on a wrong base even if draft conversion fails (0.120541ms)
    ✔ allows main only on the public fork while upstream stays dev-only (0.27675ms)
    ✔ soft-fails ready-for-review restoration the same way (0.206958ms)
    ✔ listens for synchronize so rebase can clear ancestry failures (0.083667ms)
    ✔ uses label events for GUI waivers, hygiene sponsorship, and a trusted CodeRabbit status signal (0.187167ms)
    ✔ wakes from trusted Bugbot checks and revalidates exact-head evidence (0.126459ms)
    ✔ does not add review events that would break the trusted-base model (0.272292ms)
    ✔ queries review threads and feeds them to the findings claim check (0.166125ms)
    ✔ fails closed when review threads cannot be read (0.073834ms)
    ✔ writes exactly one consolidated comment via a single upsert helper (0.134125ms)
    ✔ manages the review-ready status label at the ready moment (0.089083ms)
    ✔ does not embed a literal CodeRabbit review command in the ready notice (0.086834ms)
    ✔ does not rewrite the gate comment when the rebuilt body is unchanged (0.08825ms)
    ✔ keeps CodeRabbit auto-review unfiltered so maintainer PRs are not starved (2.240167ms)
    ✔ migrates legacy two-comment PRs and deletes the old comments (1.356958ms)
    ✔ checks out scripts from the event-specific trusted boundary (never PR head) (1.542875ms)
    ✔ orders same-head CodeRabbit reviews deterministically without timestamps (0.1375ms)
    ✔ loads pr-quality via require from the checked-out scripts (0.060791ms)
    ✔ checks stacked bases via open PR heads before wrong_base enforcement (0.099375ms)
    ✔ strips stale WRONG BRANCH prefix on failure when base is corrected (0.072666ms)
    ✔ enforce-pr-target workflow (11.395333ms)
    ▶ fork auto-release decision
    ✔ dispatches an unused stable package version from green main CI (2.665583ms)
    ✔ skips non-workflow_run events (0.485125ms)
    ✔ skips another triggering workflow (1.25875ms)
    ✔ skips unsuccessful CI (0.173291ms)
    ✔ skips non-main branches (0.116166ms)
    ✔ skips a moved main branch (0.113833ms)
    ✔ skips another package (0.103417ms)
    ✔ skips prerelease versions (0.134417ms)
    ✔ skips versions already on npm (0.130291ms)
    ✔ rejects an empty SHA as malformed input (0.5175ms)
    ✔ rejects a missing package name as malformed input (0.161459ms)
    ✔ fork auto-release decision (6.981417ms)
    ▶ fork auto-release env CLI
    ✔ prints dispatch JSON from env vars without a node heredoc (62.433833ms)
    ✔ treats VERSION_ON_NPM as already published when set (50.352458ms)
    ✔ fork auto-release env CLI (112.944666ms)
    ▶ issue Codex sync did not complete. Fix the reported Codex config issue and retry. lidge-jun/opencodex#1672 regression
    ✔ rejects a reproduction that only echoes the generic final sync failure from Summary (9.325709ms)
    ✔ rejects ordered-list formatting when it only repeats Summary evidence (1.000125ms)
    ✔ normalizes identical multi-line ordered lists on both sides (0.465875ms)
    ✔ preserves numeric failure evidence inside fenced and indented code blocks (1.001417ms)
    ✔ keeps the same failure text valid when Reproduction adds an actionable command (3.313708ms)
    ✔ issue Codex sync did not complete. Fix the reported Codex config issue and retry. lidge-jun/opencodex#1672 regression (15.92675ms)
    ✔ accepts [Bug] Cursor Claude-family models fail via Claude Code path — needs v2.11+ paired trace lidge-jun/opencodex#1162-shaped bug evidence without literal Reproduction/Version/OS headings (10.688583ms)
    ✔ accepts emphasized Environment keys (2.126417ms)
    ✔ does not duplicate case-insensitive reproduction aliases (0.325666ms)
    ✔ does not treat vague alternative headings as actionable reproduction (0.463417ms)
    ✔ still rejects an unknown OpenCodex version from Environment (0.527166ms)
    ✔ still rejects missing OS metadata from Environment (0.195625ms)
    ▶ detectIssueKind
    ✔ detects new feature form without [Feature]: prefix (1.599459ms)
    ✔ detects legacy feature form with [Feature]: prefix (0.09675ms)
    ✔ detects new bug form without [Bug]: prefix (0.111916ms)
    ✔ detects legacy bug form with [Bug]: prefix (0.064459ms)
    ✔ detects provider compatibility form (0.230792ms)
    ✔ detects documentation form (0.087791ms)
    ✔ returns null for unrelated issue with manually applied enhancement label (0.059542ms)
    ✔ uses stored bot kind when headings are removed (0.086583ms)
    ✔ detectIssueKind (5.266667ms)
    ▶ validateIssue - feature
    ✔ keeps nested sub-headings and fenced heading text inside a section ([Bug]: issue-quality closes valid reports because extractSection stops at nested sub-headings lidge-jun/opencodex#541) (8.098ms)
    ✔ ignores markdown headings inside backtick and tilde fences when finding section boundaries ([Bug]: issue-quality closes valid reports because extractSection stops at nested sub-headings lidge-jun/opencodex#541) (0.39775ms)
    ✔ rejects issue [Feature]: Native OpenAI Chat Completions Proxy Endpoint (/v1/chat/completions) lidge-jun/opencodex#208-style duplicate content (0.67825ms)
    ✔ rejects an image-only goal section that hides repeated prose (It is hoped that the usage query will support time-based queries and statistics, as well as key-based queries and statistics lidge-jun/opencodex#1098) (2.538084ms)
    ✔ rejects a markdown-image-only goal section with repeated prose (It is hoped that the usage query will support time-based queries and statistics, as well as key-based queries and statistics lidge-jun/opencodex#1098) (0.505042ms)
    ✔ rejects a markdown image with bracketed alt text in the goal (It is hoped that the usage query will support time-based queries and statistics, as well as key-based queries and statistics lidge-jun/opencodex#1098) (0.362875ms)
    ✔ rejects a markdown image whose URL contains balanced parentheses (It is hoped that the usage query will support time-based queries and statistics, as well as key-based queries and statistics lidge-jun/opencodex#1098) (0.28125ms)
    ✔ preserves a goal section that mixes an image with real text (1.364458ms)
    ✔ treats image/media-only sections as empty via isMediaOnly (1.185083ms)
    ✔ accepts a concise but actionable feature (0.521416ms)
    ✔ rejects issue Change voice chat to different model lidge-jun/opencodex#401-style low-effort feature with placeholder example (0.70825ms)
    ✔ rejects feature reports with placeholder example variants (2.203958ms)
    ✔ reports blank example usage as missing, not placeholder (0.919625ms)
    ✔ accepts a valid legacy feature request without blocker/example headings (0.437459ms)
    ✔ accepts a detailed CJK submission (2.105917ms)
    ✔ rejects terse goal sections that only contain a keyword, digit, or punctuation (1.154833ms)
    ✔ rejects a single long non-CJK word as overly terse (2.4355ms)
    ✔ counts mixed-script CJK text without inflating non-CJK letter length (0.171334ms)
    ✔ rejects mixed-script CJK stubs that only inflate letter counts (0.787042ms)
    ✔ accepts sufficiently detailed goal sections (0.230958ms)
    ✔ accepts a 6-7 word goal when it includes concrete technical detail (0.53375ms)
    ✔ rejects a 6-7 word goal that lacks concrete technical detail (0.514667ms)
    ✔ treats only commands, errors, paths, or exact actions as actionable reproduction detail (4.06375ms)
    ✔ bounds long non-matching reproduction path tokens (9.651ms)
    ✔ rejects fenced placeholder-only examples (1.22725ms)
    ✔ accepts real fenced examples that merely mention N/A (0.393042ms)
    ✔ validateIssue - feature (44.3495ms)
    ▶ validateIssue - bug
    ✔ rejects an empty bug report (0.464416ms)
    ✔ rejects a bug with Summary filled but Reproduction empty (0.19575ms)
    ✔ rejects a bug whose Reproduction is only an ellipsis (Open Codex Error lidge-jun/opencodex#598) (0.136875ms)
    ✔ rejects a bug with Reproduction filled but Summary empty (0.132292ms)
    ✔ accepts a terse real crash report (1.092875ms)
    ✔ accepts a valid legacy bug report without version/OS headings (0.757708ms)
    ✔ accepts a legacy bug with No response in old optional env fields (0.848541ms)
    ✔ accepts a legacy bug with N/A-style placeholders in Version and Operating system (1.6705ms)
    ✔ rejects a new-form bug where env fields were actively cleared (0.581042ms)
    ✔ rejects unknown / don't-know Version values (Unexpected interruption continues to occur lidge-jun/opencodex#624) (2.827167ms)
    ✔ rejects issue Unexpected interruption continues to occur lidge-jun/opencodex#624-style low-effort new-form bug (12.483125ms)
    ✔ rejects a new-form bug with a usable Version but placeholder OS (8.4245ms)
    ✔ rejects a new-form bug when the Version heading was removed (13.806625ms)
    ✔ rejects a new-form bug when the Operating system heading was removed (5.18525ms)
    ✔ rejects a new-form bug whose Reproduction is only a vague phrase (0.516833ms)
    ✔ rejects a Dont work in VSCode Codex plugin lidge-jun/opencodex#977-shaped bug with product keywords but no actionable reproduction (5.63025ms)
    ✔ rejects unknown Operating system stand-ins on the new bug form (2.434208ms)
    ✔ validateIssue - bug (57.82975ms)
    ▶ validateIssue - provider-compatibility
    ✔ rejects when request and response are both absent (0.615084ms)
    ✔ accepts a complete provider compatibility report (1.077583ms)
    ✔ rejects provider compat report when provider/endpoint fields are cleared (2.870375ms)
    ✔ validateIssue - provider-compatibility (5.1205ms)
    ▶ validateIssue - documentation
    ✔ rejects an empty documentation report (0.127167ms)
    ✔ accepts a complete documentation correction (0.207708ms)
    ✔ validateIssue - documentation (0.384458ms)
    ▶ normalisation
    ✔ treats 'No response' as empty (0.244334ms)
    ✔ treats NA and not applicable as placeholders (0.12875ms)
    ✔ detects unusable Version stand-ins without treating them as generic placeholders (0.135666ms)
    ✔ does not treat sentences containing placeholder phrases as empty (0.810125ms)
    ✔ shares one placeholder matcher across clean, isPlaceholder, and isRawPlaceholder (0.142167ms)
    ✔ strips HTML comments (0.064834ms)
    ✔ normalises punctuation and capitalisation (0.1405ms)
    ✔ removes filler phrases (0.154ms)
    ✔ normalisation (2.113916ms)
    ▶ extractSection
    ✔ extracts content between headings (0.129417ms)
    ✔ returns null for missing sections (0.037792ms)
    ✔ extractSection (0.232542ms)
    ▶ shouldReopen
    ✔ allows reopen when timestamps and state match (0.091958ms)
    ✔ forbids reopen when timestamp differs (0.125042ms)
    ✔ forbids reopen when state reason differs (0.070792ms)
    ✔ forbids reopen when bot state is inactive (0.030958ms)
    ✔ returns false when issue is already open (0.024709ms)
    ✔ forbids reopen on maintainer override (0.021292ms)
    ✔ forbids reopen when a human closed the issue (closed_by is not the bot) (0.023291ms)
    ✔ allows reopen when the bot is the recorded closer (0.02625ms)
    ✔ shouldReopen (0.511ms)
    ▶ shouldEnforceClosure
    ✔ enforces when there is no bot state yet (0.038667ms)
    ✔ enforces while the bot still owns an active closure (0.020959ms)
    ✔ does not enforce after a maintainer override (0.020917ms)
    ✔ still enforces after a normal active:false without maintainer override (0.020042ms)
    ✔ shouldEnforceClosure (0.138333ms)
    ▶ translated feature headings and soft-pass
    ✔ accepts Goal / Problem + Expected behaviour as a valid feature (0.317666ms)
    ✔ soft-passes [Feature]: with rich custom headings outside the alias map (0.447583ms)
    ✔ soft-passes retitled feature reports that drop the [Feature]: prefix (0.091958ms)
    ✔ soft-passes retitled bug reports with substantial non-English structure (Claude Desktop 3P Auto Mode classifier retries after 64-token Anthropic OAuth outputs lidge-jun/opencodex#545) (0.309791ms)
    ✔ does not soft-pass a single arbitrary rich heading (Codex fix(ci): soft-pass detailed issues after maintainer retitle lidge-jun/opencodex#564) (0.089334ms)
    ✔ does not soft-pass provider reports that only fill mapped metadata headings (0.170084ms)
    ✔ still rejects empty [Feature]: bodies (0.161625ms)
    ✔ does not treat a title containing problem as a bug (0.037625ms)
    ✔ does not soft-pass long unstructured bodies without headings (0.039042ms)
    ✔ does not classify Expected behaviour + Example as feature without a feature hint (0.061042ms)
    ✔ classifies alias headings as feature when a goal heading is present (0.05675ms)
    ✔ lets a strong bug form override a stale stored feature kind (0.908458ms)
    ✔ accepts US spelling Expected behavior as a behaviour alias (0.370916ms)
    ✔ does not treat enhancement + non-goal aliases as a feature detect hit (0.121708ms)
    ✔ does not let a weak title-prefix detection override stored documentation kind (0.100167ms)
    ✔ translated feature headings and soft-pass (3.895666ms)
    ▶ labelForKind
    ✔ maps kinds to triage labels (0.096792ms)
    ✔ labelForKind (0.128042ms)
    ▶ validateIssue - freeform / non-template
    ✔ rejects a plain freeform body that previously skipped validation (0.265625ms)
    ✔ rejects a 499 client_closed_request errors during web-search tool usage lidge-jun/opencodex#521-shaped Description/Reproduction/Log entry body with a clear message (0.361292ms)
    ✔ still detects and validates a real structured bug as before (0.416625ms)
    ✔ does not treat Summary+Reproduction alone as a bug without prefix or label (0.327542ms)
    ✔ keeps label-backed storedKind validation for enhancement freeform (0.453792ms)
    ✔ validateIssue - freeform / non-template (2.263791ms)
    ▶ rejectsWorkflowDispatchPullRequest
    ✔ rejects pull request numbers on workflow_dispatch (0.111917ms)
    ✔ allows issues and non-dispatch events (0.05125ms)
    ✔ rejectsWorkflowDispatchPullRequest (0.224583ms)
    ▶ rejectsWorkflowDispatchNonDefaultBranch
    ✔ rejects workflow_dispatch runs that are not on the default branch (0.087458ms)
    ✔ allows default-branch dispatches and normal issue events (0.044791ms)
    ✔ rejectsWorkflowDispatchNonDefaultBranch (0.177375ms)
    ▶ mapAreaFieldToLabels
    ✔ maps canonical Area dropdown values (0.89925ms)
    ✔ maps legacy Service lifecycle wording and ignores Other / Multiple areas (0.606291ms)
    ✔ exposes metadata for every non-documentation area label (0.110333ms)
    ✔ mapAreaFieldToLabels (1.69575ms)
    ▶ detectAreaLabels
    ✔ applies Area mapping plus orthogonal heuristics (1.392333ms)
    ✔ adds provider for provider-compatibility form and label (0.957417ms)
    ✔ runs heuristics for Multiple areas / Other without inventing per-provider labels (0.362958ms)
    ✔ does not map Documentation Area onto the documentation kind label (1.292959ms)
    ✔ ignores Operating system metadata for platform heuristics (0.645375ms)
    ✔ uses heuristicBody translation text when Area is Other (1.757959ms)
    ✔ matches truncated streaming wording via truncat stem (0.307ms)
    ✔ detectAreaLabels (7.05275ms)
    ▶ clean() respects fenced code (regression)
    ✔ keeps section text that follows a comment-like literal in a fence (0.085209ms)
    ✔ still strips a real HTML comment outside code (0.03175ms)
    ✔ clean() respects fenced code (regression) (0.145792ms)
    ▶ code-region scanning is GFM-correct and linear (regression)
    ✔ honors a closing fence longer than its opener (0.045708ms)
    ✔ honors a code span containing a line ending (0.026709ms)
    ✔ stays linear on adversarial input (6.597417ms)
    ✔ code-region scanning is GFM-correct and linear (regression) (6.712833ms)
    ▶ hashTranslationSource
    ✔ changes when only the title changes (3.20375ms)
    ✔ changes when only the body changes (0.128875ms)
    ✔ is stable for unchanged title and body (0.082917ms)
    ✔ hashTranslationSource (4.202583ms)
    ▶ splitTranslationBlock
    ✔ handles generated block at end (0.4055ms)
    ✔ preserves suffix after generated block (0.102417ms)
    ✔ preserves prefix before generated block (0.059292ms)
    ✔ does not remove contributor-authored details elsewhere (0.0655ms)
    ✔ fails safely when closing details is missing (0.084875ms)
    ✔ preserves nested details inside translated content via end marker (0.090542ms)
    ✔ removes multi-level nested details only inside the generated block (0.102ms)
    ✔ migrates legacy blocks that close on first details end (0.097625ms)
    ✔ does not greedily erase across duplicate end markers (0.051458ms)
    ✔ splitTranslationBlock (1.258541ms)
    ▶ isPreparedSourceStillCurrent
    ✔ detects body changes between prepare and apply (0.08ms)
    ✔ detects title changes between prepare and apply (0.071458ms)
    ✔ allows apply when only generated translation changed (0.11775ms)
    ✔ isPreparedSourceStillCurrent (0.427041ms)
    ▶ bot-owned control state
    ✔ always includes visible bookkeeping, including English (1.618917ms)
    ✔ incomplete AI/parse failures bookkeep as unknown, never false-English (0.755458ms)
    ✔ English creates a bot comment with visible English bookkeeping (0.440916ms)
    ✔ English updates the canonical bot comment instead of creating duplicates (0.491625ms)
    ✔ updates the oldest sticky control comment even when its state is corrupt (0.673583ms)
    ✔ non-English persist writes or updates a visible bot-owned comment (0.407834ms)
    ✔ ignores author comments containing the control marker (0.216917ms)
    ✔ treats corrupt control state as missing (0.16125ms)
    ✔ never treats the issue body as authoritative control state (0.403375ms)
    ✔ failed sticky update preserves existing control comments and does not delete (1.260458ms)
    ✔ re-fetches comments when none are supplied and still verifies authorship (0.345041ms)
    ✔ failed comment update preserves the previous comment (0.290542ms)
    ✔ deletes redundant bot comments only after sticky replacement succeeds (0.159708ms)
    ✔ cleanup failure leaves valid fallback comments intact (0.175292ms)
    ✔ cooldown and hourly limits survive repeated issue events via bot comments (0.20075ms)
    ✔ rapid sequential edits cannot invoke the model repeatedly (0.107125ms)
    ✔ persistence never mutates the issue title or body (0.066334ms)
    ✔ selects only github-actions control comments (0.087833ms)
    ✔ reader and selector agree on the newest control comment (0.064334ms)
    ✔ round-trips base64url control state without HTML breakout (0.610709ms)
    ✔ rejects invalid decoded payloads (0.233ms)
    ✔ scrubs injection characters from detected language (0.14575ms)
    ✔ heals slightly-future prior within skew and uses wall-clock attemptedAt (0.208417ms)
    ✔ rejects far-future attemptedAt and strips far-future recent entries (0.147125ms)
    ✔ corrupt far-future comment does not outrank a valid current comment (0.724917ms)
    ✔ mergeTranslationAttemptState ignores poisoned far-future prior (0.065833ms)
    ✔ canonicalisation preserves valid bounded recent history across comments (0.083333ms)
    ✔ strips trailing obsolete markers without treating them as control state (0.046125ms)
    ✔ preserves author whitespace when stripping a trailing obsolete marker (0.057292ms)
    ✔ leaves marker-like author content inside fences, quotes, and prose untouched (0.033208ms)
    ✔ translation application preserves marker-like author content (0.0435ms)
    ✔ stale-source checking detects actual author edits after safe normalisation (0.487292ms)
    ✔ rate limits repeated non-ASCII detections (0.120333ms)
    ✔ defuses mention-shaped tokens without rewriting emails or mid-token at-signs (0.061625ms)
    ✔ ignores forged body-embedded legacy state (0.088125ms)
    ✔ deleteVerifiedControlComments skips author-forged marker comments (0.121208ms)
    ✔ bot-owned control state (11.903792ms)
    ▶ eligibility
    ✔ allows meaningful title with short body (0.0495ms)
    ✔ re-translates after title-only edits (0.044083ms)
    ✔ eligibility (0.133458ms)
    ▶ appendTranslationBlock
    ✔ replaces an existing generated block exactly once (0.05575ms)
    ✔ truncates translations that would exceed the issue body limit (0.153ms)
    ✔ appendTranslationBlock (0.260875ms)
    ▶ issue comment translation
    ✔ skips bots, control comments, and pull-request threads (0.15775ms)
    ✔ hashes comments under comment: so they do not collide with issue hashes (0.048916ms)
    ✔ allows a meaningful non-English comment and builds an in-place translation block (0.205166ms)
    ✔ rejects comments without a usable numeric id (0.057875ms)
    ✔ skips unchanged comment bodies via source hash (0.079458ms)
    ✔ keeps issue and comment completed hashes independent (0.084959ms)
    ✔ enforces minSourceChars on stripped comment body only (0.034666ms)
    ✔ short comments do not become eligible via comment: namespace padding (0.033792ms)
    ✔ stale-guards comment edits with isPreparedSourceStillCurrent (0.035125ms)
    ✔ issue comment translation (0.819417ms)
    ▶ missingRequiredTranslationFields
    ✔ requires translated title/body only when the matching source field is nonempty (0.067083ms)
    ✔ missingRequiredTranslationFields (0.0865ms)
    ▶ sourceComplete vs rate-limit attempts
    ✔ incomplete attempts count toward rate limits but stay retryable after cooldown (0.100542ms)
    ✔ completed no-translation and successful apply mark the source hash (0.064833ms)
    ✔ incomplete issue and comment attempts preserve a prior completed hash (0.106708ms)
    ✔ sourceComplete vs rate-limit attempts (0.314208ms)
    ▶ deterministic duplicate auto-close
    ✔ does not treat the generic Codex sync did not complete. Fix the reported Codex config issue and retry. lidge-jun/opencodex#1672 final sync message as duplicate proof (4.312708ms)
    ✔ selects an AI-nominated duplicate when both reports share an exact specific failure signature (0.803125ms)
    ✔ does not treat a semantic version as a structured field path (0.138334ms)
    ✔ still accepts an exact IPv4 address as a discriminator (0.103375ms)
    ✔ keeps case-distinct file paths distinct (0.159292ms)
    ✔ still matches a genuine structured field path (0.091875ms)
    ✔ recognizes fails as a strong failure signal (0.08125ms)
    ✔ recognizes short-prefix named error classes as specific duplicate evidence (0.0735ms)
    ✔ selects the longest shared signature across all nominated candidates (0.10625ms)
    ✔ preserves technical punctuation so distinct signatures cannot collapse together (0.097333ms)
    ✔ never selects the current issue as its own duplicate (0.070833ms)
    ✔ uses a locale-independent code-unit tie-breaker for equal-length signatures (0.077958ms)
    ✔ does not auto-close an AI duplicate without an exact strong failure signature (0.063209ms)
    ✔ ignores exact strong matches that the AI did not nominate as duplicates (0.043916ms)
    ✔ does not promote short generic HTTP failures to auto-close signatures (0.045417ms)
    ✔ workflow searches open and recently closed issues and closes only through duplicate state reason (0.356958ms)
    ✔ deterministic duplicate auto-close (8.540125ms)
    ▶ hasConcreteRelatedSignature
    ✔ rejects standalone ECONNRESET referring only to the new issue (0.951458ms)
    ✔ rejects shared route with different failures (0.651667ms)
    ✔ rejects same provider with different root causes (0.262208ms)
    ✔ does not treat ordinary e-words as error constants (0.573625ms)
    ✔ does not treat capitalized common words as errno tokens (0.381708ms)
    ✔ ignores bare three-digit numbers without status context (0.105708ms)
    ✔ rejects different HTTP statuses despite component overlap (0.079333ms)
    ✔ rejects distinct statuses even when the shared-comparison gate is open (0.058375ms)
    ✔ rejects shared wording that borrows a concrete token from only one issue (0.980958ms)
    ✔ rejects mixed HTTP and errno failures attributed to different issues (0.265083ms)
    ✔ rejects this/current/present issue attributions after generic both-wording (0.827416ms)
    ✔ keeps shared concrete failure signatures (0.345292ms)
    ✔ keeps shared errno plus shared comparison (0.124375ms)
    ✔ hasConcreteRelatedSignature (8.199167ms)
    ▶ hardenRelatedMatches
    ✔ drops 503 from /v1/responses via Codex even though direct proxy curl to same endpoint returns 200 OK (Xiaomi MiMo provider, openai-chat adapter) lidge-jun/opencodex#452-style weak related links to unrelated HTTP errors (0.607125ms)
    ✔ drops generic same-client / same-app overlap without a concrete signature (0.066042ms)
    ✔ keeps related when shared comparison has a concrete signature (0.118375ms)
    ✔ one valid related entry does not validate other weak entries (0.066042ms)
    ✔ each related entry requires its own concrete reason (0.050666ms)
    ✔ caps related at 3 and never overlaps duplicates (0.161291ms)
    ✔ hardenRelatedMatches (3.292875ms)
    ▶ parseTriageMatches
    ✔ returns null when hardening clears a weak related-only match (0.20825ms)
    ✔ keeps strong duplicates even if related is weak (0.083417ms)
    ✔ ignores unknown and self issue numbers (0.103292ms)
    ✔ ignores malformed related objects and legacy string related arrays (0.114291ms)
    ✔ prevents duplicate and related lists from overlapping (0.060541ms)
    ✔ caps related output at 3 (0.069792ms)
    ✔ parseTriageMatches (0.702959ms)
    ▶ parseAiJson
    ✔ strips a json fence before parsing (0.096416ms)
    ✔ returns null for unparseable input (0.088875ms)
    ✔ parseAiJson (0.2365ms)
    ▶ sanitizeReason
    ✔ strips markdown and mention markers (0.0725ms)
    ✔ sanitizeReason (0.123375ms)
    ▶ parseAiResponse
    ✔ parses plain JSON objects (0.752042ms)
    ✔ parses fenced JSON (0.137833ms)
    ✔ rejects invalid JSON, empty input, and arrays (0.102375ms)
    ✔ repairs JS-style apostrophe escapes that models put in JSON strings (0.078625ms)
    ✔ repairs apostrophe escapes inside a fenced code block (0.251334ms)
    ✔ preserves literal backslashes for non-apostrophe invalid escapes (0.118833ms)
    ✔ repairs invalid or truncated unicode escapes instead of keeping bare \u (1.1195ms)
    ✔ keeps requires_translation=true for issue and comment payloads with invalid escapes (88.231541ms)
    ✔ parseAiResponse (91.444084ms)
    ▶ parse-issue-translation-response process
    ✔ writes translated outputs for requires_translation=true (28.749958ms)
    ✔ writes English path without translation fields (28.795208ms)
    ✔ marks invalid JSON incomplete so sources stay retryable (87.426ms)
    ✔ leaves translate decisions incomplete until apply succeeds (27.34475ms)
    ✔ treats only boolean false as a completed no-translation decision (35.516ms)
    ✔ keeps invalid requires_translation values incomplete and retryable (244.259875ms)
    ✔ treats string requires_translation as incomplete, not English-complete (29.945208ms)
    ✔ supports multiline bodies and shell-looking content (28.778ms)
    ✔ writes false outputs on invalid JSON and empty responses (95.924958ms)
    ✔ parses fenced responses in the process path (31.716375ms)
    ✔ scrubs control characters from language and title (30.536334ms)
    ✔ parse-issue-translation-response process (669.391167ms)
    ▶ patch parsing
    ✔ returns added content without diff headers (1.466084ms)
    ✔ detects empty catch blocks across added lines (0.476208ms)
    ✔ keeps hunk context and added lines for result scanning (0.251208ms)
    ✔ patch parsing (3.447167ms)
    ▶ assessHygiene
    ✔ requires regression coverage for behavior changes (0.947334ms)
    ✔ accepts behavior changes with tests or approved exception (0.206042ms)
    ✔ does not read an empty catch across a hunk boundary (0.085ms)
    ✔ treats a deleted lockfile as no dependency change (0.098792ms)
    ✔ does not demand a test for a comment-only source change (0.177792ms)
    ✔ still demands a test when a comment change carries any code (0.6255ms)
    ✔ classifies renamed behavior files on both sides (0.471917ms)
    ✔ accepts a renamed behavior file when tests are included (1.157792ms)
    ✔ classifies renamed generated files on both sides (0.16575ms)
    ✔ blocks added suppressions (0.219125ms)
    ✔ blocks focused or skipped tests (0.183917ms)
    ✔ blocks empty catches (0.128667ms)
    ✔ detects a catch emptied by deletion (0.107125ms)
    ✔ does not flag a nonempty catch in a hunk with unrelated deletions (0.102209ms)
    ✔ blocks generated output and orphan lockfile churn (0.109209ms)
    ✔ allows removal of generated output (0.079625ms)
    ✔ does not count deleted tests as regression coverage (0.073542ms)
    ✔ allows maintainer-approved narrow exceptions (0.085041ms)
    ✔ assessHygiene (5.794583ms)
    ▶ collectDeterministicHygieneFailures
    ✔ combines patch hygiene and sponsored-surface failures (0.299291ms)
    ✔ skips sponsorship for maintainers with push permission (0.099792ms)
    ✔ requires sponsorship when renaming away from a restricted path (0.195625ms)
    ✔ exposes hints and gate labels for the Ready coupling (0.089292ms)
    ✔ collectDeterministicHygieneFailures (0.851875ms)
    ▶ pr-hygiene workflow trust boundary
    ✔ checks out trusted scripts from an integration branch, never a PR-controlled ref (0.538083ms)
    ✔ never lets a PR-controlled ref reach an executable step (0.831916ms)
    ✔ uses repository permission level for the sponsorship exemption (0.193959ms)
    ✔ pr-hygiene workflow trust boundary (1.681292ms)
    ▶ detectTypeLabelFromTitle
    ✔ maps conventional prefixes to type labels (1.004375ms)
    ✔ maps sentence-case prefixes when no conventional colon is present (0.329292ms)
    ✔ returns null without a recognized prefix (0.16125ms)
    ✔ detectTypeLabelFromTitle (2.30075ms)
    ▶ hasHumanTypeLabelOverride
    ✔ is false when only the Actions bot touched type labels (0.263417ms)
    ✔ is true after a human replaces the bot type label (PR fix(codex): warn or restart stale app-server after sync lidge-jun/opencodex#518) (0.198542ms)
    ✔ stays true even if the bot later reverts the human choice (0.149917ms)
    ✔ ignores non-type labels from humans (0.1355ms)
    ✔ hasHumanTypeLabelOverride (1.118875ms)
    ▶ planTypeLabelSync
    ✔ adds the detected label and removes other type labels when bot-owned (1.036666ms)
    ✔ is a no-op add when the detected label is already present (0.099917ms)
    ✔ skips when a human has overridden the type label (0.0945ms)
    ✔ labels sentence-case bug-fix titles (PR Fix Console Go tool schema sanitization lidge-jun/opencodex#524) (0.064041ms)
    ✔ skips titles without a recognized prefix (0.066291ms)
    ✔ planTypeLabelSync (1.548292ms)
    ▶ detectTypeLabelFromCommits
    ✔ reads the type from unanimous commits (0.582417ms)
    ✔ treats chore as supporting, not competing (PR stack 5/7: probe reset-derived cooldowns without waiting to be selected (#915) lidge-jun/opencodex#955 shape) (0.133459ms)
    ✔ keeps chore when nothing else competes (0.125167ms)
    ✔ abstains on a genuine mix of fix and feat (0.069791ms)
    ✔ reads only the first line of a multi-line commit message (0.068583ms)
    ✔ returns null for absent or unusable input (0.061333ms)
    ✔ detectTypeLabelFromCommits (1.193167ms)
    ▶ planTypeLabelSync commit fallback
    ✔ labels a stack PR whose title carries no type (0.149042ms)
    ✔ does not let commits override a title that already classifies (0.075ms)
    ✔ still skips when neither the title nor the commits classify (0.073667ms)
    ✔ still honours a human override before consulting commits (0.078125ms)
    ✔ planTypeLabelSync commit fallback (0.503583ms)
    ▶ pr-labeler workflow
    ✔ listens for labeled and unlabeled so human overrides cancel stale sync runs (0.289416ms)
    ✔ keeps trusted default-branch checkout, concurrency cancel, and minimal permissions (0.448125ms)
    ✔ pr-labeler workflow (0.82375ms)
    ▶ parseMaintainerLogins
    ✔ reads the current-maintainers table and excludes the change log (1.51ms)
    ✔ returns an empty list when the section heading is missing (0.296542ms)
    ✔ does not match a ### subsection or prose mentioning the heading (0.152584ms)
    ✔ accepts a valid CRLF heading with trailing whitespace and a following H2 (0.137375ms)
    ✔ handles empty and duplicate-free output (0.149708ms)
    ✔ parseMaintainerLogins (3.487458ms)
    ▶ inlineCode
    ✔ wraps values with a delimiter longer than any backtick run (0.609084ms)
    ✔ inlineCode (2.385625ms)
    ▶ readinessChecklistLines
    ✔ mirrors per-item checked state (0.425375ms)
    ✔ readinessChecklistLines (0.663125ms)
    ▶ buildGateCommentBody
    ✔ carries the marker, serialized state, status, mirror, and tick count (0.420375ms)
    ✔ renders a ready status without a checklist when not required (0.167292ms)
    ✔ does not claim ready when the PR is kept in draft (0.156625ms)
    ✔ buildGateCommentBody (0.972375ms)
    ▶ descriptionFailureLines
    ✔ covers every reason (0.214958ms)
    ✔ descriptionFailureLines (0.354083ms)
    ▶ buildFailureSections
    ✔ builds a wrong-base section naming every allowed base (0.329041ms)
    ✔ builds ancestry, description, and screenshot sections (0.190625ms)
    ✔ buildFailureSections (0.668667ms)
    ▶ failureSummary
    ✔ names every failure kind (0.129583ms)
    ✔ failureSummary (0.198709ms)
    ▶ buildStaleNotice
    ✔ names the recorded and current heads when a completion drifted (0.159125ms)
    ✔ covers the never-recorded predate case (0.042334ms)
    ✔ covers an unrecorded complete checklist on synchronize (0.038458ms)
    ✔ matches the injected section text it resets (0.05975ms)
    ✔ buildStaleNotice (0.35775ms)
    ▶ buildClaimCheckNotice
    ✔ names the latest-dev violation and the reset action (0.066375ms)
    ✔ ignores a stale ci_green code without inventing GitHub-CI copy (0.040917ms)
    ✔ returns only the reset line for an empty violation list (0.362917ms)
    ✔ buildClaimCheckNotice (0.510916ms)
    ▶ buildFindingsClaimNotice
    ✔ names each bot with unresolved threads and the untick (0.074875ms)
    ✔ handles a single bot with one thread (0.030458ms)
    ✔ buildFindingsClaimNotice (0.135625ms)
    ▶ hygiene section round-trip
    ✔ renders a hygiene block in the gate comment when requested (0.075041ms)
    ✔ extracts the hygiene content from a gate comment (0.1465ms)
    ✔ replaces an existing hygiene block without duplicating it (0.056583ms)
    ✔ appends a hygiene block when the gate comment has none (0.056709ms)
    ✔ ignores delimiter text embedded inside a hygiene content line (0.216666ms)
    ✔ preserves both sections across an interleaved gate rebuild and hygiene update (0.120833ms)
    ✔ hygiene section round-trip (0.782875ms)
    ▶ durable CodeRabbit outside-diff findings
    ✔ uses CodeRabbit's stable cr-comment markers as finding identities (1.196625ms)
    ✔ keeps standalone outside-diff findings active without an inline thread (0.238417ms)
    ✔ adds outside-diff markers without double-counting the review actionable total (0.164375ms)
    ✔ a later clean CodeRabbit review on the same head clears older markers (1.062917ms)
    ✔ uses review id as a deterministic tie-breaker when timestamps are missing (0.128875ms)
    ✔ ignores CodeRabbit markers from an older head and from human reviews (0.068292ms)
    ✔ deduplicates repeated markers in the review body (0.111083ms)
    ✔ durable CodeRabbit outside-diff findings (3.960708ms)
    ▶ enforcer state markers
    ✔ parses a valid enforcer state marker (1.9785ms)
    ✔ returns null for markerless or unreadable state and warns (0.584125ms)
    ✔ round-trips through stateMarker (0.130333ms)
    ✔ parses and serializes readiness state with warnings on failure (0.203292ms)
    ✔ enforcer state markers (3.980583ms)
    ▶ state defaults
    ✔ builds the cleared enforcer state (0.096792ms)
    ✔ builds the fresh active enforcer state (0.053417ms)
    ✔ builds the fresh readiness state at the current version (0.05725ms)
    ✔ state defaults (0.311208ms)
    ▶ completionIsStale
    ✔ is not stale when the recorded completion head matches the live head (0.911209ms)
    ✔ is stale when the recorded head differs from the live head, even with an open checklist (0.17125ms)
    ✔ is stale when ticks predate the live head on a first completion (0.16275ms)
    ✔ is not stale when ticks predate the live head but nothing is ticked (0.111875ms)
    ✔ is stale when a complete checklist has no recorded head on synchronize (0.086958ms)
    ✔ is not stale for an unrecorded complete checklist on a non-synchronize event (0.0685ms)
    ✔ is stale when the event delivered no head SHA at all (issue_comment rerun) (0.076ms)
    ✔ is not stale for maintainers or absent checklists (0.073916ms)
    ✔ completionIsStale (1.962916ms)
    ▶ readinessClaimViolations
    ✔ passes when the head is current enough (0.221084ms)
    ✔ never treats local CI as a bot-verifiable claim (0.109625ms)
    ✔ flags a head more than the threshold behind the base (0.081542ms)
    ✔ fails closed when the behind count is unknown (0.063666ms)
    ✔ honours a custom threshold (0.058333ms)
    ✔ readinessClaimViolations (0.693125ms)
    ▶ unresolvedFindingsClaim
    ✔ passes when there are no review threads at all (0.421541ms)
    ✔ passes when every bot thread is resolved (0.208208ms)
    ✔ flags one unresolved Codex thread and counts it per bot (0.207291ms)
    ✔ flags unresolved threads from both bots and counts each (0.173417ms)
    ✔ ignores unresolved threads from humans (0.080917ms)
    ✔ fails closed on a thread with no resolution state (0.0725ms)
    ✔ exposes the bot allowlist (0.055333ms)
    ✔ unresolvedFindingsClaim (1.409875ms)
    ▶ coderabbitOutsideDiffFindings
    ✔ flags a CodeRabbit review of the live head with actionable comments (0.1855ms)
    ✔ ignores a review of a different head (0.081042ms)
    ✔ ignores a review reporting zero actionable comments (0.073916ms)
    ✔ uses the most recent review of the live head (0.13825ms)
    ✔ returns clean for no reviews or no live head (0.116666ms)
    ✔ ignores a human review that quotes the actionable-comments line (0.076583ms)
    ✔ sorts undated reviews last deterministically (0.082125ms)
    ✔ coderabbitOutsideDiffFindings (0.908083ms)
    ▶ unresolvedFindingsClaim with outside-diff supplement
    ✔ does not count outside-diff when no unresolved bot thread exists (0.196584ms)
    ✔ adds the outside-diff count to an unresolved thread count (0.181583ms)
    ✔ keeps a resolved thread set clean even with a stale review (0.117167ms)
    ✔ unresolvedFindingsClaim with outside-diff supplement (0.645917ms)
    ▶ gate state
    ✔ round-trips through gateStateMarker and parseGateState (0.273959ms)
    ✔ returns null for markerless or unreadable gate state and warns (0.19325ms)
    ✔ builds a fresh gate state (0.103417ms)
    ✔ merges legacy enforcer + readiness states (0.15025ms)
    ✔ keeps enforcer-owned auto-draft when the readiness record says false (0.077875ms)
    ✔ migrates with either legacy state absent (0.070791ms)
    ✔ gate state (1.0665ms)
    ▶ isWrongAncestry
    ✔ flags fix(windows): follow active Codex home for tray listener lidge-jun/opencodex#644-shaped compares (0 behind main, far behind base, few ahead of main) (0.315542ms)
    ✔ uses threshold 20 by default (0.058875ms)
    ✔ passes when head is behind main (not sitting on main tip) (0.043541ms)
    ✔ passes stale dev-based branches that are many commits ahead of main (0.163583ms)
    ✔ isWrongAncestry (1.49125ms)
    ▶ authorHasPushPermission
    ✔ accepts write/maintain/admin only (0.245917ms)
    ✔ authorHasPushPermission (0.297541ms)
    ▶ assessPrDescription
    ✔ rejects empty and comment-only bodies (1.766958ms)
    ✔ rejects placeholder-only bodies (0.270792ms)
    ✔ rejects literal escaped newlines like fix(windows): follow active Codex home for tray listener lidge-jun/opencodex#644 (0.056459ms)
    ✔ rejects thin real-newline bodies (0.108291ms)
    ✔ rejects an untouched GitHub PR template as empty/thin (0.143875ms)
    ✔ accepts two rich markdown sections (0.235375ms)
    ✔ accepts unstructured bodies that are long enough with multiple blocks (0.142667ms)
    ✔ assessPrDescription (2.889209ms)
    ▶ hasGuiCue
    ✔ matches gui as a whole word, case-insensitively, in title or body (0.270291ms)
    ✔ does not match negated gui phrases (0.0415ms)
    ✔ does not match gui inside other words (0.034375ms)
    ✔ does not match missing or non-string inputs (0.027917ms)
    ✔ hasGuiCue (0.431625ms)
    ▶ guiPathsChanged
    ✔ matches gui/ paths with a slash guard (0.075875ms)
    ✔ guiPathsChanged (0.131959ms)
    ▶ isChangedFileListTruncated
    ✔ treats head drift, invalid counts, and oversized lists as truncated (0.125417ms)
    ✔ isChangedFileListTruncated (0.170833ms)
    ▶ hasGuiOverride
    ✔ matches a maintainer comment with a negation phrase (0.093209ms)
    ✔ does not let the PR author or a non-collaborator waive the gate (0.182541ms)
    ✔ does not match a comment that names gui without negating it (0.098042ms)
    ✔ does not match a negation that belongs to another sentence or line (0.082833ms)
    ✔ is clean for no comments or a comment without a body (0.071917ms)
    ✔ hasGuiOverride (0.704958ms)
    ▶ hasScreenshotEvidence
    ✔ accepts embedded markdown images (0.394166ms)
    ✔ accepts HTML img tags (0.09425ms)
    ✔ accepts reference-style images with a matching definition (0.178541ms)
    ✔ rejects image syntax inside fenced code and HTML comments (0.041625ms)
    ✔ rejects img tags without a renderable src and references without a definition (0.038ms)
    ✔ rejects plain links, bare image URLs, and text-only bodies (0.028167ms)
    ✔ hasScreenshotEvidence (0.872625ms)
    ▶ review readiness checklist
    ✔ builds exactly the four required boxes inside the markers (0.093167ms)
    ✔ keeps the closing 'ready for review' box separated by a blank line (0.041042ms)
    ✔ reports absent when the body has no markers (0.416458ms)
    ✔ counts checked boxes and requires all four for completion (0.151166ms)
    ✔ reports per-item state so the mirror marks the right boxes (0.046958ms)
    ✔ treats a reworded but complete section as complete (0.038625ms)
    ✔ stays incomplete for fewer or extra boxes inside the markers (0.047833ms)
    ✔ treats inverted or partial markers as present-but-incomplete, never appends again (0.075583ms)
    ✔ appends once and is idempotent (0.058167ms)
    ✔ appends cleanly to an empty body (0.03925ms)
    ✔ strips the marker-bounded section and leaves the rest intact (0.05225ms)
    ✔ strips a section-only body to empty and leaves markerless bodies alone (0.028084ms)
    ✔ resets every checked box to unticked and keeps the surrounding body (0.065083ms)
    ✔ resets a partially ticked section as well (0.035208ms)
    ✔ preserves the surrounding author formatting exactly (0.034083ms)
    ✔ is idempotent on an already-unticked section (0.033ms)
    ✔ leaves markerless and malformed bodies alone (0.027459ms)
    ✔ review readiness checklist (1.432541ms)
    ▶ uncheckReviewReadinessBoxes
    ✔ unchecks only the requested boxes (0.117583ms)
    ✔ can uncheck several boxes at once (0.037542ms)
    ✔ preserves the surrounding author content exactly (0.037583ms)
    ✔ is idempotent on an already-unchecked box (0.042125ms)
    ✔ leaves markerless and malformed bodies alone (0.428875ms)
    ✔ uncheckReviewReadinessBoxes (0.730625ms)
    ▶ assessPrDescription with the readiness section
    ✔ never counts the injected checklist as description substance (0.1685ms)
    ✔ assessPrDescription with the readiness section (0.195583ms)
    ▶ collectPrQualityFailures
    ✔ reports wrong_base without requiring ancestry inputs (0.187375ms)
    ✔ reports wrong_base and bad_description together for main + empty body (0.041541ms)
    ✔ reports wrong_ancestry for contributor on fix(windows): follow active Codex home for tray listener lidge-jun/opencodex#644-shaped compare (0.079542ms)
    ✔ skips ancestry for push permission but still flags bad description (0.034791ms)
    ✔ applies ancestry when permission lookup failed (fail closed) (0.061333ms)
    ✔ does not flag stale dev-based branches that are far ahead of main (0.05425ms)
    ✔ skips ancestry when compare lookup failed (cannot evaluate) (0.053417ms)
    ✔ skips wrong_base when stackedBase is set (0.050042ms)
    ✔ still flags wrong_base for non-allow-list bases without stackedBase (0.039958ms)
    ✔ flags gui/ file changes without a screenshot (0.069166ms)
    ✔ does not flag a gui title when no gui/ files changed (0.051ms)
    ✔ flags truncated file lists even when gui/ is not in the partial list (0.353958ms)
    ✔ flags truncated file lists when gui/ appears in the partial list (0.322875ms)
    ✔ does not flag no gui changes text without gui/ file changes (0.073208ms)
    ✔ flags a gui mention in the body without a screenshot when gui/ changed (0.305208ms)
    ✔ waives the screenshot gate for a maintainer override comment (0.064209ms)
    ✔ keeps the screenshot gate when only the PR author claims no gui change (0.046792ms)
    ✔ accepts a gui title when a screenshot image is embedded (0.108166ms)
    ✔ accepts a gui title when the screenshot uses reference-style markdown (0.173833ms)
    ✔ still flags gui/ changes when image syntax is only inside a code fence (0.155292ms)
    ✔ ignores the template's own gui/screenshot instruction (0.062834ms)
    ✔ collectPrQualityFailures (2.572458ms)
    ▶ comment stripping respects fenced code (regression)
    ✔ keeps a screenshot that follows a comment-like literal in a fence (0.034541ms)
    ✔ still ignores a screenshot inside a real HTML comment (0.022625ms)
    ✔ comment stripping respects fenced code (regression) (0.083ms)
    ▶ isRestrictedPath
    ✔ covers auth, workflow, release, and dependency surfaces (0.366625ms)
    ✔ leaves ordinary product surfaces alone (0.264083ms)
    ✔ isRestrictedPath (1.382625ms)
    ▶ isAgentProtectedPath
    ✔ escalates optional-Lab boundaries, provider code, and rename sources (0.135625ms)
    ✔ allows the two scheduled maintenance surfaces (0.90875ms)
    ✔ isAgentProtectedPath (1.183209ms)
    ▶ assessSponsoredSurface
    ✔ requires sponsorship for a restricted surface (1.240583ms)
    ✔ passes once a maintainer sponsors it (0.218875ms)
    ✔ exempts an author who can already push (0.154708ms)
    ✔ applies to every contributor, not only first-timers (0.138583ms)
    ✔ ignores a pull request that touches nothing restricted (0.179708ms)
    ✔ assessSponsoredSurface (2.223833ms)
    ▶ release dispatch guard
    ✔ accepts an exact audited SHA on main (0.400542ms)
    ✔ accepts an exact audited SHA on preview (0.114292ms)
    ✔ rejects non-workflow_dispatch events (0.094292ms)
    ✔ rejects release dispatches from unapproved refs (0.052167ms)
    ✔ requires expected-sha (0.050292ms)
    ✔ requires a full 40-character commit SHA (0.049ms)
    ✔ rejects when the selected ref moved after audit (0.061333ms)
    ✔ release dispatch guard (1.803125ms)
    ✔ streams a large prompt over stdin and maps the Copilot token to GITHUB_TOKEN (300.328875ms)
    ✔ surfaces Copilot stderr and preserves a non-zero exit code (216.517708ms)
    ✔ kills a hung Copilot process at the configured timeout (113.006916ms)
    ℹ tests 552
    ℹ suites 94
    ℹ pass 552
    ℹ fail 0
    ℹ cancelled 0
    ℹ skipped 0
    ℹ todo 0
    ℹ duration_ms 913.518709 (552 passing tests)
  • bun test v1.3.14 (0d9b296a) (227 passing tests)
  • bun install v1.3.14 (0d9b296a)

Checked 6 installs across 26 packages (no changes) [12.00ms]

  • Privacy scan passed
  • Workflow YAML parsing and script syntax compilation checks
  • Dedicated security review and audit performed with subagents (GPT-5.6 Luna)

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

@github-actions

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 25, 2026
@yansigit
yansigit changed the base branch from main to dev August 25, 2026 01:23
- Implement trusted Google Jules dispatcher and reconciler workflow (.github/workflows/agent-maintenance.yml)
- Add agent maintenance client, state validation, and repair digest (.github/scripts/agent-maintenance.cjs)
- Enforce exact-head Cursor Bugbot verification in PR gating (.github/workflows/enforce-pr-target.yml)
- Add comprehensive contract & unit tests for maintenance lifecycle (.github/scripts/agent-maintenance.test.cjs)
- Add Cursor Bugbot guidelines (.cursor/BUGBOT.md) and fork Dependabot config (.github/dependabot.yml)
- Update governance, AGENTS.md, MAINTAINERS.md, and docs/fork/AGENT-MAINTENANCE.md
@yansigit
yansigit force-pushed the codex/agent-maintenance-hardening branch from da9b527 to 0340779 Compare August 25, 2026 01:26
@yansigit
yansigit merged commit 812b5dd into dev Aug 25, 2026
22 checks passed
@yansigit
yansigit deleted the codex/agent-maintenance-hardening branch August 25, 2026 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant