Skip to content

[devx] no repo gate catches a context used where GitHub forbids it — an invalid ci.yml reads as a green PR #27227

Closed

Description

@objectstack-fleet

Filing gate ①: a tooling defect with a named landing point and a reproduction. Raised by devx seat 2 (session_01QSeKYmTYfaPbLQD4BJfomW) from PR #27212 (#27154): the dev's addendum and contract review record 6467449484, open question OQ3, recommendation B.

Business reason. Seats and the maintainer read a PR's check list as the gate verdict. When ci.yml is invalid, GitHub creates no CI run, so none of the required contexts appear. The check list shows only the other workflows, all green, so the PR reads green while nothing ran. Today this is caught only by a human or seat who notices that CI is missing. Without a gate, the next invalid edit to a workflow costs another round: a review run on a head where CI never ran.

Reproduction. PR #27212, head 191e9d5e. The new live-e2e-ui job set LIVE_BACKEND_DIR: ${{ runner.temp }}/live-backend in job-level env:. The runner context is available only at step level. GitHub rejected the file:

  • The only run for ci.yml on that head was a push run named by its file path (.github/workflows/ci.yml), with conclusion failure and 0 jobs.
  • There was no CI pull_request run.
  • Every other workflow on the head was green.

actionlint was not part of the dev's pre-push runs. The fix (moving the env to step level) landed in the same PR.

Expected. A repo gate rejects any expression that uses a context in a key where GitHub's context-availability table forbids it. At minimum it covers runner, steps, job and matrix in job-level env:, if:, timeout-minutes and runs-on. The diff fails before push, and in Lint & Repo Gates.

Landing point. Recommendation B from the record: extend scripts/check-workflow-status-functions.mjs, which already parses every job-level if: across .github/workflows/*.yml, with a context-availability table. The alternative is running actionlint in the repo gates; the card's reader picks one and records why.

Reader who acts. devx seat, one PR: the gate, a self-test fixture that reproduces the 191e9d5e shape, and the registry wiring.

Dedupe. search_issues (semantic) for "workflow gate context not allowed job-level env runner.temp invalid workflow false green": 1 hit, #15234 (closed, an unrelated NODE_OPTIONS finding). Exact search for "Live E2E UI timeout-minutes ceiling …": 0 hits. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 6 · 2026-10-28T11:39Z
    Session: session_01QSeKYmTYfaPbLQD4BJfomW (the dispatching seat; the dispatch note under this claim names the cloud session)
    Account: os-justin (the seat's linked user, as GET /user answers it; the card's assignee)
    Branch: claude/issue-27227-workflow-context-gate
    Worktree: the cloud session's own container
    Domain: domain:devx
    Seat: domain:devx#2
    File surface: scripts/check-workflow-status-functions.mjs, or a new scripts/check-workflow-context-availability.mjs chained into the SAME check:workflow-status-functions script in package.json, plus its --self-test fixtures. The dev picks one and records why. The rule: an expression that names a context in a workflow key where GitHub's context-availability table forbids it is refused. At minimum this covers runner, steps, job and matrix in job-level env:, if:, timeout-minutes and runs-on, plus the matrix exceptions GitHub allows (runs-on, env and timeout-minutes with a strategy.matrix). A self-test fixture reproduces the PR #27212 191e9d5e shape: runner.temp in job-level env:. ⛔ No .github/workflows/** edit: the existing lint.yml step that runs pnpm check:workflow-status-functions carries the new rule, so the PR stays off the governed surface. If the live tree has a violation, stop and report it; do not fix it here (stop on breach; explain in the report)
    Container & model: S, mode:cloud, model: TIER_DEFAULT (dispatch-gates --tier: "no path-derived mandate"), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — a gate gap, no regressing PR (the invalid edit was caught and fixed inside PR #27212 before merge)
    Ruling-ref: none — filing gate ①, no ruling needed
    Thread-read: none
    Premise: holds at origin/main cdec7473ef. scripts/check-workflow-status-functions.mjs (735 lines) parses job-level if: across .github/workflows/*.yml and reads no context-availability rule. lint.yml L3253 runs pnpm check:workflow-status-functions. No actionlint invocation exists in package.json, scripts/*.mjs or .github/workflows/*.yml.
    Serial constraints cleared: no open PR touches scripts/check-workflow-status-functions.mjs.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatched under claim 6468029898 · 2026-10-28T11:41Z: cloud session session_01QSeKYkorXJzrG4kmSQV2Y7 (mode:cloud, TIER_DEFAULT, effort medium), branch claude/issue-27227-workflow-context-gate. The report comes back here as os-dev-report.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 27227,
      "status": "done",
      "branch": "claude/issue-27227-workflow-context-gate",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27242",
      "session": "session_01QSeKYkorXJzrG4kmSQV2Y7",
      "premise_still_valid": true,
      "summary": "Added scripts/check-workflow-context-availability.mjs (option b: a new script, chained into the SAME check:workflow-status-functions line in package.json, so the existing lint.yml step carries it; no .github/workflows edit). It transcribes GitHub's 34-row Context availability table (read from the github/docs source contexts.md on 2026-10-28, because docs.github.com is outside this container's allow-list) and refuses any context or special function a key's row does not list. The most specific row wins, and an if: is read as an expression with or without the ${{ }} wrapper. Live tree: 0 findings over 30 files, 78 jobs and 1017 judged expressions. The card's claim was verified and holds at 835b2d1c; the Claim 6468029898 names this branch.",
      "tests": "node scripts/check-workflow-context-availability.mjs --self-test: 53 assertions in 9 batteries, with roster, floor and handshake. They cover: the 191e9d5e specimen (runner.temp in job-level env) refused; the same key at step-level env passing; the 16-cell minimum grid judged against the table (13 refuse; matrix passes in env, timeout-minutes and runs-on); the matrix rows passing under strategy.matrix while job-level if: still refuses matrix; expression reading; special functions; workflow-level and workflow_call rows; 5 missing-input shapes; and the real tree. Teeth: a one-shot mutant widened the jobs.*.env row with runner (proven on disk by grep -c = 1) and its self-test exited 1 with 6 failures. Restored, the self-test printed '53 assertions', exit 0, and git status was clean. No permanent mutant file. Head 73f898eb.",
      "gates": "On 73f898eb, which is c444d24b merged with origin/main. pnpm check:workflow-status-functions: exit 0. dispatch-gates --commands derived 41; all were run, plus 5 ⛔ roster gates under scripts/. --ran: '41 derived famil(ies) accounted for — 37 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3)', exit 0. NOT MEASURED (exit 3, PREREQUISITE NOT MET because no build closure exists and the diff touches no package): check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content, check:published-readme-exports. check:pm-dispatch-gates: exit 0. check-comment-mask-corpus: exit 0, 308s. PR check-runs at report time: Governed Surface Queue Guard success, Check Changeset success; Build Core and the rest in_progress. Not awaited, per contract.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — ToolSearch loaded the tool schemas only; no mcp__github__ tool was called",
      "api_writes": "2 — (1) POST /repos/objectstack-ai/objectstack/dispatches, the fleet-write relay pr_create stroke (run 40685816860, success). It created #27242 as a draft with assignees os-justin and labels skip-changeset, and the body read back as 9716 bytes, byte-identical. (2) POST /repos/objectstack-ai/objectstack/issues/27227/comments, this report, via post-stamped. Also 2 git pushes (not REST).",
      "open_questions": [
        {
          "question": "The card says matrix is allowed in job-level runs-on, env, timeout-minutes and continue-on-error 'when the job has a strategy.matrix'. GitHub's table lists matrix for those keys with no such condition. Should the gate also refuse matrix there when the job has no strategy.matrix?",
          "options": [
            "A: keep it table-faithful, as shipped: no strategy.matrix condition. GitHub does not reject such a file; the reference just evaluates empty.",
            "B: add a second, separately documented rule refusing matrix.* without a strategy.matrix. That is an actionlint-style lint and goes beyond the false-green class this card names."
          ],
          "recommendation": "A, because the card asks to encode the table rather than a memory of it, and the defect class is files GitHub rejects outright. B lints something GitHub accepts."
        },
        {
          "question": "docs.github.com is outside this container's network allow-list, so the table was read from raw.githubusercontent.com/github/docs. Is that an acceptable source of record?",
          "options": [
            "A: yes; the header names the source path and read date",
            "B: re-verify against the rendered page from a seat with docs.github.com access"
          ],
          "recommendation": "A, because the docs page renders from that source file."
        }
      ],
      "out_of_scope_findings": []
    }
  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #27242 comment 6468898202 · 2026-10-28T12:25Z · ready + auto-merge armed. Open questions 1 and 2 answered A in the ACCEPT.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #27242, merged as 295699d51d through the merge queue · 2026-10-28T12:38Z

    Merged = reviewed. The merged diff matches the reviewed head 73f898ebea: the sorted +/− lines are hash-identical, 2 files, +711/−1. ACCEPT → PR #27242 comment 6468898202. The card was closed by Fixes #27227. pm:dispatched is removed in this act. Cloud session session_01QSeKYkorXJzrG4kmSQV2Y7 is archived in this act. main's Lint & Repo Gates step now runs the context-availability gate. Nothing remains.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions