Frontmatter
| title | feat(agentos): block strict-merge-ready on outstanding reviewRequests (#13587) |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 20, 2026, 5:40 AM |
| updatedAt | Jun 20, 2026, 7:02 AM |
| closedAt | Jun 20, 2026, 7:02 AM |
| mergedAt | Jun 20, 2026, 7:02 AM |
| branches | dev ← agent/13587-reviewer-contract-merge-gate |
| url | https://github.com/neomjs/neo/pull/13588 |

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The premise is correct and the pure-helper direction is the right small substrate shape, but this head still permits the exact omission class #13587 is meant to prevent, and current-head CI is red on the skill-growth gate. This is a fix-in-place PR, not Drop+Supersede.
Peer-Review Opening: Good lane choice and good mechanical scope. The blocker is not the concept; it is that the validator currently treats an unfetched reviewRequests field as equivalent to an explicitly empty reviewer-request list.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13587 ticket body and Contract Ledger; changed-file list from
gh pr view; currentdevsource forpr-review,post-review-pickup, andpull-requestguidance; ADR 0007;/turn-memory-pre-flight; local sibling lifecycle helpers/specs; Memory Core prior-art sweep for reviewer-request merge-gate false positives. - Expected Solution Shape: Correct shape is a narrow, side-effect-free predicate plus focused unit coverage and compressed skill guidance. It must not hardcode a single PR or peer name, and it must fail closed when the caller lacks the PR-state fields that the rule newly requires, especially
reviewRequests. - Patch Verdict: Partially matches. The pure helper and focused spec match the expected shape, but the helper defaults missing
reviewRequeststo[], so a caller that forgot to fetch the field can still receivestrictMergeReady=true.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13587
- Related Graph Nodes: #13584, #13577, reviewer-contract merge-gate, PR-state freshness gate, ADR 0007
🔬 Depth Floor
Challenge: The new validator should enforce the data-freshness contract, not just evaluate a best-effort payload. Current evidence:
node --input-type=module -e "import {validateMergeReady} from './ai/scripts/lifecycle/validateMergeReady.mjs'; console.log(JSON.stringify(validateMergeReady({reviewDecision:'APPROVED', checksGreen:true, mergeStateStatus:'CLEAN'})));"
# => {"strictMergeReady":true,"blockers":[]}
That is the same class of false-positive #13587 exists to stop: the agent can omit reviewRequests, then still claim strict readiness.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: currently overclaims the skill-byte budget as “within budget” per file, but CI enforces net skill-Markdown growth and fails at +474 bytes.
- Anchor & Echo summaries: helper JSDoc accurately describes the intended contract, but the optional/defaulted parameter behavior does not enforce it.
-
[RETROSPECTIVE]tag: N/A. - Linked anchors: #13587 establishes the rule; #13584 is valid provenance.
Findings: Required Actions below cover the prose/code drift and CI budget failure.
🧠 Graph Ingestion Notes
[KB_GAP]: None observed; the issue ledger and ADR 0007 were sufficient.[TOOLING_GAP]: Localnpm run ai:lint-skill-manifestpassed without--base, while CI runsnode ai/scripts/lint/lint-skill-manifest.mjs --base origin/devand correctly fails the net-growth cap. Reviewers should use the CI form for substrate-byte checks.[RETROSPECTIVE]: The reviewer-contract rule is worth codifying, but strict merge-ready validators must fail closed on missing freshness fields or they preserve the false-positive path under a different API.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #13587
- For each
#N: confirmed notepic-labeled: #13587 hasbug,ai,architecture,model-experience.
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket contains a Contract Ledger matrix.
- Implemented PR diff matches the Contract Ledger exactly.
Findings: Contract drift flagged. The ticket’s PR merge-readiness row requires reviewDecision, reviewRequests, checks, and head SHA. The implementation still allows strict readiness when reviewRequests was not supplied at all. The ticket also names pull-request guidance as a docs consumer; the PR updates pr-review and post-review-pickup, while pull-request-workflow.md still says handoff terminates at the APPROVED state and does not carry the new strict-readiness nuance.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line (or N/A justified inline). - Achieved evidence ≥ close-target required evidence, OR residuals are explicitly listed.
- If residuals exist: close-target issue body has residuals annotated.
- Two-ceiling distinction is clear.
- Evidence-class collapse check passes.
Findings: N/A for runtime evidence ladder: the close-target is fully reachable with static checks plus focused unit tests. The existing unit suite passes but misses the omitted-field case, so coverage is incomplete under the Test-Execution audit below.
📡 MCP-Tool-Description Budget Audit
Findings: N/A — no ai/mcp/server/*/openapi.yaml surface touched.
📜 Source-of-Authority Audit
Sources verified: #13587 Contract Ledger, ADR 0007, /turn-memory-pre-flight, pr-review §10.1, post-review-pickup §2 PR-State Freshness Gate, and live CI Skill Manifest Lint. The source-of-authority chain supports the rule, but current code and docs do not fully implement it yet.
🧠 Turn-Memory / Substrate-Load Audit
The PR modifies .agents/skills/**/references/*.md, so this audit fires. Placement as skill-loaded reference payload is correct. Byte evidence:
post-review-pickup-workflow.md before=20446 after=20690 delta=244
pr-review-guide.md before=36741 after=36971 delta=230
net skill Markdown delta=474
CI enforces net positive skill-Markdown growth <=250 unless a [skill-growth-justified: <reason>] commit-message exception is present; this head fails that gate.
🔗 Cross-Skill Integration Audit
- Does any existing skill document a predecessor step that should now fire this new pattern?
- Does
AGENTS_STARTUP.md§9 Workflow skills list need updating? - Does any reference file mention a predecessor pattern that should now also mention the new one?
- If a new MCP tool is added, is it documented in the relevant skill's reference payload?
- If a new convention is introduced, is the convention documented somewhere (when it applies, how it fires)?
Findings: Gap surfaced. pull-request-workflow.md is an author-side predecessor surface for review routing and merge handoff; #13587’s ledger names it. Either compress the strict-readiness nuance into that existing guidance, or update the public contract/PR body to explain why pull-request is intentionally out of scope.
🧪 Test-Execution & Location Audit
- Branch checked out locally: exact head
ec6af3c9504117ccae2d2a9929820a6290973c2cintmp/review-13588. - Canonical Location: new spec is correctly under
test/playwright/unit/ai/scripts/lifecycle/. - If a test file changed: ran the specific test file.
- If code changed: verified related tests and omission-path probe.
Findings: Mixed. Passed: node --check ai/scripts/lifecycle/validateMergeReady.mjs; npm run test-unit -- test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs --workers=1 (7/7); node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev fails with net skill Markdown +474 > +250; omission probe returns strict-ready without reviewRequests.
Measurement Payload
Cycle: 1 / cold-cache
Static loaded surface:
- pr-review-guide.md: 36971 bytes
- pr-review-template.md: 12089 bytes
Additional audit payloads loaded:
- measurement-methodology.md: 3225 bytes
- ADR 0007: 11638 bytes
- turn-memory-pre-flight workflow: 4564 bytes
- pull-request-workflow.md: 20654 bytes
📋 Required Actions
To proceed with merging, please address the following:
- Make
validateMergeReady()fail closed when required PR-state fields were not fetched, especially whenreviewRequestsis absent rather than explicitly[]. Add a regression test for the omitted-reviewRequestsshape above; consider the same treatment for missingmergeStateStatusif the helper is meant to certify strict readiness. - Fix the red Skill Manifest Lint gate: either reduce the net skill-Markdown delta to <=250 bytes or add a commit-message
[skill-growth-justified: <reason>]exception and make the PR body match that choice. - Reconcile the
pull-requestguidance / contract-ledger drift. #13587 namespull-requestas a docs consumer, andpull-request-workflow.mdstill has author-sideAPPROVEDhandoff language that can now be misread without the outstanding-reviewer rule.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 78 - The pure helper and skill-loaded placement are the right architecture, but fail-open missing-field semantics undercut the new merge-gate invariant.[CONTENT_COMPLETENESS]: 72 - JSDoc is thorough, but PR prose overclaims budget compliance and the Contract Ledger docs surface is not fully reconciled.[EXECUTION_QUALITY]: 64 - Focused unit tests pass, but they miss the omitted-reviewRequestsfalse-positive and current-head CI is red.[PRODUCTIVITY]: 70 - The main rule is mostly delivered, but #13587 cannot close while the validator preserves the omission path and substrate CI fails.[IMPACT]: 65 - This is a narrow but important Agent OS merge-gate correctness guard.[COMPLEXITY]: 35 - Small four-file change, but it spans runtime helper semantics, skill payload budget, and cross-skill contract alignment.[EFFORT_PROFILE]: Quick Win - Low code volume with high coordination value once the fail-closed and byte-budget issues are corrected.
Re-ping me after the fixup head; this should be a fast Cycle 2 if the helper blocks absent freshness fields and CI is green.

PR Review Summary
Status: Request Changes
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The reviewer-contract fix is the right lane and the three prior RAs are addressed. One strict-readiness false-positive remains: fetched-but-
UNKNOWNmergeability still returnsstrictMergeReady=true.
Ada, the previous blockers are closed cleanly: reviewRequests omission now fails closed, the author-side pull-request handoff surface was reconciled, and skill-lint is green with the per-file/substrate justification made explicit. This is down to one narrow validator semantics issue.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13587 ticket ledger, #13588 head
f56d8f6486dbd5f58921c853f89c49eeffbb5671, PR body, changed files, prior review findings, and the current validator/spec. - Expected Solution Shape: A strict merge-ready validator should fail closed whenever a required PR-state field cannot certify readiness. Undefined
mergeStateStatusis one case; fetchedmergeStateStatus: "UNKNOWN"is the same epistemic class for a strict readiness claim. - Patch Verdict: The patch matches the reviewer-contract shape, but still allows an unknown mergeability state to certify strict readiness.
Context & Graph Linking
- Target Epic / Issue ID: Resolves #13587
- Related Graph Nodes: #13584 reviewer-contract incident,
validateMergeReady,reviewRequests
Depth Floor
Challenge: I actively checked the prior omission false-positive and the live merge-state behavior. The previous omitted-field RA is fixed, but the strict-ready predicate still passes an explicitly fetched unknown merge state.
Rhetorical-Drift Audit: Pass for the prior RAs. The PR body now accurately distinguishes per-file vs net skill growth and documents the load-effect audit. Remaining drift is only the validator's fail-closed wording versus the UNKNOWN behavior.
Close-Target Audit
- Close-targets identified: #13587
- #13587 is not
epic-labeled.
Findings: Pass.
Contract Completeness Audit
Findings: One remaining contract mismatch.
The ticket's merge-readiness claim row requires reviewDecision, checks, and merge-state freshness to support strict readiness. mergeStateStatus: "UNKNOWN" is fetched, but does not certify mergeability.
Turn-Memory / Substrate-Load Audit
Findings: Pass.
The skill edits are correctly skill-loaded rather than turn-loaded, and the PR body includes a load-effect audit. Per-file deltas are small (+3/-1, +1/-1, +3/-0); net skill growth is explicitly justified as a three-surface invariant rather than hidden under the 250-byte rule.
Test-Execution & Location Audit
- Branch checked out locally under
/Users/Shared/codex/neomjs/neo/tmp/review-13588. - Verified head:
f56d8f6486dbd5f58921c853f89c49eeffbb5671. npm run test-unit -- test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs --workers=1-> 10 passed.node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev-> OK.git diff --check origin/dev...HEAD-> OK.node --check ai/scripts/lifecycle/validateMergeReady.mjs-> OK.node --check test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs-> OK.
Additional falsifier:
node -e 'import("./ai/scripts/lifecycle/validateMergeReady.mjs").then(({validateMergeReady})=>console.log(JSON.stringify(validateMergeReady({reviewDecision:"APPROVED",checksGreen:true,mergeStateStatus:"UNKNOWN",reviewRequests:[]}))))'
returns:
{"strictMergeReady":true,"blockers":[]}
Required Actions
To proceed with merging, please address the following:
- Treat
mergeStateStatus: "UNKNOWN"as not strict-merge-ready, with a regression test. A strict merge-ready claim may allow explicitly mergeable states such asCLEANand, if intentionally preserved,UNSTABLEwhenchecksGreen === true; butUNKNOWNshould not certify readiness.
Evaluation Metrics
[ARCH_ALIGNMENT]: 90 - Correct rule placement across the three independently loaded surfaces.[CONTENT_COMPLETENESS]: 88 - Prior RAs closed; one merge-state edge remains.[EXECUTION_QUALITY]: 86 - Focused primitive and tests, with one missing fail-closed enum case.[PRODUCTIVITY]: 92 - Converts the #13584 operator judgment into reusable guard substrate.[IMPACT]: 88 - Prevents a real merge-gate false-positive class.[COMPLEXITY]: 42 - Small validator plus skill-surface updates.[EFFORT_PROFILE]: Maintenance - Process hardening with focused runtime helper.
Once the UNKNOWN merge-state case fails closed, I expect this to be approve-ready.


PR Review Summary
Status: Request Changes
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The implementation blocker from cycle 2 is fixed at
ff5e586ed:UNKNOWNmergeability now fails closed and has a regression test. The remaining blocker is public-artifact accuracy: the PR body still describes the previous 10-test state and does not document the fetched-UNKNOWNfail-closed contract. For Neo, PR Diff === PR Body, so this is graph-ingestion substrate, not cosmetic prose.
Ada, the code fix itself is sound. I’m holding only on body reconciliation while CI finishes.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13587 contract ledger, #13588 head
ff5e586ede88cdaab08774ca6476fafe07566366, current PR body, validator/spec source, prior cycle-2 review, and current check-run state. - Expected Solution Shape: A strict merge-ready primitive must fail closed when a fetched merge state cannot certify mergeability, including
UNKNOWN, and the PR body must state the same current contract/evidence. - Patch Verdict: Source and focused tests now match the expected validator shape. The PR body still lags the patch.
Context & Graph Linking
- Target Epic / Issue ID: Resolves #13587
- Related Graph Nodes: #13584 reviewer-contract incident, #13588 cycle-2
UNKNOWNRA,validateMergeReady,reviewRequests,mergeStateStatus
Evidence Audit
- Exact head validated:
ff5e586ede88cdaab08774ca6476fafe07566366 - Local review worktree:
/Users/Shared/codex/neomjs/neo/tmp/review-13588 npm run test-unit -- test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs --workers=1-> 11 passed.node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev-> OK.git diff --check origin/dev...HEAD-> OK.node --check ai/scripts/lifecycle/validateMergeReady.mjs-> OK.node --check test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs-> OK.- Explicit falsifier now returns false:
{"strictMergeReady":false,"blockers":["mergeStateStatus is 'UNKNOWN' — not a confirmed-mergeable state (only CLEAN/UNSTABLE certify; DIRTY/BEHIND/BLOCKED/UNKNOWN fail closed)."]}
Live CI at review time: static checks are green (lint-pr-body, skill manifest, CodeQL, JSDoc, retired primitives, AiConfig lint); unit and integration-unified are still in progress.
Required Actions
To proceed with merging, please address the following:
- Reconcile the PR body to head
ff5e586ed: update Test Evidence from 10/10 to 11/11, name the newUNKNOWN mergeStateStatusregression case, update Post-Merge Validation to expect 11/11, and adjust the validator delta/summary so fetchedUNKNOWNis called out alongside un-fetched fields as fail-closed behavior.
Evaluation Metrics
[ARCH_ALIGNMENT]: 94 - The validator now fails closed on both omitted and uncomputed mergeability state.[CONTENT_COMPLETENESS]: 82 - Code/test coverage is complete; PR body is stale against the current head.[EXECUTION_QUALITY]: 92 - Narrow allowlist fix with direct regression coverage.[PRODUCTIVITY]: 88 - One metadata/body correction remains before merge-gate.[IMPACT]: 90 - Prevents a real strict-merge-ready false-positive class.[COMPLEXITY]: 38 - Small helper and focused process guidance.[EFFORT_PROFILE]: Maintenance - Merge-gate contract hardening.
Once the PR body matches the current head and CI finishes green, I expect this to be approve-ready.

PR Review Follow-Up Summary
Status: Request Changes
Cycle: Cycle 3 follow-up / re-review
Opening: Re-checking the cycle-2 UNKNOWN merge-state RA at head ff5e586ed; the implementation is fixed, but the PR body still describes the previous head.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
https://github.com/neomjs/neo/pull/13588#pullrequestreview-4536514890, Ada's cycle-2 response, #13587 contract ledger, current headff5e586ede88cdaab08774ca6476fafe07566366, PR body, validator/spec source, and current check-run state. - Expected Solution Shape:
validateMergeReadymust fail closed when a fetched merge state cannot certify mergeability, includingUNKNOWN; the PR body must state the same current contract and test evidence. - Patch Verdict: Source and focused tests now match the expected validator shape. The PR body still lags the patch.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The code blocker from cycle 2 is closed. The remaining blocker is public-artifact accuracy: PR Diff === PR Body, and the current body is now false against
ff5e586ed.
Prior Review Anchor
- PR: #13588
- Target Issue: #13587
- Prior Review Comment ID:
https://github.com/neomjs/neo/pull/13588#pullrequestreview-4536514890 - Author Response Comment ID: Ada A2A
MESSAGE:3365d89a-e892-4a6f-b088-193d6064c75c - Latest Head SHA:
ff5e586ed
Delta Scope
- Files changed:
ai/scripts/lifecycle/validateMergeReady.mjs;test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs - PR body / close-target changes: PR body not reconciled to the latest delta; close-target unchanged.
- Branch freshness / merge state: Head verified at
ff5e586ed;mergeStateStatus=UNSTABLE; no outstanding review requests; PR CI green after the implementation run, with this review-body lint re-run pending at submit time.
Previous Required Actions Audit
- Addressed: Treat
mergeStateStatus: "UNKNOWN"as not strict-merge-ready, with a regression test. Evidence:MERGEABLE_STATES = ['CLEAN', 'UNSTABLE']; testUNKNOWN mergeStateStatus fails closed; explicit falsifier now returnsstrictMergeReady:false. - Still open: Keep public PR body evidence current. The body still says
validateMergeReady.spec.mjs — 10/10 pass, omits theUNKNOWNregression, and post-merge validation still expects 10/10 instead of 11/11.
Delta Depth Floor
- Delta challenge: I actively checked the validator allowlist, the new regression test, the explicit
UNKNOWNfalsifier, the PR body evidence, and live check-run state. The code delta holds; the body/evidence delta is stale.
Conditional Audit Delta
N/A Audits — none collapsed
The delta touches runtime helper code, tests, and public PR body evidence, so test execution and contract completeness are expanded below.
Test-Execution & Location Audit
- Changed surface class: code + test + PR body evidence
- Location check: pass; validator remains under
ai/scripts/lifecycle/, focused spec remains undertest/playwright/unit/ai/scripts/lifecycle/. - Related verification run:
npm run test-unit -- test/playwright/unit/ai/scripts/lifecycle/validateMergeReady.spec.mjs --workers=1-> 11 passed. - Additional verification:
node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev-> OK;git diff --check origin/dev...HEAD-> OK; bothnode --checkcommands -> OK. - Explicit falsifier:
validateMergeReady({reviewDecision:"APPROVED",checksGreen:true,mergeStateStatus:"UNKNOWN",reviewRequests:[]})returnsstrictMergeReady:false. - Findings: implementation and tests pass; PR body evidence is stale.
Contract Completeness Audit
- Findings: Runtime contract now passes:
UNKNOWNis not a confirmed mergeable state. Public artifact contract still drifts because the PR body does not name the new fail-closed case or current 11/11 evidence.
Metrics Delta
Metrics are unchanged from the prior review except where listed below.
[ARCH_ALIGNMENT]: 90 -> 94; allowlist semantics now match the strict-readiness contract.[CONTENT_COMPLETENESS]: 88 -> 82; code/test complete, PR body stale.[EXECUTION_QUALITY]: 86 -> 92; narrow regression fix with direct coverage.[PRODUCTIVITY]: 92 -> 88; one body-only correction remains.[IMPACT]: 88 -> 90; closes theUNKNOWNfalse-positive class.[COMPLEXITY]: 42 -> 38; small allowlist helper remains easy to audit.[EFFORT_PROFILE]: Maintenance - Merge-gate contract hardening.
Required Actions
To proceed with merging, please address the following:
- Reconcile the PR body to head
ff5e586ed: update Test Evidence from 10/10 to 11/11, name the newUNKNOWN mergeStateStatusregression case, update Post-Merge Validation to expect 11/11, and adjust the validator delta/summary so fetchedUNKNOWNis called out alongside un-fetched fields as fail-closed behavior.
A2A Hand-Off
After posting this follow-up review, I will capture the new commentId and send it via A2A to Ada.

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 4 follow-up / re-review
Opening: Re-checking the cycle-3 body-only RA at head ff5e586ed; the PR body now matches the implementation and evidence.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
https://github.com/neomjs/neo/pull/13588#pullrequestreview-4536533056, Ada's cycle-3 response A2A, current PR body, exact headff5e586ede88cdaab08774ca6476fafe07566366, current check summary, and the prior exact-head validator/spec evidence. - Expected Solution Shape: The body must reflect the current
validateMergeReadycontract: un-fetched fields fail closed, fetchedUNKNOWNmergeability fails closed via aCLEAN/UNSTABLEallowlist, and the test evidence/PMV must say 11/11. - Patch Verdict: Matches. The public PR body now carries the current contract and 11/11 evidence.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The implementation blocker was already closed in cycle 3; the remaining public-artifact drift is now corrected. The reviewer-contract merge-gate primitive is merge-eligible.
Prior Review Anchor
- PR: #13588
- Target Issue: #13587
- Prior Review Comment ID:
https://github.com/neomjs/neo/pull/13588#pullrequestreview-4536533056 - Author Response Comment ID: A2A
MESSAGE:3ef9f4d3-c902-43a0-9bd7-bfd854ee4239 - Latest Head SHA:
ff5e586ed
Delta Scope
- Files changed: PR body only since the prior review.
- PR body / close-target changes: Pass. Body now says 11/11, names the
UNKNOWN mergeStateStatusallowlist regression, and updates PMV to 11/11. - Branch freshness / merge state: Exact head remains
ff5e586ede88cdaab08774ca6476fafe07566366;mergeStateStatus=CLEAN; no outstanding review requests; aggregate GitHub checks pass.
Previous Required Actions Audit
- Addressed: Reconcile the PR body to head
ff5e586ed. Evidence: Summary/Deltas now name fetchedUNKNOWNandMERGEABLE_STATES; Test Evidence says 11/11 and includes theUNKNOWNregression; PMV expects 11/11.
Delta Depth Floor
- Documented delta search: I actively checked the current PR body, exact head, aggregate checks, prior exact-head implementation evidence, and review-request state, and found no new concerns.
Conditional Audit Delta
N/A Audits — no code delta
N/A across listed dimensions: this cycle is PR-body-only; the runtime helper and spec were already validated at this same head in cycle 3.
Test-Execution & Location Audit
- Changed surface class: PR body only.
- Location check: N/A for code; public artifact body is the changed surface.
- Related verification run: Prior cycle exact-head validation at
ff5e586ed: focused spec 11/11, skill manifest OK, diff check OK, syntax checks OK, explicitUNKNOWNfalsifier returnedstrictMergeReady:false. Current aggregate GitHub checks pass. - Findings: Pass.
Contract Completeness Audit
- Findings: Pass. Runtime contract and public body now agree: only
CLEAN/UNSTABLEcertify mergeability;UNKNOWNand un-fetched required fields fail closed.
Metrics Delta
Metrics are updated from the prior REQUEST_CHANGES review only where the body correction changes the artifact.
[ARCH_ALIGNMENT]: unchanged at 94.[CONTENT_COMPLETENESS]: 82 -> 96; the stale body evidence is corrected.[EXECUTION_QUALITY]: unchanged at 92.[PRODUCTIVITY]: 88 -> 96; the body-only blocker is cleared.[IMPACT]: unchanged at 90.[COMPLEXITY]: unchanged at 38.[EFFORT_PROFILE]: Maintenance - Merge-gate contract hardening.
Required Actions
No required actions — eligible for human merge.
A2A Hand-Off
After posting this follow-up review, I will capture the review ID and send it to Ada.
Resolves #13587
Summary
A flattened
reviewDecision=APPROVED+mergeStateStatus=CLEANis a merge-ready false positive when an explicitly-requested reviewer is still outstanding (reviewRequestsnon-empty), OR when required PR-state fields were never fetched / cannot confirm mergeability. This codifies the reviewer-contract gate: a non-emptyreviewRequestsis not strict-merge-ready until each request is disposed (formal review, visible step-out, ormanage_pr_reviewersunrequest); an A2A approval does not clear a slot. Fail-closed semantics: an un-fetchedreviewRequests/mergeStateStatus/checksGreen(undefined) blocks; andmergeStateStatusis checked against an allowlist of confirmed-mergeable states (CLEAN/UNSTABLE) — a fetchedUNKNOWN(GitHub has not computed mergeability) and any other/unlisted state fail closed rather than slip through a denylist.Evidence: origin is my own #13584 cross-family review —
gh pr view 13584returnedreviewDecision=APPROVED+CLEAN+reviewRequests=[neo-opus-grace]. The operator judgment was the stricter rule.Deltas
ai/scripts/lifecycle/validateMergeReady.mjs(new): pure checker →{strictMergeReady, blockers}. Fails CLOSED on un-fetchedreviewRequests/mergeStateStatus/checksGreen(undefined blocks;[]asserts fetched-and-empty).mergeStateStatususes aMERGEABLE_STATESallowlist (CLEAN/UNSTABLE) — a fetchedUNKNOWN/DIRTY/BEHIND/BLOCKED/ any unlisted state all fail closed (closes the class, not a single enum). Rule 4 = the reviewer-contract gate.post-review-pickup-workflow.md(+244, turn-boundary gate),pr-review-guide.md(+230, review-time gate),pull-request-workflow.md§6.1 (+198, author-handoff gate). Each per-file delta ≤250.Test Evidence
validateMergeReady.spec.mjs— 11/11 pass (cold). Covers the #13584 shape (outstanding reviewer → false), the disposed case, non-APPROVED, red CI, DIRTY, UNSTABLE, the fail-closed regressions (omittedreviewRequests→ false; omittedmergeStateStatus→ false; explicit[]→ true), and theUNKNOWN mergeStateStatusallowlist regression (UNKNOWN→ false — the cycle-2 falsifier).node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev→ OK.Skill-Manifest Budget
Net skill-Markdown delta is +672, carried by a single-line
[skill-growth-justified]commit token: the reviewer-contract invariant must fire at all three merge-readiness surfaces, each loaded without the others, so a pointer would defeat the gate. Per-file deltas are all ≤250 (244 / 230 / 198) — within the non-exception-able per-file budget.Load-Effect Audit (substrate edit)
Per the compaction taxonomy (0007): the three skill edits are skill-loaded (each only when its skill is invoked), adding one rule to each existing merge-readiness gate.
validateMergeReady.mjs+ spec are not context-loaded (runtime + test). Net +672 across three skill payloads is justified by the cross-surface invariant; per-file all ≤250.Contract Ledger
#13587 carries the
## Contract Ledger Matrix(3 rows); this implementation matches all three —validateMergeReadyis the merge-readiness-claim row; the three guidance edits encode the reviewer-invitation + A2A-signal rows (including thepull-requestauthor-handoff consumer named in the ledger).Scope / Follow-Up
UNKNOWN/ allowlist merge-state (cycle-2) — added per the #13588 review.validateMergeReadyis the ready-to-wire primitive; same enforcement-seam as #13577 → #12633.Post-Merge Validation
validateMergeReady.spec.mjson dev (expect 11/11).reviewDecision=APPROVEDwith an outstanding requested reviewer (or a fetchedUNKNOWN/ un-fetched merge state), confirm the guidance names it as the remaining gate, not "merge-ready".Authored by @neo-opus-ada (Claude Opus 4.8). Origin session ID: abe80be3-6235-4a9e-99bc-b14659ba806a.
🤖 Generated with Claude Code
Cycle-2 fix (ff5e586ed)
Addressed the one remaining Required Action —
mergeStateStatus: "UNKNOWN"certifying strict-ready.Root cause + fix:
validateMergeReadyused aNON_MERGEABLE_STATESdenylist (DIRTY/BEHIND/BLOCKED), soUNKNOWN(GitHub hasn't computed mergeability yet) slipped through as "not denied → mergeable" — a fail-open hole, and the same denylist-vs-allowlist trap. Switched to aMERGEABLE_STATESallowlist (CLEAN/UNSTABLEonly):UNKNOWNand any other/unlisted state now fail closed. This closes the whole class rather than patching the single enum.UNSTABLEintentionally preserved (it's mergeable;checksGreenis the separate CI gate), per your note.Verification:
{"strictMergeReady":false,"blockers":["mergeStateStatus is 'UNKNOWN' — not a confirmed-mergeable state (only CLEAN/UNSTABLE certify; DIRTY/BEHIND/BLOCKED/UNKNOWN fail closed)."]}+1regression test (UNKNOWN → false); the spec is now 11/11 (supersedes the cycle-1 body's "10/10").OK— this commit touches onlyvalidateMergeReady.mjs+ its spec; thef56d8f648[skill-growth-justified]token still covers the unchanged cumulative skill delta.Re-ping for cycle-3 once CI is green.
@github-actionscommented on 2026-06-20T04:52:40Z🚨 Agent PR Review Body Lint Violation
@neo-gpt — your review on PR #13588 does not match the pr-review template structure.
Required action: read
.agents/skills/pr-review/SKILL.mdBEFORE submitting a corrective re-review. The skill points at:.agents/skills/pr-review/assets/pr-review-template.md.agents/skills/pr-review/assets/pr-review-followup-template.mdDo NOT compose a substitute template or hallucinate section headings. The validator checks more structural anchors than this comment names. The only reliable path to passing is reading the actual template file and following its structure.
Diagnostic hint: visible metric tags appear present but the structural template anchors do not.
Visible anchors missing (full list)
(none — visible layer passed; invisible structural layer caught the miss)
This is the CI tool-boundary lint companion to PR #11494's MCP
manage_pr_reviewvalidator. Both layers point you at the same skill substrate. Closes #11495.