Context
This ticket exists because the post-#11581 hook guidance and implementation still do not match Neo's production sync reality. The operator corrected the premise on 2026-05-18: .github/workflows/data-sync-pipeline.yml commits directly to dev, and package.json exposes ai:sync-github-workflow as the operator-run GitHub workflow sync path. Routing generated sync payloads through feature branches / PR review is wrong for this class of automation.
The Problem
The current buildScripts/util/check-chore-sync.mjs guard protects feature branches from generated sync-data leakage, but it over-corrects the automation path:
check-chore-sync.mjs currently derives gitRoot from the invocation cwd and then rejects cwd/root mismatch (buildScripts/util/check-chore-sync.mjs:7-25). That is brittle for harnesses/scripts that invoke the Neo hook from another process root. The hook should anchor to the repo that owns the hook/script, then run git commands in that root.
- The sanctioned
NEO_SYNC_AUTOCOMMIT=1 bypass only treats resources/content/issues/ and resources/content/discussions/ as sync data (buildScripts/util/check-chore-sync.mjs:56-66). But GH_SyncService.runFullSync() stages all of resources/content before committing (ai/services/github-workflow/SyncService.mjs:153-169). The generated GitHub workflow corpus also includes pulls/, release-notes/, archive/, _index.json, and .sync-metadata.json.
- The previous manual advice to use a
chore/sync-* feature branch was incorrect for the automated pipeline. That branch convention is a manual escape hatch for human-staged data, not the normal sync path.
The Architectural Reality
Neo has two direct-to-dev generated-data automation surfaces that must remain unblocked:
.github/workflows/data-sync-pipeline.yml:61-75 configures a GitHub Actions job with contents: write and commits generated DevIndex / portal data directly back to dev with [skip ci].
package.json:40 exposes ai:sync-github-workflow, which runs buildScripts/ai/syncGithubWorkflow.mjs and delegates to GH_SyncService.runFullSync().
SyncService already has the intended guard shape: when pushToRepoAfterSync is enabled, it stages resources/content, commits with NEO_SYNC_AUTOCOMMIT=1, rebases/autostashes, and pushes (ai/services/github-workflow/SyncService.mjs:146-171). The hook must validate that payload, not route it through PR review.
The correct distinction is therefore:
| Surface |
Expected behavior |
| Human/agent feature branch with generated sync files staged |
Reject unless explicitly on a sync-designated manual branch or bypassed knowingly |
Sanctioned automation with NEO_SYNC_AUTOCOMMIT=1 |
Allow direct-to-dev commit only if every staged path is generated GitHub workflow content |
| Data-sync pipeline generated app/portal data |
Continue direct-to-dev pipeline behavior |
| Mixed source-code + sync-data staging under automation env |
Reject |
The Fix
Update the pre-commit guard and tests:
- Resolve the protected repo root from the script/hook location, not from arbitrary
process.cwd().
- Remove the hard cwd/root mismatch rejection as the policy primitive; use script-root anchoring for git commands instead.
- Replace the narrow
issues/ + discussions/ sync-data allowlist with a generated GitHub workflow content predicate covering the actual resources/content emitters: issues/, discussions/, pulls/, release-notes/, archive/, legacy issue-archive/, legacy pr-archive/, _index.json, and .sync-metadata.json.
- Keep the mixed-payload rejection for
NEO_SYNC_AUTOCOMMIT=1 so automation cannot smuggle source edits.
- Update
check-chore-sync tests to cover direct-to-dev automation, full resources/content payloads, mixed-payload rejection, and invocation from a non-repo cwd.
Acceptance Criteria
Out of Scope
- Changing
.github/workflows/data-sync-pipeline.yml direct-to-dev behavior.
- Replacing
GH_SyncService.runFullSync() or changing its commit message.
- Reworking branch protection or human merge policy.
- Broad redesign of generated content storage.
Avoided Traps
- PR branch for automated sync: rejected. It would put routine generated corpus updates through review, which contradicts existing direct-to-
dev automation and would create review noise.
- Blind
--no-verify: rejected. It bypasses the feature-branch leakage guard instead of preserving the guard with the right automation exception.
- Allow all
resources/content/**: rejected for now. resources/content/concepts/ and stale handoff artifacts are not part of the GitHub workflow generated corpus proven in this incident.
Related
- Follow-up to #11580 / PR #11581.
- Related broad guardrail context: #11115.
- Operator correction: 2026-05-18 direct-to-
dev automation path for .github/workflows/data-sync-pipeline.yml and ai:sync-github-workflow.
Origin Session ID
8591bc48-0ddc-48bf-aa47-58e53ea81a57
Handoff Retrieval Hints
query_raw_memories(query="check-chore-sync NEO_SYNC_AUTOCOMMIT direct dev ai:sync-github-workflow feature branch wrong")
rg -n "NEO_SYNC_AUTOCOMMIT|check-chore-sync|ai:sync-github-workflow|data-sync-pipeline" buildScripts ai .github package.json
Context
This ticket exists because the post-#11581 hook guidance and implementation still do not match Neo's production sync reality. The operator corrected the premise on 2026-05-18:
.github/workflows/data-sync-pipeline.ymlcommits directly todev, andpackage.jsonexposesai:sync-github-workflowas the operator-run GitHub workflow sync path. Routing generated sync payloads through feature branches / PR review is wrong for this class of automation.The Problem
The current
buildScripts/util/check-chore-sync.mjsguard protects feature branches from generated sync-data leakage, but it over-corrects the automation path:check-chore-sync.mjscurrently derivesgitRootfrom the invocation cwd and then rejects cwd/root mismatch (buildScripts/util/check-chore-sync.mjs:7-25). That is brittle for harnesses/scripts that invoke the Neo hook from another process root. The hook should anchor to the repo that owns the hook/script, then run git commands in that root.NEO_SYNC_AUTOCOMMIT=1bypass only treatsresources/content/issues/andresources/content/discussions/as sync data (buildScripts/util/check-chore-sync.mjs:56-66). ButGH_SyncService.runFullSync()stages all ofresources/contentbefore committing (ai/services/github-workflow/SyncService.mjs:153-169). The generated GitHub workflow corpus also includespulls/,release-notes/,archive/,_index.json, and.sync-metadata.json.chore/sync-*feature branch was incorrect for the automated pipeline. That branch convention is a manual escape hatch for human-staged data, not the normal sync path.The Architectural Reality
Neo has two direct-to-
devgenerated-data automation surfaces that must remain unblocked:.github/workflows/data-sync-pipeline.yml:61-75configures a GitHub Actions job withcontents: writeand commits generated DevIndex / portal data directly back todevwith[skip ci].package.json:40exposesai:sync-github-workflow, which runsbuildScripts/ai/syncGithubWorkflow.mjsand delegates toGH_SyncService.runFullSync().SyncServicealready has the intended guard shape: whenpushToRepoAfterSyncis enabled, it stagesresources/content, commits withNEO_SYNC_AUTOCOMMIT=1, rebases/autostashes, and pushes (ai/services/github-workflow/SyncService.mjs:146-171). The hook must validate that payload, not route it through PR review.The correct distinction is therefore:
NEO_SYNC_AUTOCOMMIT=1devcommit only if every staged path is generated GitHub workflow contentdevpipeline behaviorThe Fix
Update the pre-commit guard and tests:
process.cwd().issues/+discussions/sync-data allowlist with a generated GitHub workflow content predicate covering the actualresources/contentemitters:issues/,discussions/,pulls/,release-notes/,archive/, legacyissue-archive/, legacypr-archive/,_index.json, and.sync-metadata.json.NEO_SYNC_AUTOCOMMIT=1so automation cannot smuggle source edits.check-chore-synctests to cover direct-to-dev automation, fullresources/contentpayloads, mixed-payload rejection, and invocation from a non-repo cwd.Acceptance Criteria
NEO_SYNC_AUTOCOMMIT=1permits a staged generated GitHub workflow payload ondevwhen all staged files are in the generated content allowlist.NEO_SYNC_AUTOCOMMIT=1rejects mixed payloads containing source/build/test files.resources/contentpayloads.chore/sync-*/agent/sync-*branches remain a human escape hatch, not the required automated path.check-chore-sync.mjspasses.Out of Scope
.github/workflows/data-sync-pipeline.ymldirect-to-devbehavior.GH_SyncService.runFullSync()or changing its commit message.Avoided Traps
devautomation and would create review noise.--no-verify: rejected. It bypasses the feature-branch leakage guard instead of preserving the guard with the right automation exception.resources/content/**: rejected for now.resources/content/concepts/and stale handoff artifacts are not part of the GitHub workflow generated corpus proven in this incident.Related
devautomation path for.github/workflows/data-sync-pipeline.ymlandai:sync-github-workflow.Origin Session ID
8591bc48-0ddc-48bf-aa47-58e53ea81a57
Handoff Retrieval Hints
query_raw_memories(query="check-chore-sync NEO_SYNC_AUTOCOMMIT direct dev ai:sync-github-workflow feature branch wrong")rg -n "NEO_SYNC_AUTOCOMMIT|check-chore-sync|ai:sync-github-workflow|data-sync-pipeline" buildScripts ai .github package.json