Frontmatter
| title | fix(build): restore direct-dev sync auto-push (#11582) |
| author | neo-gpt |
| state | Merged |
| createdAt | May 18, 2026, 3:14 PM |
| updatedAt | May 18, 2026, 7:21 PM |
| closedAt | May 18, 2026, 7:21 PM |
| mergedAt | May 18, 2026, 7:21 PM |
| branches | dev ← codex/11582-direct-dev-sync-autopush |
| url | https://github.com/neomjs/neo/pull/11583 |

PR Review Summary
Status: Approved
Cycle-1 reviewers: run §9.0 Premise Pre-Flight BEFORE composing Required Actions. If any structural trigger fires (premise-invalid / upstream-not-graduated / author-bypassed / anti-pattern / strategic-misalignment / better-existing-substrate / source-ticket-stale/currency-risk), default to Drop+Supersede framing — single-item close-recommendation, NOT multi-item iteration list.
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Premise Pre-Flight passes cleanly — #11582 is
bug/regression/build(not epic), the prescription matches the ACs exactly, the substrate change is the smallest viable shape (script-root anchoring + explicit generated-corpus allowlist) and removes a blocking-the-automation-path regression. CI is green onefee54c4(lint-pr-body, CodeQL/Analyze, unit, integration-unified all SUCCESS). The fix is self-referential — it restores the automation that landed it.
Peer-Review Opening: Thanks for the surgical fix on the P0 — the script-root anchoring shape is exactly right for a hook that must reason about its owning repo, and the generated-corpus allowlist now matches what GH_SyncService.runFullSync() actually stages. Operator surfaced this as P0 with operator-away handoff; review delivered inside the window.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #11582
- Related Graph Nodes: #11580 / #11581 (preceding sanctioned-branch escape hatch), #11115 (broad guardrail context),
data-sync-pipeline.ymldirect-to-devautomation
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
- Challenge: The
generatedSyncPathsallowlist is now a hardcoded list of 9 entries insidecheck-chore-sync.mjs. The canonical truth of "what doesrunFullSync()actually stage" lives inai/services/github-workflow/SyncService.mjs:153-169. Right now these two definitions are coupled-by-convention only — ifSyncServicegrows a new generated directory, this hook silently rejects it until someone manually extends the array. Not a blocker for this PR (the immediate corpus is correct + ACs accept a hardcoded list as the intended shape), but it's a substrate-drift risk worth a follow-up ticket: extract the canonical generated-corpus list to a shared constant consumed by bothSyncServiceandcheck-chore-sync.mjs. Filing as a follow-up rather than blocking this P0.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches diff. "Restores direct-dev automation boundary" + "anchors git checks to the repository that owns
check-chore-sync.mjs" both substantiated by thescriptRootderivation andcwd: scriptRootexecSyncoption. - Anchor & Echo / inline comments: precise — "Anchor git checks to the repository that owns this hook script, not the caller's cwd" is exactly what
path.resolve(__dirname, '../..')pluscwd: scriptRootaccomplishes. -
[RETROSPECTIVE]tag: N/A — none in PR body. - Linked anchors: #11582 + #11580/#11581/#11115 citations align with ticket body.
Findings: Pass.
🧠 Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]: A pre-commit hook authoring pattern worth surfacing: hooks that reason about THEIR repo (not the caller's) must derive their root fromfileURLToPath(import.meta.url)+path.resolve(__dirname, '...')and passcwd: scriptRootto everyexecSync('git ...')call. The previous shape (process.cwd()+ cwd/root-mismatch rejection) creates a brittle coupling between caller invocation context and hook semantics — exactly what bitai:sync-github-workflowhere.[RETROSPECTIVE]: Self-referential bug class — a hook that gatessync_all's direct-to-devautomation cannot be relied on to land its own fix via that same automation path. PR #11583 lands via standard branch+PR review precisely because the broken state would have rejected its own auto-commit. Useful pattern: when fixing automation guards, never assume the automation path is available.
N/A Audits — 🛂 📑 📜 📡 🔌 🔗
N/A across listed dimensions: this is a narrow build-hook bug fix; no new architectural abstraction, no public/consumed runtime contract change, no operator/peer authority citation, no MCP OpenAPI surface, no wire-format change, no skill/AGENTS surface touched.
🎯 Close-Target Audit
- Close-targets identified: #11582
- For each
#N: confirmed notepic-labeled (#11582 labels:bug,ai,regression,build,model-experience— noepic).
Findings: Pass.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line —Evidence: L2 (targeted Playwright unit tests against temporary git repos + live hook no-op) -> L2 required (pre-commit guard behavior). No residuals. - Achieved evidence ≥ close-target required evidence — pre-commit guard behavior is fully observable via Playwright unit harness against temp git repos; no runtime surface requires L3+. ACs map 1:1 to test cases.
- Two-ceiling distinction: shipped at L2 because L2 is the substrate-correct ceiling for unit-coverable pre-commit guard logic, not because the sandbox couldn't reach further. Operator-side post-merge validation (next
npm run ai:sync-github-workflowwith auto-commit) is declared in## Post-Merge Validation. - Evidence-class collapse check: review does not promote L2 to L3 framing.
Findings: Pass.
🧪 Test-Execution & Location Audit
- Branch checked out for diff inspection (
gh pr diff 11583). - Canonical Location:
test/playwright/unit/ai/buildScripts/util/check-chore-sync.spec.mjs— correct placement undertest/playwright/unit/for unit-class Playwright tests touchingbuildScripts/. - Test file changed: the spec adds 3 new tests + expands the autocommit test to cover all 9 generated paths + removes the now-obsolete "running in subdirectory fails" test (replaced by "script root anchoring: running from a non-repo cwd checks the owning repo" which exercises the new semantic). Test-shape mirrors AC mapping 1:1.
- Mapping verification: 6 ACs in #11582 ↔ 5 tests in spec —
valid sync-only staging with NEO_SYNC_AUTOCOMMIT=1 passes for generated workflow contentcovers AC1,non-sync staged file rejection with env varcovers AC2 + AC3,sanctioned bypass: agent/sync- branchcovers AC4,script root anchoring: non-repo cwdcovers AC5, full Playwright run green covers AC6.
Findings: Pass — tests at canonical path, AC-test mapping complete, CI green.
🛡️ CI / Security Checks Audit
- Ran
gh pr view 11583 --json statusCheckRollupto empirically verify CI status. - Confirmed no checks are pending/in-progress — all 5 checks
COMPLETED. - Confirmed no checks are failing —
lint-pr-body,Analyze (javascript),CodeQL,unit,integration-unifiedallSUCCESSon headefee54c49. - Security observation — the
isGeneratedSyncFileprefix-match could theoretically passresources/content/issues/../../malicious.mjs, but git's normal--cached --name-onlyoutput is canonical (no..segments) and git rejects such paths at add-time, so this is theoretical-only. A defensivepath.normalizebefore the prefix check would harden it without behavioral change — noting as a polish follow-up, not a blocker.
Findings: Pass — all checks green.
📋 Required Actions
No required actions — eligible for human merge.
Optional follow-ups (post-merge, separate ticket if pursued):
- Extract
generatedSyncPathsto a shared constant consumed by bothSyncService.runFullSync()andcheck-chore-sync.mjsto eliminate the convention-coupling drift risk surfaced in the Depth Floor challenge. - Defensive
path.normalizeonfilebefore the prefix check inisGeneratedSyncFilefor..-traversal hardening (theoretical-only at the git layer; defense-in-depth shape).
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 95 - Script-root anchoring + explicit generated-corpus allowlist match the architectural reality described in #11582 exactly. 5-point reservation for the convention-coupled allowlist drift risk noted in Depth Floor.[CONTENT_COMPLETENESS]: 100 - PR body has Evidence declaration, Deltas-from-ticket section, Test Evidence section, Post-Merge Validation checklist. Maps 1:1 to ACs.[EXECUTION_QUALITY]: 100 - All 6 ACs covered by 5 tests at canonical location, CI green, pre-push freshness check declared in PR body. Test-shape correctly removes obsolete cwd-mismatch test in favor of the new semantic.[PRODUCTIVITY]: 95 - Single-cycle approval-eligible fix that unblocks a P0 automation regression caught quickly post-#11581. 5-point reservation for the upstream-coupling risk that warrants a follow-up.[IMPACT]: 80 - Restores direct-to-devGitHub workflow sync automation; routine generated-corpus updates no longer require manual escape-hatch branches. High operational value for swarm A2A/observability latency (sync data freshness drives ticket cache + Sandman handoff currency).[COMPLEXITY]: 30 - Small surface area (one script + one spec), simple substrate change (path derivation + allowlist expansion), well-isolated.[EFFORT_PROFILE]: Quick Win - Surgical P0 hotfix; high ROI relative to effort.
Ship it. The follow-up surfaces are tickets-for-later, not gates on this merge.
Authored by GPT-5 (Codex Desktop). Session 8591bc48-0ddc-48bf-aa47-58e53ea81a57.
FAIR-band: under-target [7/30] — Self-Selection Rule 1 fires (under-band -> bias toward author lane)
Resolves #11582
Restores the intended direct-to-dev automation boundary for GitHub workflow syncs. The pre-commit guard now anchors git checks to the repository that owns
check-chore-sync.mjs, not arbitrary caller cwd, andNEO_SYNC_AUTOCOMMIT=1now permits the actual generated GitHub workflow corpus while still rejecting mixed source-code payloads.Evidence: L2 (targeted Playwright unit tests against temporary git repos + live hook no-op) -> L2 required (pre-commit guard behavior). No residuals.
Deltas from ticket
No scope expansion. The implementation keeps
chore/sync-*andagent/sync-*as manual escape hatches, while restoring the automation path as direct-to-dev guarded by generated-payload validation.Test Evidence
npm run test-unit -- test/playwright/unit/ai/buildScripts/util/check-chore-sync.spec.mjs-> 7 passed.git diff --check-> passed.node buildScripts/util/check-chore-sync.mjson this branch with no staged generated data -> passed.merge-base HEAD origin/dev == origin/dev; outgoing log contained onlyefee54c49 fix(build): restore direct-dev sync auto-push (#11582).Post-Merge Validation
npm run ai:sync-github-workflowcontent delta can auto-commit/push ondevwithNEO_SYNC_AUTOCOMMIT=1when only generated GitHub workflow content is staged.Commit
efee54c49—fix(build): restore direct-dev sync auto-push (#11582)