Skip to content

ci: improve issue intake, enforce minimum quality, and ping PR authors on wrong-branch retarget#229

Merged
Ingwannu merged 9 commits into
lidge-jun:devfrom
Wibias:codex/issue-intake-rework
Jul 22, 2026
Merged

ci: improve issue intake, enforce minimum quality, and ping PR authors on wrong-branch retarget#229
Ingwannu merged 9 commits into
lidge-jun:devfrom
Wibias:codex/issue-intake-rework

Conversation

@Wibias

@Wibias Wibias commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Complete rework of OpenCodex issue intake: redesigned forms for all four submission types, a tested validation module, a hardened enforcement workflow, and a CI test job. This is a v2 addressing all three design issues flagged in the review of #225.


What changed

Issue forms

Bug report (bug_report.yml)

  • Removed the [Bug]: title prefix.
  • Added Client or integration and Area dropdowns.
  • Made Version and Operating system required fields.
  • Split logs from screenshots (screenshots now use a drag-and-drop upload field).
  • Added Redacted configuration JSON textarea.
  • Updated checkboxes to cover account details and request credentials.

Feature proposal (feature_request.yml)

  • Removed the [Feature]: title prefix. Renamed to Feature proposal.
  • Replaced the two-field form with a structured four-field form: goal, current limitation, expected behaviour, concrete usage example.
  • Added contribution-quality checkboxes.

Provider or API compatibility (provider_compatibility.yml) -- new

  • Covers incompatible endpoints, request/response shapes, streaming, tool calls, model discovery, and authentication.
  • Required fields: client, provider, version, endpoint, current behaviour, expected behaviour, minimal redacted request, actual response/error, upstream documentation URL.
  • Uses a new provider-compatibility label to distinguish these from generic enhancement issues in the issue list (see Required maintainer action below).

Documentation (documentation.yml) -- new

  • Covers missing, incorrect, outdated, confusing documentation, broken examples, and broken links.
  • Uses the existing documentation label (confirmed present).

Config (config.yml)

  • blank_issues_enabled: false -- contributors can no longer bypass the forms.

Validator (.github/scripts/issue-quality.cjs)

Pure CommonJS module, zero runtime dependencies, no GitHub API calls.

Exports: clean, normalise, canonicalise, extractSection, detectIssueKind, validateIssue, shouldReopen.

Detection uses distinct section headings, not title prefixes, and keeps full backward compatibility with legacy [Bug]: and [Feature]: prefixed submissions. A stored bot kind in the hidden comment survives heading removal by the author.

Validation rules by kind:

Feature: closes only when required core sections are missing/empty, all sections repeat the same content, all sections repeat the issue title, or unchanged placeholders were submitted. Legacy forms are not penalised for missing the new-form-only blocker and example headings.

Bug: deliberately narrow. Closes only when summary AND reproduction are both empty, both repeat the title, or environment fields (version/OS) exist as headings but were cleared. Legacy bug reports without those headings are not penalised. A terse but real crash report always passes.

Provider compatibility: closes when required behaviour sections are missing, current and expected behaviour are identical, request/response are both absent, or upstream docs are empty without explanation.

Documentation: closes when location and problem description are both missing, the body merely repeats the title, or required sections contain only placeholders.

Never closes for grammar, spelling, brevity, technical vocabulary, or tone.


Enforcement workflow (.github/workflows/enforce-issue-quality.yml)

  • Triggers on opened, edited, reopened.
  • Permissions: contents: read (checkout only), issues: write.
  • Checks out the validator from the trusted default-branch ref. No contributor code runs.
  • Both Actions pinned to immutable SHAs with version comments.
  • Per-issue concurrency group prevents race conditions on rapid edits.

Maintainer override protection (addresses review finding 1 from #225):

Reopen is allowed only when ALL of the following are true:

  1. Bot state is active.
  2. Issue is still closed.
  3. closed_at exactly matches the bot's stored timestamp.
  4. state_reason matches.
  5. closed_by.login is github-actions[bot] -- a human closer blocks reopen unconditionally.
  6. The current event is not a maintainer reopen.

If a maintainer reopens an issue the bot closed, the bot deactivates its state and posts a neutral acknowledgment. It does not close again.

Bot comment: single hidden comment, updated in place. State stored as a hidden HTML marker. Closure message names specific reasons and guidance. Does not describe issues as "low quality" or similar.


Tests (.github/scripts/issue-quality.test.cjs)

33 tests using node:test and node:assert/strict, zero dependencies.

Covers: detection of all four new and both legacy form types, stored bot kind surviving heading removal, manually applied labels on unrelated issues, #208-style duplicate content, concise valid features, CJK submissions, empty/terse bug reports, legacy forms without version/OS or blocker/example headings, provider-compat missing request/response, documentation corrections, normalisation (No response, HTML comments, punctuation, filler phrases), and all six closure-ownership decision paths including the closed_by guard.

Test workflow (.github/workflows/issue-quality-tests.yml)

Runs on PRs and pushes touching any of the issue templates, validator, test file, or enforcement workflow. Runs the 33 tests and a structural YAML check (valid element types, unique IDs, required keys).

PR-target workflow (.github/workflows/enforce-pr-target.yml)

  • Removed contents: write -- the workflow only needs pull-requests: write.
  • The wrong-branch comment now explicitly @mentions the PR author so they get a direct notification to retarget, instead of relying on them watching the repo.

Verification

node --test .github/scripts/issue-quality.test.cjs
# 33 pass, 0 fail

All four issue forms pass the structural YAML check. No hidden or bidirectional Unicode characters. No arbitrary length thresholds. No unpinned Actions. No [Bug]: or [Feature]: prefixes on new forms. Legacy prefixed submissions still detected and validated with appropriate per-form rules.

Commits

  • d019cfc feat(issues): redesign OpenCodex issue forms
  • 1aab30f refactor(ci): extract and harden issue-quality validation
  • e78c543 test(ci): cover issue classification and reopening rules
  • 15a03b9 chore(ci): minimise PR-target workflow permissions
  • a1c38ae fix(ci): check closed_by before reopening (owner feedback on ci: enforce issue quality for feature requests + disable blank issues #225)
  • 596b200 fix(ci): prevent false positives on legacy forms and misleading bot comment
  • 838e08e feat(issues): use provider-compatibility label on compat form

Required maintainer action

The provider-compatibility label does not exist in the repo yet. Please create it before merging so the provider/API compatibility form can apply it automatically:

gh label create "provider-compatibility" --repo lidge-jun/opencodex --color "0075ca" --description "Incompatible provider, endpoint, or API integration"

Until then, issues submitted via the provider/API compatibility form will not have a label applied. Everything else works without this step.

Wibias added 7 commits July 22, 2026 00:10
- Bug report: add client/integration and area dropdowns, require version
  and OS, split logs from screenshots, add upload field for attachments,
  add redacted-config JSON field. Remove [Bug]: title prefix.
- Feature proposal: restructure around goal/blocker/behaviour/example,
  require a concrete usage example, add workflow-specific checks.
  Remove [Feature]: title prefix.
- New provider/API compatibility form for endpoint, request/response
  shape, and upstream-spec-anchored reports.
- New documentation form for missing, incorrect, outdated, or broken docs.
- Disable blank issues (config.yml).
Move all classification and validation logic into a pure CommonJS module
(.github/scripts/issue-quality.cjs) with zero runtime dependencies. The
workflow (.github/workflows/enforce-issue-quality.yml) now only handles
GitHub API operations: fetching live issue state, managing the hidden bot
comment, closing/reopening, and respecting maintainer overrides.

Key design decisions:
- Detection uses distinct section headings, not title prefixes.
- Legacy [Bug]: and [Feature]: prefixed issues remain supported.
- Stored bot kind survives heading removal by the author.
- No word-count or character-count thresholds anywhere.
- Closure ownership: reopen only when the bot's stored closedAt and
  stateReason exactly match the live issue and no maintainer superseded.
- Trusted authors (OWNER/MEMBER/COLLABORATOR) are exempt.
- Single hidden bot comment, updated in place (no duplicates).
29 tests using node:test and node:assert/strict (zero dependencies):
- Detection: new and legacy forms for all four kinds, stored bot kind,
  manually applied labels on unrelated issues.
- Validation: lidge-jun#208-style duplicates, concise actionable content, CJK
  submissions, empty reports, terse crash reports, provider-compat
  missing request/response, documentation corrections.
- Normalisation: No response, HTML comments, punctuation, filler phrases.
- Closure ownership: timestamp match/mismatch, state reason, inactive
  bot state, already-open issue, maintainer override.

The test workflow runs on PRs and pushes touching the issue templates,
validator, or enforcement workflow. It also validates that all issue-form
YAML files parse correctly, use only supported element types, and have
unique IDs.
Drop contents: write from enforce-pr-target.yml. The workflow only
needs pull-requests: write to update titles, draft status, and comments.
No behavioural change.
…n#225)

The reopen decision now verifies that the bot itself was the last actor
to close the issue (closed_by === 'github-actions[bot]'). A human closing
the issue, even with a matching timestamp, is treated as intentional
closure and the bot will not reopen.

Addresses finding 1 from the repo owner's review of PR lidge-jun#225.
…omment

- Feature validation: blocker and example sections are only required when
  their headings exist (new form). Legacy forms with only 'Problem to solve'
  and 'Proposed solution' no longer trigger the missing-sections reason.
- Bug validation: version/OS absence only closes when the headings exist in
  the body. Legacy bug reports without those fields are not penalised.
- Workflow: maintainer reopen comment now says 'Maintainer decision respected'
  instead of 'Automated check passed', which was false when the issue was
  still invalid.
- Tests: two new cases lock in legacy-form compatibility.
Separates provider/API issues from generic enhancement requests in the
issue list. The label needs to be created in the repo by a maintainer:
  gh label create provider-compatibility --color 0075ca --description 'Incompatible provider, endpoint, or API integration'
@Wibias

Wibias commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Failing Checks are not related this PR.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 596b200b0e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/scripts/issue-quality.cjs Outdated
Comment thread .github/workflows/enforce-issue-quality.yml Outdated
Comment thread .github/scripts/issue-quality.cjs
Wibias added 2 commits July 22, 2026 00:34
1. Legacy _No response_ in old optional env fields no longer triggers the
   'Version and Operating system are both missing' reason. Added isRawPlaceholder()
   to distinguish intentionally blank optional fields from actively cleared ones.

2. Heading-removal bypass closed: when detectIssueKind() returns null on an
   edited issue but a form label (bug/enhancement/documentation/provider-compatibility)
   is still present, the workflow uses that label as a fallback kind instead of
   skipping enforcement silently.

3. Provider/API compatibility validator now checks that provider and endpoint
   fields are non-empty. A report where those headings exist but were cleared
   after submission is rejected.

36 tests pass.
@Wibias Wibias changed the title ci: improve issue intake and enforce minimum quality ci: improve issue intake, enforce minimum quality, and ping PR authors on wrong-branch retarget Jul 22, 2026
@lidge-jun

Copy link
Copy Markdown
Owner

Review note: the automation direction is good, but merging this before the provider-compatibility label exists in the repo would break label application on the new issue form. Sequencing: (1) create the label, (2) then land this in a staged review since it changes intake policy for all future issues. Holding until that's set up.

Copy link
Copy Markdown
Owner

Reviewed the workflow permissions, event boundaries, checked-in scripts, and CI coverage. I found no malware, credential-exfiltration path, contributor-code execution under pull_request_target, or suspicious dependency change. The issue intake validator is useful and the current matrix is green. I will create the missing provider-compatibility label and merge this into dev.

@Ingwannu
Ingwannu merged commit 07d7b91 into lidge-jun:dev Jul 22, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants