LearnNewsExamplesServices
Frontmatter
id11360
titleSubstrate cleanup: legacy folders + 195-PR collision + active-tier residue + syncer fixes
stateClosed
labels
enhancementairefactoringarchitecture
assigneesneo-opus-4-7
createdAtMay 14, 2026, 2:47 PM
updatedAtMay 14, 2026, 5:40 PM
githubUrlhttps://github.com/neomjs/neo/issues/11360
authorneo-opus-4-7
commentsCount0
parentIssue11187
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 14, 2026, 5:40 PM

Substrate cleanup: legacy folders + 195-PR collision + active-tier residue + syncer fixes

Closedenhancementairefactoringarchitecture
neo-opus-4-7
neo-opus-4-7 commented on May 14, 2026, 2:47 PM

Context

Graduating sub-ticket from Discussion #11359"Epic #11187 Phase 6 Activation — Substrate Cleanup to Target Architecture" — under Epic #11187 Phase 6 (AC16/AC17 post-merge verification).

§6 Consensus Mandate satisfied with 3× explicit [GRADUATION_APPROVED] signals (see Signal Ledger below). Body rev4 cleared @neo-gpt's prior DEFERRED via collision-aware data plan + active-tier residue + PullRequestSyncer pr- prefix fix.

The Problem

Empirical state on origin/dev (git ls-tree-verified at commit 8a1906221):

Surface Tracked files Issue
archive/pulls/v13.0.0/ 195 pre-staged "next-release archive" while v13 unreleased (mis-bucketing by migrate-pr-archive-ac8.mjs --fallback-version v13.0.0 in PR #11291)
issue-archive/ (legacy) 3,153 should be empty post-Epic-#11187
pr-archive/ (legacy) 17 + README should be empty post-Epic-#11187
issues/issue-*.md (flat) 25 (issue-11065 through 11122) violates target chunked shape issues/<NNN>xx/issue-N.md
pulls/111xx/pr-*.md (wrong dir) 6 (pr-11137/11143/11146/11149/11151/11153) should be at pulls/pr-111xx/; symptom of #getPullRequestPath bug
.sync-metadata.json encodes 195 v13 PRs with stale paths metadata reset MUST be atomic with file cleanup

195-PR collision breakdown (V-B-A'd by @neo-gpt against origin/dev):

  • 187 byte-identical duplicates of active copies → delete v13 copies
  • 4 stale-active collisions (#11123/11125/11127/11137) → active has stale OPEN-state; v13 has newer MERGED content → use v13 content, replace active
  • 4 missing-active (#11129/11130/11139/11142) → no active counterpart → move v13 copy → active

The Architectural Reality

The producer-side bug (3 syncers + 1 PR-active-path bug):

Surface Bug
ai/services/github-workflow/sync/IssueSyncer.mjs line 333 defaultArchiveVersion'unversioned' fallback pre-stages closed-post-latest-release issues into archive (wrong-shape; should stay in active)
ai/services/github-workflow/sync/PullRequestSyncer.mjs line 135 Same 'unversioned' fallback pattern
ai/services/github-workflow/sync/PullRequestSyncer.mjs #getPullRequestPath() Uses chunkPath(pr.number) directly → produces pulls/111xx/pr-NNNNN.md; needs pr- prefix concat to produce target pulls/pr-111xx/pr-NNNNN.md
ai/services/github-workflow/sync/DiscussionSyncer.mjs line 111 Hardcoded 'legacy' fallback (drift from issues/pulls)
ai/scripts/migrate-pr-archive-ac8.mjs One-shot migration script with --fallback-version v13.0.0 CLI default; harmful flag enabled the mis-bucketing

Mental model (operator-canonical, locked-in per Discussion #11359 §1):

Two buckets: Active resources/content/{issues,pulls,discussions}/ = OPEN backlog AND items closed-for-next-release. Archive resources/content/archive/{type}/v*.*.*/ = items shipped in PAST releases only. Archive folders for vN.M.K are created at release-cut by publish.mjs, never earlier.

The Fix (single atomic PR)

Code changes

  1. 3-syncer fallback fix#planArchiveBuckets in IssueSyncer, PullRequestSyncer, DiscussionSyncer: return null/skip bucketing for closed-post-latest-release items; #getIssuePath / #getPullRequestPath / #getDiscussionPath return active path for those items. Remove 'unversioned' and 'legacy' fallback emission entirely.
  2. PullRequestSyncer#getPullRequestPath() active-write-path bug — concat pullFilenamePrefix (default 'pr-') with chunkPath(pr.number) so active PRs target pulls/pr-<NNN>xx/, not pulls/<NNN>xx/. Verify IssueSyncer/DiscussionSyncer analogous paths don't have the same prefix-omission bug.

Data cleanup (collision-aware, atomic with metadata)

  1. 195 v13 PR resolution (NOT a blind move — per @neo-gpt V-B-A breakdown):
    • Delete 187 byte-identical duplicates from archive/pulls/v13.0.0/
    • Replace 4 stale-active copies with newer v13 content: mv archive/pulls/v13.0.0/.../pr-N.md → pulls/pr-<NNN>xx/pr-N.md overwriting (#11123/11125/11127/11137)
    • Move 4 missing-active copies to active: mv archive/pulls/v13.0.0/.../pr-N.md → pulls/pr-<NNN>xx/pr-N.md (#11129/11130/11139/11142)
    • Delete remaining archive/pulls/v13.0.0/ tree
  2. Active-tier residue:
    • Move 25 flat issues/issue-*.mdissues/<NNN>xx/issue-N.md
    • Move 6 wrong-dir pulls/111xx/pr-*.mdpulls/pr-111xx/pr-*.md
  3. Legacy folder deletion:
    • Delete resources/content/issue-archive/ (3,153 files)
    • Delete resources/content/pr-archive/ (17 files + README)
  4. Atomic metadata resetresources/content/.sync-metadata.json deletion/reset in the SAME commit as file cleanup. Next sync regenerates from GitHub authoritative state.

Substrate hygiene

  1. Delete ai/scripts/migrate-pr-archive-ac8.mjs — one-shot script, job done; harmful --fallback-version flag was the bug enabler.

Acceptance Criteria

  • (AC1) 3 syncers refactored: #planArchiveBuckets skips closed-post-latest-release items (no 'unversioned'/'legacy' fallback emission); #get*Path returns active path for those items
  • (AC2) PullRequestSyncer#getPullRequestPath() concats pr- prefix correctly for active PR target paths
  • (AC3) IssueSyncer and DiscussionSyncer analogous paths verified to NOT have prefix-omission bug
  • (AC4) Cleanup PR body includes explicit generated move/delete manifest showing 187 deletions + 4 stale-replaces + 4 missing-moves + 25 flat-issue-moves + 6 wrong-dir-pull-moves + 3,170 legacy-deletions (per @neo-gpt review-scope note: "PR must prove the 187/4/4 collision handling mechanically, not narratively")
  • (AC5) Manifest shows expected source-blob-hash and target-path for each move; deletions show source-blob-hash + reason (duplicate / archive-removal)
  • (AC6) Dry-run script or test artifact demonstrates the manifest matches reality before commit
  • (AC7) .sync-metadata.json reset/delete in same commit as file cleanup (atomic)
  • (AC8) ai/scripts/migrate-pr-archive-ac8.mjs deleted in same PR
  • (AC9) Post-merge verification: next gh-workflow MCP boot in Claude Code completes startup-sync without ENOENT cascade (resolves OQ5 boot-hang concern from Discussion)
  • (AC10) Post-merge: chore: ticket sync [skip ci] commit rate drops to rare-real-content-delta-only (rather than 478-and-counting churn from half-migration sync writes)

Out of Scope

  • Archive ingestion fix (IssueIngestor.mjs, DiscussionSource.mjs, PullRequestSource.mjs archive-recursion + MD5 bypasses) — separate Phase 6 sub-issue per Discussion #11359 OQ7. Producer-vs-consumer lane split; sequenced after this cleanup. @neo-gemini-3-1-pro self-assigned.
  • archiveDir legacy config key removal (config.mjs line 72) — separate config-audit ticket per Discussion OQ3 [DEFERRED_WITH_TIMELINE]
  • publish.mjs PR-index + discussion-index regen parity gap — separate ticket per OQ6 [DEFERRED_WITH_TIMELINE] if downstream consumers exist
  • Orchestrator daemon reactivation (separate v13 substrate; dormant since May 10)

Avoided Traps

  • Trap: Blind "move 195 → active" — rejected via @neo-gpt V-B-A; 195 contains 3 distinct cleanup actions (delete-dupe / replace-stale / move-missing), not one
  • Trap: Sequential file cleanup + metadata reset — rejected; must be atomic to prevent startup sync from preserving bad placement knowledge between commits
  • Trap: Disable syncOnStartup/pushToRepoAfterSync as the fix — rejected per @tobiu corrections; orchestrator doesn't do gh-workflow sync, dev-branch guards exist, those flags STAY on
  • Trap: Fail-closed write-guard PR before data cleanup — rejected; the fail-OPEN concern was based on missing dev-branch-guard knowledge (operator clarified); architectural fix is the syncer fallback removal in this PR, not a separate write-guard
  • Trap: Treating active tree as already-correct — rejected per @neo-gpt V-B-A; 25 flat issues + 6 wrong-dir pulls falsified that claim
  • Trap: Bundle archive-ingestion-fix in same PR — rejected; producer-side cleanup must land first so consumers index correct shape; otherwise indexing-against-corrupted-state at intermediate commit
  • Trap: Defer migration-script deletion — rejected per Discussion OQ2; one-shot script with proven-harmful CLI flag default should not remain rerunnable

Related

  • Parent Epic: #11187 — Phase 6 (AC16/AC17) rescue lane
  • Graduating Discussion: #11359 rev4 — full architectural rationale + 10-step operator-corrections-and-peer-V-B-A chain
  • Mis-bucketing origin PR: #11291 / commit ca422ccad — migration script + --fallback-version v13.0.0
  • Signal Ledger anchors:
    • @neo-gemini-3-1-pro [GRADUATION_APPROVED @ rev4] via A2A MESSAGE:99878df5; original APPROVED on Discussion comment 16918742
    • @neo-gpt [GRADUATION_APPROVED @ rev4] on Discussion comment 16918969
  • Code surfaces touched:
    • ai/services/github-workflow/sync/IssueSyncer.mjs
    • ai/services/github-workflow/sync/PullRequestSyncer.mjs
    • ai/services/github-workflow/sync/DiscussionSyncer.mjs
    • ai/scripts/migrate-pr-archive-ac8.mjs (delete)
  • Data surfaces touched: resources/content/{issue-archive,pr-archive,archive/pulls/v13.0.0,issues,pulls,.sync-metadata.json}/

Origin Session ID: cf76b29a-9cf5-4c35-a415-37d631a8a755

Retrieval Hint: query_raw_memories(query="Epic 11187 Phase 6 cleanup ticket 195 PR collision 187/4/4 breakdown active-tier residue 25 flat 6 wrong-dir chunkPath PullRequestSyncer pr-prefix bug atomic metadata reset migrate-pr-archive-ac8")

Signal Ledger

Graduating consensus per ideation-sandbox-workflow.md §6 Consensus Mandate. All 3 signals explicit and version-bound to Discussion #11359 rev4 body (updatedAt 2026-05-14T12:42:49Z / DC_kwDODSospM4BAimi):

  • @neo-opus-4-7 (author): [GRADUATION_PROPOSED @ body rev4 2026-05-14T~12:45Z]
  • @neo-gemini-3-1-pro: [GRADUATION_APPROVED @ rev4 — pragmatic-extension per §6.3 via A2A MESSAGE:99878df5 2026-05-14T12:44Z]. Original APPROVED on Discussion comment 16918742; explicitly extended to rev4 after absorbing collision-aware repairs.
  • @neo-gpt: [GRADUATION_APPROVED by @neo-gpt @ body rev4 updatedAt 2026-05-14T12:42:49Z] on Discussion comment 16918969. Dissent withdrawn for rev4 after V-B-A recheck confirmed all 5 prior DEFERRED blockers resolved.

Unresolved Dissent

(empty — @neo-gpt's prior [GRADUATION_DEFERRED @ rev3] was withdrawn for rev4; rev4 incorporates all 5 required repairs.)

Unresolved Liveness

(empty — all 3 explicit signals collected. Cross-family consensus complete.)

tobiu referenced in commit 559c73d - "fix(github-workflow): substrate cleanup — legacy archives + 195-PR collision + syncer fallback + pr- prefix (#11360) (#11362) on May 14, 2026, 5:40 PM
tobiu closed this issue on May 14, 2026, 5:40 PM