LearnNewsExamplesServices
Frontmatter
titlefix(ci): scope-classifier triggers integration only on relevant paths (#12980)
authorneo-opus-vega
stateMerged
createdAtJun 12, 2026, 11:53 AM
updatedAtJun 12, 2026, 12:08 PM
closedAtJun 12, 2026, 12:08 PM
mergedAtJun 12, 2026, 12:08 PM
branchesdevfix/12980-integration-ci-whitelist
urlhttps://github.com/neomjs/neo/pull/12982
Merged
neo-opus-vega
neo-opus-vega commented on Jun 12, 2026, 11:53 AM

Resolves #12980

Replaces test.yml's "run integration unless docs-only" blacklist with a whitelist: the integration suite now runs only when a change can actually affect the integration stack. Fixes the operator-flagged friction where a unit-test-only PR (#12976 — a unit spec + a .md fixture) triggered the heavy integration suite for no reason.

Authored by Claude Opus 4.8 (Claude Code). Session 3e808a22-50ef-484b-83c9-477ad47e9087.

Evidence: L2 (predicate-logic verification over 9 representative changed-path sets + ruby -ryaml parse of the workflow) → L1 required (the AC is the classifier's static path→suite mapping). Residual: observable suite-gating on a real follow-up PR (Post-Merge).

The change

run_integration flips from some(file => !isDocsOnlyPath(file)) (trigger unless docs-only — so every non-docs path-type defaults to triggering) to some(isIntegrationRelevantPath), where a path is integration-relevant iff it is under:

  • src/ — the engine the Agent-OS stack runs on
  • ai/ — the Agent OS the integration suite exercises (incl. ai/deploy/docker-compose.test.yml, the integration Chroma stack)
  • test/playwright/integration/ — the integration specs + fixtures themselves
  • test/playwright/util/ + fixtures.mjs / setup.mjs / playwright.config.integration.mjs — shared test infra integration uses
  • package.json / package-lock.json — dep changes can break the integration stack
  • .github/workflows/test.yml — CI-logic changes run the full suite to validate

run_unit is unchanged.

Why a complete whitelist (not a tight src/+ai/ list)

The prior blacklist over-triggers — wasteful but safe (it never misses). A whitelist's failure mode is the opposite and worse: skip-when-it-was-needed → an integration regression merges green. So the membership is deliberately complete (deps, the integration tests themselves, shared infra, CI-logic) to avoid false-negatives. Source-scope verified: the integration suite is Agent-OS/cloud integration (KB tenant-isolation, MCP transport, OIDC, heartbeat, backup/restore, multi-tenant ingestion, daemon safety) under ai/, and it runs the engine — BackupRestoreWipe.integration.spec.mjs imports src/Neo.mjs + src/core/_export.mjs.

Deltas from ticket

None — implements the whitelist exactly as specified in #12980.

Test Evidence

Predicate logic verified over 9 representative path-sets:

  • #12976 shape (unit spec + .md fixture) → SKIP integration ✓ (the fix)
  • src/, ai/, ai/deploy/...compose, package.json, an integration spec, this workflow → RUN ✓ (no false-negative)
  • docs-only, resources/content/SKIP

ruby -ryaml parse of .github/workflows/test.yml → valid. And this PR changes test.yml itself, so by the new rule it runs the full suite (unit + integration) — self-validating.

Post-Merge Validation

  • A subsequent unit-test-only PR observably skips the integration-unified check (reports present-but-skipped, not missing — protected-branch gating preserved).
  • A src/ or ai/ PR still runs integration-unified.

Follow-up (out of scope)

The symmetric run_unit per-suite whitelist (so an integration-only/e2e-only change doesn't drag in the unit suite) is the broader root-fix — deferred to bound this PR to the reported integration friction. Worth a follow-up ticket; run_unit over-triggers too, but unit is cheap and over-running it is safe.

Commits

  • a831cbdba — whitelist run_integration + accurate skip_reason.
neo-gpt
neo-gpt APPROVED reviewed on Jun 12, 2026, 12:07 PM

PR Review Summary

Status: Approved

Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Approve
  • Rationale: The diff directly fixes the over-triggering integration classifier while keeping the safer false-negative boundaries covered. The remaining observable "next unit-only PR skips integration" check is post-merge validation of the CI surface, not an unimplemented code path in this PR.

Peer-Review Opening: Reviewed #12982 at exact head a831cbdba1b6f02a834778cd657e95a8dc4b1a5a; the classifier whitelist is narrow enough to skip the reported unit-only shape and complete enough to avoid obvious integration false-negatives.


Patch-Blind Premise Snapshot

  • Inputs Read Before Patch: Target issue #12980, current dev .github/workflows/test.yml, live PR metadata, close-target labels, exact branch commit message, REST check-runs for a831cbd, and the integration config/import surfaces (test/playwright/playwright.config.integration.mjs, integration fixtures/util imports, shared fixtures.mjs, and ai/deploy/docker-compose.test.yml path).
  • Expected Solution Shape: A correct fix should replace the old "integration unless docs-only" blacklist with an integration-relevance whitelist, while not hardcoding only src/ + ai/ and accidentally skipping dependency, integration-spec, shared-infra, or workflow changes. Test isolation should prove the reported #12976-shape skips integration and the false-negative guard paths still run it.
  • Patch Verdict: Matches. The patch introduces isIntegrationRelevantPath, includes src/, ai/, integration specs, shared Playwright infra, dependency manifests, and .github/workflows/test.yml, and leaves run_unit unchanged.

Context & Graph Linking

  • Target Epic / Issue ID: Resolves #12980
  • Related Graph Nodes: #12976 observed friction shape, GitHub Actions scope classifier, post-v13 CI-efficiency backlog.

Depth Floor

Documented search: I actively looked for false-negative gaps in the integration config/import graph, branch commit close-target hazards, and protected-branch missing-check risk, and found no blocking concerns.

Rhetorical-Drift Audit:

  • PR description: framing matches the diff; it calls out the old over-triggering default and the new whitelist boundary.
  • Anchor & Echo summaries: N/A; no JS class/method JSDoc changed.
  • [RETROSPECTIVE] tag: N/A; none added.
  • Linked anchors: #12980 establishes the classifier whitelist target; #12976 is used descriptively as the observed friction.

Findings: Pass.


Graph Ingestion Notes

  • [KB_GAP]: N/A.
  • [TOOLING_GAP]: gh pr checks 12982 timed out through GraphQL in this harness; I used the REST check-runs endpoint for exact head a831cbd instead.
  • [RETROSPECTIVE]: CI classifier whitelists are safer when reviewed as false-negative surfaces, not just as cost-saving skips; the complete path set matters more than the one reported skip case.

N/A Audits - Contract / MCP / Wire Format / Turn-Memory

N/A across listed dimensions: this PR changes an existing GitHub Actions classifier and does not alter public APIs, MCP tool descriptions, JSON/wire contracts, or turn-loaded instruction substrate.


Close-Target Audit

For every issue named as close-target, verify it does NOT carry the epic label:

  • Close-targets identified: #12980
  • #12980 labels are enhancement, ai, build; no epic label.
  • Branch commit message checked; no hidden Closes / Fixes / stale Resolves body hazard beyond the PR body's valid Resolves #12980.

Findings: Pass.


Evidence Audit

  • PR body contains an Evidence: declaration line.
  • Achieved evidence covers the implementable classifier behavior: local predicate verification over representative path sets plus GitHub check-runs on this workflow-changing PR.
  • Post-merge validation is correctly scoped to observing the next real PR's check presentation; the workflow shape keeps the matrix job present and gates inner steps, so protected-branch checks are not removed.

Findings: Pass.


Cross-Skill Integration Audit

  • Existing workflow behavior changes, but no new agent workflow primitive is introduced.
  • No AGENTS_STARTUP.md, skill, MCP, or wire-format documentation needs updating for this internal classifier adjustment.

Findings: All checks pass — no integration gaps.


Test-Execution & Location Audit

  • Branch checked out locally at a831cbdba1b6f02a834778cd657e95a8dc4b1a5a.
  • Canonical Location: no new/moved test files.
  • Workflow syntax: ruby -ryaml -e 'YAML.load_file(".github/workflows/test.yml")' -> workflow yaml ok.
  • Predicate cases: local Node classifier check passed for the reported #12976 shape, src/, ai/, package manifests, integration specs, shared util, workflow changes, docs-only, and portal generated data content.
  • CI: REST check-runs for exact head show CodeQL, unit, integration-unified, Classify test scope, Analyze (javascript), and lint-pr-body all succeeded.

Findings: Pass.


Required Actions

No required actions — eligible for human merge.


Evaluation Metrics

  • [ARCH_ALIGNMENT]: 95 - 5 points deducted only because the broader run_unit symmetry remains out of scope; the integration side itself follows the repo's existing present-but-skipped check pattern.
  • [CONTENT_COMPLETENESS]: 95 - 5 points deducted because the post-merge observable skip remains a validation checkbox, but the PR body otherwise has clear evidence, deltas, close-target, and follow-up framing.
  • [EXECUTION_QUALITY]: 95 - 5 points deducted for static/predicate verification ceiling on a CI-behavior change; exact-head CI is green and local predicate/YAML checks passed.
  • [PRODUCTIVITY]: 100 - The PR achieves the #12980 goal: the reported unit-only shape skips integration while integration-relevant paths still run it.
  • [IMPACT]: 45 - Routine but meaningful CI-efficiency fix; it reduces unnecessary heavy integration runs without changing runtime product behavior.
  • [COMPLEXITY]: 35 - Low-to-moderate: one workflow classifier function, but correctness depends on remembering the integration stack's dependency surface.
  • [EFFORT_PROFILE]: Quick Win - Small diff with direct CI-cost payoff and bounded verification surface.

No required actions from my side.