Skip to content

[Test] main requires only the test context with strict false and develop has no branch protection at all, so integration, build, multi-runtime, package-health and examples gate nothing on the branch where work lands #1018

Description

@pathosDev

Problem

The repository runs eleven workflows and one check can block anything. That one check is test, it is required only on main, and main is not where work lands.

Concretely, from the GitHub API:

  • main requires exactly one status context, test. strict is false, so a PR may merge against a stale base — the check that passed was run on a tree that is not the tree being merged. enforce_admins is false and required_approving_review_count is 0, so the release merge described in AGENTS.md bypasses all of it by design.
  • develop returns 404 Branch not protected. It has no required checks, no restrictions, nothing.

AGENTS.md mandates that every feature branch merges into develop locally with git merge --no-ff and no pull request. That is the only integration path in daily use, and it is entirely ungated: build, examples, integration, integration-brokers, multi-runtime, package-health, benchmarks and docs-checks all run, all report, and none of them can stop a merge. A red integration run on develop is a notification, not a gate — nothing in the repository configuration prevents the next merge, and nothing prevents cutting a release from that commit.

The one required check is also the narrowest one available. It runs with ACTOR_TS_SKIP_FLAKY_MNS=1, which quarantines the worker-thread multi-node suites and the in-process LeaseMajority end-to-end — so the required gate is specifically the configuration in which the cluster's split-brain arbitration does not execute. publish.yml sets the same variable at job level, so the prepublishOnly run that guards npm publish is quarantined identically. The multi-node path is verified by the integration workflow, which is advisory on both branches.

The net effect is that "tests are green" as a merge precondition is enforced only for main, only for the unit suite, only minus the quarantine, and only against a possibly-stale base.

Evidence

gh api repos/pathosDev/actor-ts/branches/main/protection, reduced to the fields that decide anything:

repos/pathosDev/actor-ts/branches/main/protection
{
  "required_status_checks": { "contexts": ["test"], "strict": false },
  "required_pull_request_reviews": {
    "required_approving_review_count": 0,
    "require_code_owner_reviews": false
  },
  "enforce_admins": false,
  "required_linear_history": false,
  "required_signatures": false,
  "required_conversation_resolution": false,
  "lock_branch": false
}

gh api repos/pathosDev/actor-ts/branches/develop/protection:

repos/pathosDev/actor-ts/branches/develop/protection
{
  "message": "Branch not protected",
  "documentation_url": "https://docs.github.com/rest/branches/branch-protection#get-branch-protection",
  "status": "404"
}

The integration path that everything actually travels, from the working standards:

AGENTS.md
- **`develop` is the integration branch** — all ongoing development lands
  there. …
- **Always integrate with a merge commit (`git merge --no-ff`) — never rebase,
  never fast-forward.** This holds in both directions: `features/…``develop`
  and, at release time, `develop``main`.
- **Do not push.** The agent commits locally only — on its `features/…` branch
  and when merging into `develop`; the human pushes `develop`.

The workflows that report but cannot block. Each of these defines exactly one job and runs on branch pushes and/or PRs to main/develop; none is in main's single required context, and develop has no contexts at all:

.github/workflows/
  build.yml              job: build            push '**', PR main/develop
  examples.yml           job: frontend         push '**', PR main/develop
  package-health.yml     job: package-health   push '**', PR main/develop
  benchmarks.yml         job: benchmarks       push '**', PR main/develop
  docs-checks.yml        jobs: api-drift, lockfile-sync
  multi-runtime.yml      jobs: smoke, unit-bun push develop/main, PR main/develop
  integration.yml        job: integration      push develop, PR main/develop, schedule
  integration-brokers.yml job: broker          push develop, PR main/develop, schedule

The quarantine on the one required check:

.github/workflows/test.yml:83-91
        # The worker-thread multi-node suites (ParallelMultiNodeSpec +
        # parallel-pubsub) and the in-process LeaseMajority e2e are
        # quarantined on GitHub's hosted runners — Bun there can't respawn
        # functional worker threads after the first test, which also
        # starves the lease arbitration into a false split-brain.  They
        # run locally + in Docker; the real-network `integration` workflow
        # is the multi-node CI gate.  See the [CI] tracking issue.
        env:
          ACTOR_TS_SKIP_FLAKY_MNS: '1'

and the same variable on the publish path, where it governs the bun test inside prepublishOnly:

.github/workflows/publish.yml:42-49
    # Quarantine the worker-thread multi-node suites (ParallelMultiNodeSpec +
    # LeaseMajority e2e) on GitHub's hosted runners, exactly as test.yml does —
    # Bun there can't respawn worker threads after the first test.  Set at JOB
    # level so the `bun test` inside `npm publish`'s `prepublishOnly` inherits
    # it.  Those suites run locally + in Docker; the `integration` workflow is
    # the real multi-node gate.
    env:
      ACTOR_TS_SKIP_FLAKY_MNS: '1'

integration.yml is named in both comments as "the real multi-node gate". It gates nothing — it is not a required context on either branch.

Proposal

The local-merge workflow is a deliberate choice and this issue does not ask to change it. It does ask that the branch that receives those merges be defended, and that "required" mean the set of checks whose failure would actually stop a release.

  • Protect develop. Required contexts: test, build, package-health, multi-runtime. These four are fast, deterministic, and run on every push already. With AGENTS.md's local merges, protection on develop cannot block the merge itself — it blocks the push, which is exactly the right point: a merge that breaks the build never reaches the shared branch.
  • Add integration to main's required set, or state in AGENTS.md that multi-node is verified by a scheduled run and accepted as non-blocking. The current state — two workflow comments calling it "the real gate" while the API says it is advisory — is the part that is indefensible either way.
  • Set strict: true on main. A required check that ran against a different tree is not a check.
  • Make the quarantine visible. test.yml should fail if ACTOR_TS_SKIP_FLAKY_MNS skipped a suite and no successful integration run exists for the same SHA. That converts "quarantined, covered elsewhere" from a comment into an assertion. [Test] Nightly workflow for the ACTOR_TS_SKIP_FLAKY_MNS-quarantined suites #538's nightly is the other half of this and should land with it.
  • Leave enforce_admins: false. The release merge legitimately needs it; the point is that it should be the only bypass, not one of several.

Acceptance sketch

  • gh api repos/pathosDev/actor-ts/branches/develop/protection returns a policy, not a 404.
  • develop's required contexts include test, build, package-health and multi-runtime.
  • main has strict: true, and its required set either includes integration or AGENTS.md records the explicit decision not to.
  • The workflow comments claiming integration is "the multi-node CI gate" match the API, in whichever direction is chosen.
  • A run that sets ACTOR_TS_SKIP_FLAKY_MNS=1 is not reported as a full pass without a corresponding integration result.

Verification status

Found in the ten-lens production-readiness review of 2026-08-05 (v0.13.0) and re-verified before filing: confirmed by execution — both branch-protection payloads above are verbatim gh api responses captured at verification time, and the workflow inventory is ls .github/workflows/ plus the on:/job headers of each file. No repository setting was changed.

Adjacent: #538 asks for a nightly workflow covering the ACTOR_TS_SKIP_FLAKY_MNS quarantine — it adds a run, this issue makes runs binding; neither substitutes for the other. #545 (compile and smoke-run examples/ in CI) and #816 (a Windows leg) both add workflows that, under the present configuration, would also be advisory on develop the day they merge. #541 tightens the coverage floor inside a check that is required on main only.

Part of the production-readiness review batch — tracked in #913.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginfrastructureCI / build / live-integration testspriority: highTop priority — high impact, plan nextproduction-goalBlocks or defines the path to production readiness

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions