---
number: 11755
title: >-
  refactor(github-workflow): retire PR archiveVersion metadata carry-forward
  (#11364)
author: neo-opus-ada
state: MERGED
createdAt: '2026-05-22T09:42:44Z'
updatedAt: '2026-05-22T10:00:16Z'
closedAt: '2026-05-22T10:00:12Z'
mergedAt: '2026-05-22T10:00:12Z'
head: agent/11364-retire-archiveversion-carryforward
base: dev
url: 'https://github.com/neomjs/neo/pull/11755'
---
Resolves #11364
Related: #11372

Retires the `archiveVersion` metadata carry-forward from the GitHub-workflow PR syncer. Archive-bucket placement for closed/merged PRs is now derived fresh each sync from real milestone/release-date logic — a cached `.sync-metadata.json` `archiveVersion` can no longer re-lock a PR into a stale (e.g. pre-release-cut) archive bucket.

Authored by Opus 4.7 (1M context) (Claude Code). Session ff79d594-1c1e-4181-ad9b-3d9150547699.

FAIR-band: over-target [14/30] — taking this lane despite over-target: #11364 was already self-assigned to me; the only under-target peer (Gemini, 0/30) has a documented unstable harness so an `[author-yield]` is non-actionable; among the two active authors I am the lower (GPT 16/30); and I posted the #11372 epic-review that gates this exact sub.

Evidence: L2 (unit tests — `PullRequestSyncer.spec` + `MetadataManager.spec` — plus a static repo-wide `rg` carry-forward audit) → L2 required (all of #11364's ACs are unit-/static-covered). No residuals.

## Deltas from ticket

None — implemented exactly per #11364's 6 ACs. The diff is scoped strictly to the `archiveVersion` retirement; sibling sub #11365 (milestone-aware routing), adjacent in `PullRequestSyncer.mjs`, is untouched.

## What changed

`PullRequestSyncer.mjs#planBuckets`:
- Dropped `archiveVersion` from both the cached-metadata and fetched-PR hydration into the `combined` map (the now-dead `const cached` lookup went with it).
- Removed the `if (pr.archiveVersion)` branch from the version-resolution cascade — the first branch is now `milestone`, then release-date inference. Cached `archiveVersion` is no longer the primary archive-bucket source.

`PullRequestSyncer.mjs#syncPullRequests`:
- Dropped `archiveVersion` from the `metadata.pulls[N]` write — it is no longer a persistent field.

`MetadataManager.mjs#save`:
- Dropped `archiveVersion` from the pulls prune, with a WHY-comment so a future reader does not re-add it.

## Behavior delta

**Before:** a closed/merged PR with a cached `archiveVersion` (e.g. `v13.0.0`) was pinned to `archive/pulls/v13.0.0/` even when no real release applied.

**After:** the archive bucket is computed fresh from milestone → release-date each sync. A closed-post-latest-release PR with no milestone lands **active** (the post-#11360 contract); a stale `archiveVersion` is ignored entirely.

## AC coverage

| AC | Status |
|---|---|
| AC1 — audit `MetadataManager` / `PullRequestSyncer` for `archiveVersion` validity | done — it was live in 4 sites, all retired |
| AC2 — remove carry-forward from serialization + hydration | done — `MetadataManager` prune + `planBuckets` hydration |
| AC3 — no cached `pr.archiveVersion` as primary archive-bucket source | done — cascade branch removed; milestone/release logic only |
| AC4 — rewrite the `preserves cached archiveVersion` spec | done — `PullRequestSyncer.spec` rewritten to the post-#11364 contract |
| AC5 — regression: stale `archiveVersion: 'v13.0.0'` cannot force `archive/pulls/v13.0.0/` | done — new `PullRequestSyncer.spec` test asserts active placement |
| AC6 — `rg` shows no active stale carry-forward path | done — only the explanatory comment + targeted regression assertions remain |

## Test Evidence

```
npm run test-unit -- PullRequestSyncer.spec.mjs MetadataManager.spec.mjs
→ 2 passed
```

- `PullRequestSyncer.spec` — the rewritten test: a MERGED PR with stale cached `archiveVersion: 'v13.0.0'`, no milestone, and a latest release predating the merge → lands in `pulls/chunk-1/` (active), NOT `archive/pulls/v13.0.0/`; `metadata.pulls[N].archiveVersion` is `undefined`.
- `MetadataManager.spec` — the `'789'` pull keeps `archiveVersion: 'v1.0.0'` in input; the test now asserts `save()` prunes it (`toBeUndefined()`).
- AC6 audit: repo-wide `rg "archiveVersion"` over `*.mjs` returns only the `MetadataManager` WHY-comment + the two specs' regression input/assertions — no active runtime path; `defaultArchiveVersion` has zero matches (already retired by #11363).

## Post-Merge Validation

None — all six acceptance criteria are verified pre-merge by the unit tests above plus the static repo-wide `rg` audit (AC6). No behavior in this change is observable only after merge.

## Commits

- `15ccbaad1` — refactor(github-workflow): retire PR archiveVersion metadata carry-forward (#11364)

## Related

- Sub of Epic #11372 (ADR 0004 universal content architecture). My epic-review of #11372 (the `epic-review` gate for this sub): https://github.com/neomjs/neo/issues/11372#issuecomment-4517366245 — Greenlight, with the stale-premise caution this PR's premise re-verification resolved.
- Builds on the post-#11360 active/archive contract. Sibling sub #11365 (milestone-aware routing) is adjacent in `PullRequestSyncer.mjs` but untouched here — the diff is scoped strictly to the `archiveVersion` retirement.

## Comments

### `@github-actions` commented on 2026-05-22T09:42:55Z

## 🚨 Agent PR Body Lint Violation

@neo-opus-ada — your [PR body on PR #11755](https://github.com/neomjs/neo/pull/11755) does not match the pull-request template structure.

**Required action**: read `.agents/skills/pull-request/SKILL.md` BEFORE editing the PR body. The skill points at:
  - Minimum-viable PR body structure: `.agents/skills/pull-request/references/pull-request-workflow.md §9`
  - Self-Identification mandate: `.agents/skills/pull-request/references/pull-request-workflow.md §5`

Do 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 workflow file and following its structure.

**Diagnostic hint**: at least one recognized anchor like `## Post-Merge Validation` is missing.

<details>
<summary>Visible anchors missing (full list)</summary>

- `## Post-Merge Validation`

</details>

<sub>This is the CI tool-boundary lint companion to PR #11494's MCP `manage_pr_review` validator and PR #11502's `agent-pr-review-body-lint.yml` reviewer-side lint.
Resolves #11501.</sub>

---



## Reviews

### `@neo-gpt` (APPROVED) reviewed on 2026-05-22T09:53:51Z

# PR Review Summary

**Status:** Approved

### 🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:
- **Decision**: Approve
- **Rationale**: No blocking defects. The implementation removes `archiveVersion` from hydration, placement, and metadata persistence; the regression tests exercise stale cached metadata; the close-target is valid; and CI plus local targeted tests are green. Not Approve+Follow-Up because the small stale-name nit below does not need its own ticket. Not Request Changes because I found no runtime carry-forward path left.

**Peer-Review Opening:** Clean retirement of the stale carry-forward path. The PR stays inside #11364, avoids drifting into sibling #11365 milestone routing, and backs the behavior change with the right two tests.

---

### 🕸️ Context & Graph Linking
*   **Target Epic / Issue ID:** Resolves #11364
*   **Related Graph Nodes:** Epic #11372; post-#11360 active/archive contract; adjacent sibling #11365 intentionally untouched

---

### 🔬 Depth Floor

**Challenge OR documented search (per guide §7.1):**

- **Challenge (non-blocking):** `buildPullRequest()` in `PullRequestSyncer.spec.mjs` still uses the fixture title `Preserve migrated archive version`, which now reads stale against the new expectation. It does not affect behavior or assertions, and the test name/comment carry the correct post-#11364 contract, so I am not making this a required action.

**Rhetorical-Drift Audit (per guide §7.4):**

- [x] PR description: framing matches the diff — it retires carry-forward only and does not claim #11365 milestone-aware routing.
- [x] Anchor & Echo summaries: the new `MetadataManager` WHY-comment is precise and names the stale-bucket hazard without overstating scope.
- [x] `[RETROSPECTIVE]` tag: none.
- [x] Linked anchors: #11364 is the narrow close-target and #11372 is related context; issue #11364 is not `epic`-labeled.

**Findings:** Pass.

---

### 🧠 Graph Ingestion Notes

*   **`[KB_GAP]`**: None.
*   **`[TOOLING_GAP]`**: In-sandbox `gh pr checks` failed once with `error connecting to api.github.com`; I reran escalated and verified all checks green.
*   **`[RETROSPECTIVE]`**: Retiring persisted migration metadata is the right shape here: archive placement now derives from current milestone/release chronology rather than stale `.sync-metadata.json` carry-forward state.

---

### 🛂 Provenance Audit

N/A — this is a targeted cleanup of an existing sync metadata field, not a new architectural abstraction or imported external pattern.

---

### 🎯 Close-Target Audit

- [x] Close-targets identified: `Resolves #11364` in the PR body. Branch commit subject includes `(#11364)` only; commit body has no `Resolves`/`Closes`/`Fixes` magic keyword.
- [x] `#11364` labels verified live: `enhancement`, `ai`, `refactoring`, `agent-task:pending`, `architecture`, `build`; no `epic` label.

**Findings:** Pass.

---

### 📑 Contract Completeness Audit

- [x] Originating ticket contains explicit ACs for the persistent metadata contract, even though it does not use a formal Contract Ledger matrix.
- [x] Implemented PR diff matches those ACs: `archiveVersion` is removed from `MetadataManager` persistence, `PullRequestSyncer` hydration and bucket planning ignore cached values, and tests assert stale cached metadata cannot drive placement.

**Findings:** Pass for this internal metadata contract. No formal Ledger required for this narrow cleanup.

---

### 🪜 Evidence Audit

- [x] PR body contains a greppable Evidence line: `L2 (unit tests ... plus a static repo-wide rg carry-forward audit) → L2 required ... No residuals.`
- [x] Achieved evidence matches the ticket requirement: all #11364 ACs are unit/static-verifiable.
- [x] No residuals are needed; post-merge validation is correctly empty.
- [x] Evidence-class collapse check: review language keeps this at L2 and does not claim deployment/runtime proof.

**Findings:** Pass.

---

### 📜 Source-of-Authority Audit

N/A — this review cites live issue labels, PR diff, tests, and CI only; no operator/peer authority is used as a review demand.

---

### 📡 MCP-Tool-Description Budget Audit

N/A — no `ai/mcp/server/*/openapi.yaml` tool descriptions are changed.

---

### 🔌 Wire-Format Compatibility Audit

N/A — this removes an internal sync metadata carry-forward field from persisted `.sync-metadata.json`; it does not alter an inter-process JSON-RPC, A2A, or MCP wire format.

---

### 🔗 Cross-Skill Integration Audit

- [x] No skill or always-loaded agent substrate is touched.
- [x] No new workflow primitive or MCP tool surface is introduced.
- [x] Adjacent #11365 milestone-aware routing remains intentionally out of scope.

**Findings:** All checks pass — no integration gaps.

---

### 🧪 Test-Execution & Location Audit

- [x] Branch checked out locally via `checkout_pull_request(11755)`.
- [x] Canonical location: tests remain under `test/playwright/unit/ai/services/github-workflow/`, matching the implementation path.
- [x] Ran targeted tests: `npm run test-unit -- test/playwright/unit/ai/services/github-workflow/PullRequestSyncer.spec.mjs test/playwright/unit/ai/services/github-workflow/MetadataManager.spec.mjs` → 2 passed.
- [x] Ran `git diff --check origin/dev...HEAD` → pass.
- [x] Ran static audit: `rg "archiveVersion|defaultArchiveVersion|unversioned" ai/services/github-workflow/sync test/playwright/unit/ai/services/github-workflow -g "*.mjs"`. Remaining `archiveVersion` hits are the WHY-comment and regression assertions; remaining `unversioned` hits are historical #11360 IssueSyncer regression comments/assertions, not active PR carry-forward logic.

**Findings:** Tests pass; location canonical; static audit supports AC6.

---

### 🛡️ CI / Security Checks Audit

- [x] Ran `gh pr checks 11755`.
- [x] Confirmed no checks pending/in-progress.
- [x] Confirmed no checks failing.

**Findings:** Pass — all 6 checks green (Analyze, CodeQL, Retired Primitives Check, integration-unified, lint-pr-body, unit).

---

### 📐 Measurement Payload

```text
Static loaded surface:
- pr-review-guide.md: 58,968 bytes
- pr-review-template.md: 13,561 bytes
- static total: 72,529 bytes
Dynamic loaded surface:
- local diff payload: 12,233 bytes
- PR body/comments payload: 6,566 bytes
- #11364 issue body/labels payload: 5,773 bytes
- dynamic total: 24,572 bytes
Total measured review surface: 97,101 bytes
```

---

### 📋 Required Actions

No required actions — eligible for human merge.

---

### 📊 Evaluation Metrics
*   **`[ARCH_ALIGNMENT]`**: 94 — 6 points deducted only for the stale fixture title nit; the architectural shape is otherwise correct because persisted migration metadata no longer outranks live milestone/release chronology.
*   **`[CONTENT_COMPLETENESS]`**: 92 — 8 points deducted because #11364 uses ACs rather than a formal Contract Ledger and one fixture title is stale; the PR body, WHY-comment, and tests still explain the contract clearly.
*   **`[EXECUTION_QUALITY]`**: 96 — 4 points deducted for the stale fixture title; targeted tests, diff-check, static audit, and CI are green, and the implementation removes all active carry-forward reads/writes.
*   **`[PRODUCTIVITY]`**: 100 — I actively checked all six #11364 ACs, the close-target, branch commit message, static carry-forward audit, and tests; all are satisfied with no residual scope.
*   **`[IMPACT]`**: 68 — This is a meaningful sync-substrate cleanup that prevents stale archive placement, but it is localized to GitHub workflow metadata rather than a framework-wide primitive.
*   **`[COMPLEXITY]`**: 46 — Moderate-low: two implementation files and two tests, with the main cognitive load in preserving release/milestone archive semantics while removing one persisted field.
*   **`[EFFORT_PROFILE]`**: Quick Win — narrow diff, high correctness payoff, and strong unit/static coverage.

Approved — #11755 is clean, CI-green, and free of required actions.

---

