---
id: 11290
title: Fail loudly on stale GitHub Workflow archive config
state: CLOSED
labels:
  - enhancement
  - ai
  - architecture
  - build
assignees:
  - neo-opus-ada
createdAt: '2026-05-13T07:43:26Z'
updatedAt: '2026-05-13T12:59:18Z'
githubUrl: 'https://github.com/neomjs/neo/issues/11290'
author: neo-gpt
commentsCount: 0
parentIssue: 11187
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-05-13T12:59:18Z'
---
# Fail loudly on stale GitHub Workflow archive config

## Context

This is the missing B0a companion for Epic #11187, surfaced during the 2026-05-13 clone-local config sync recovery.

PR #11282 merged the MetadataManager pruning prerequisite. During the follow-up archive-structure readiness check, the swarm found that `ai/mcp/server/github-workflow/config.template.mjs` had the archive fields, but each agent's gitignored clone-local `ai/mcp/server/github-workflow/config.mjs` needed manual sync. The Codex/GPT clone and Gemini real repo clone were patched cleanly. Claude's persistent checkout briefly entered a worse partial state: `archiveRoot` present while `archiveChunkThreshold` and `archiveChunkPrefix` were missing.

That state is more dangerous than a fully stale config: code that only checks for `archiveRoot` can proceed into archive planning while the lazy chunking contract is undefined.

## The Problem

The GitHub Workflow runtime config has no loud shape validation for the archive substrate fields required by Epic #11187:

- `issueSync.archiveRoot`
- `issueSync.archiveChunkThreshold`
- `issueSync.archiveChunkPrefix`

Template/local drift is expected because `config.mjs` is gitignored and clone-local. #10559 already added PR workflow guidance for template-change notification, and #11189 added the initial archive config fields. Those are necessary but not sufficient: when a local runtime config is stale or partially patched, archive sync/release tooling should fail early with an operator-actionable error instead of running with undefined chunk semantics.

## The Architectural Reality

Observed current surfaces:

- `ai/mcp/server/github-workflow/config.template.mjs` declares `archiveRoot`, `archiveChunkThreshold: 100`, and `archiveChunkPrefix: 'chunk-'`.
- `ai/mcp/server/github-workflow/config.mjs` is gitignored and can drift in each real repo clone.
- `ai/services/github-workflow/shared/archivePath.mjs` consumes the archive config contract for path construction.
- `ai/services/github-workflow/sync/IssueSyncer.mjs`, `PullRequestSyncer.mjs`, and `DiscussionSyncer.mjs` pass archive config into archive path planning.
- Release/archive runs also route through `buildScripts/release/publish.mjs` and GitHub Workflow sync services.

Duplicate sweep notes:

- #11189 is closed and covered adding the config fields, not runtime validation of stale clone-local configs.
- #10559 is closed and covered PR author/reviewer workflow guidance, not service-level fail-loud validation.
- No open ticket found for archive config shape validation.

## The Fix

Add a narrow runtime validation path for the GitHub Workflow archive config. The implementation should validate that all three archive fields are present and structurally valid before any archive planning, sync, or release archive operation can proceed.

Recommended behavior:

- Fail loudly when any required field is missing, with an error naming the exact config key and local file surface.
- Treat the three archive fields as an all-or-nothing contract for archive operations.
- Keep clone-local value overrides legal; validate shape and type, not byte-identical template equality.
- Reuse existing config/service validation patterns where available instead of adding a broad new config framework.

## Contract Ledger Matrix

| Target Surface | Source of Authority | Proposed Behavior | Fallback | Docs | Evidence |
|---|---|---|---|---|---|
| GitHub Workflow archive config shape | Epic #11187 + #11189 + this ticket | Archive operations require `archiveRoot`, `archiveChunkThreshold`, and `archiveChunkPrefix` to be present and valid | Abort before archive planning with operator-actionable error | Inline JSDoc/error text; reference #10559 for clone-local sync guidance | Unit or targeted smoke test with one missing field |
| Clone-local `config.mjs` drift handling | #10559 + 2026-05-13 recovery | Local overrides allowed; missing required archive keys fail loudly | Manual sync from template | Existing PR workflow guide remains author/reviewer layer | Reproducer fixture or temporary config object test |

## Acceptance Criteria

- [ ] GitHub Workflow archive operations validate `issueSync.archiveRoot`, `issueSync.archiveChunkThreshold`, and `issueSync.archiveChunkPrefix` before archive path planning proceeds.
- [ ] Missing `archiveRoot` fails loudly with an error naming `issueSync.archiveRoot`.
- [ ] Missing `archiveChunkThreshold` fails loudly with an error naming `issueSync.archiveChunkThreshold`.
- [ ] Missing `archiveChunkPrefix` fails loudly with an error naming `issueSync.archiveChunkPrefix`.
- [ ] Validation distinguishes required key presence/type from clone-local value equality; operator-specific local config values remain supported.
- [ ] Targeted test coverage exercises the partial-patch state observed on 2026-05-13: `archiveRoot` present, chunk threshold/prefix missing.
- [ ] PR body documents the local manual sync evidence for all three active agent clones, or explains why runtime validation makes a manual sync gap non-blocking.

## Out of Scope

- Committing any `config.mjs` file.
- Forcing byte-identical local configs across clones.
- Replacing the #10559 PR workflow guidance.
- Implementing the actual archive data migration.
- Changing archive path semantics beyond fail-loud validation.

## Avoided Traps

- **Template-only confidence.** Rejected because runtime servers read gitignored `config.mjs`, not only the tracked template.
- **Byte-identical config policing.** Rejected because clone-local config values can legitimately differ; the invariant is required key presence and valid type.
- **Silent fallback defaults.** Rejected for archive paths because defaults can hide a stale clone and create inconsistent corpus layout.
- **Broad config framework extraction.** Rejected unless implementation evidence shows multiple validators need the same abstraction.

## Related

- Epic #11187
- #11189 — initial archive config fields
- #10559 — PR workflow guard for MCP config template changes across three clones
- PR #11282 — MetadataManager pruning prerequisite for archive planning
- `ai/mcp/server/github-workflow/config.template.mjs`
- `ai/services/github-workflow/shared/archivePath.mjs`

Origin Session ID: d6d89930-f408-42a0-b60e-ec4487a8cc46

Handoff Retrieval Hints:

- `query_raw_memories(query="B0a clone-local config sync archiveChunkThreshold archiveChunkPrefix partial patch")`
- `ask_knowledge_base(query="GitHub Workflow archive config validation archiveRoot archiveChunkThreshold archiveChunkPrefix")`
- A2A anchors: `MESSAGE:64642b5e-6f33-4293-ae3b-76899ec71702`, `MESSAGE:4133e07c-5ef1-44c6-b3dd-f316734da5a9`

## Timeline

- 2026-05-13T07:43:28Z @neo-gpt added the `enhancement` label
- 2026-05-13T07:43:28Z @neo-gpt added the `ai` label
- 2026-05-13T07:43:28Z @neo-gpt added the `architecture` label
- 2026-05-13T07:43:28Z @neo-gpt added the `build` label
- 2026-05-13T07:44:57Z @neo-gpt added parent issue #11187
- 2026-05-13T08:26:36Z @neo-opus-ada cross-referenced by PR #11296
- 2026-05-13T10:22:16Z @neo-opus-ada assigned to @neo-opus-ada
- 2026-05-13T10:28:29Z @neo-opus-ada cross-referenced by PR #11297
- 2026-05-13T10:42:36Z @neo-opus-ada referenced in commit `d3cab5d` - "fix(github-workflow): consume validated archive chunk fields in path planning (#11290)

GPT Cycle 1 RA addressed: previously the B0a validator required
archiveChunkThreshold + archiveChunkPrefix in runtime config but archivePath()
still used DEFAULT_ARCHIVE_MAX_ITEMS_PER_DIR (100) + hardcoded 'chunk-' prefix.
Clones with non-default valid overrides would pass validation while still
emitting template-default paths — theatrical validation.

Substrate-correct fix:
- archivePath() now reads archiveChunkThreshold + archiveChunkPrefix from config
- Precedence: archiveChunkThreshold > legacy maxItemsPerDir > DEFAULT (100)
- archiveChunkPrefix defaults to DEFAULT_ARCHIVE_CHUNK_PREFIX ('chunk-')
- All 3 syncer call sites (Issue/PullRequest/DiscussionSyncer) now pass the
  config fields to archivePath()
- Added DEFAULT_ARCHIVE_CHUNK_PREFIX export for shared default

Test coverage: 7 new tests covering non-default overrides, precedence, fallbacks,
and rejecting invalid prefixes with path separators. Local: 24/24 ArchivePath
+ 98/98 across full github-workflow service suite — no regression.

Backward-compat: maxItemsPerDir parameter retained as legacy alias; existing
callers passing only maxItemsPerDir still work."
- 2026-05-13T12:59:18Z @tobiu referenced in commit `86ec2e6` - "feat(github-workflow): fail loudly on stale archive config in syncer entry points (#11290) (#11297)

* feat(github-workflow): fail loudly on stale archive config in syncer entry points (#11290)

Implements B0a of Epic #11187 — runtime validation of the archive substrate config
contract that prevents the silent partial-patch state observed 2026-05-13 on the
Claude main checkout (archiveRoot present, archiveChunkThreshold +
archiveChunkPrefix missing).

- Adds validateArchiveConfig(issueSyncConfig) export to archivePath.mjs
- Validates 3 required fields: archiveRoot, archiveChunkThreshold, archiveChunkPrefix
- Type-checks: non-empty string / positive integer / non-empty string
- Aggregates errors into single operator-actionable throw naming config.mjs surface
- Wired into all 3 syncer entry points: IssueSyncer/PullRequestSyncer/
  DiscussionSyncer #planArchiveBuckets() — fires before any archive path planning
- 11 new unit tests in ArchivePath.spec.mjs covering: valid config / each missing
  field / partial-patch state reproduction / type validation / null-graceful /
  error-message-operator-actionability

Substrate-pattern: clone-local value overrides remain legal (per ticket OoS);
validation enforces presence + type, not byte-identical template equality.
Reuses existing archivePath.mjs surface; no broad new config framework.

V-B-A: 91/91 pass across test/playwright/unit/ai/services/github-workflow/ —
no regression in sibling test suites.

* fix(github-workflow): consume validated archive chunk fields in path planning (#11290)

GPT Cycle 1 RA addressed: previously the B0a validator required
archiveChunkThreshold + archiveChunkPrefix in runtime config but archivePath()
still used DEFAULT_ARCHIVE_MAX_ITEMS_PER_DIR (100) + hardcoded 'chunk-' prefix.
Clones with non-default valid overrides would pass validation while still
emitting template-default paths — theatrical validation.

Substrate-correct fix:
- archivePath() now reads archiveChunkThreshold + archiveChunkPrefix from config
- Precedence: archiveChunkThreshold > legacy maxItemsPerDir > DEFAULT (100)
- archiveChunkPrefix defaults to DEFAULT_ARCHIVE_CHUNK_PREFIX ('chunk-')
- All 3 syncer call sites (Issue/PullRequest/DiscussionSyncer) now pass the
  config fields to archivePath()
- Added DEFAULT_ARCHIVE_CHUNK_PREFIX export for shared default

Test coverage: 7 new tests covering non-default overrides, precedence, fallbacks,
and rejecting invalid prefixes with path separators. Local: 24/24 ArchivePath
+ 98/98 across full github-workflow service suite — no regression.

Backward-compat: maxItemsPerDir parameter retained as legacy alias; existing
callers passing only maxItemsPerDir still work.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-13T12:59:19Z @tobiu closed this issue
- 2026-05-14T11:36:30Z @neo-opus-ada cross-referenced by #11187

