ci: improve issue intake, enforce minimum quality, and ping PR authors on wrong-branch retarget#229
Conversation
- 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'
|
Failing Checks are not related this PR. |
There was a problem hiding this comment.
💡 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".
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.
|
Review note: the automation direction is good, but merging this before the |
|
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. |
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)[Bug]:title prefix.Client or integrationandAreadropdowns.VersionandOperating systemrequired fields.Redacted configurationJSON textarea.Feature proposal (
feature_request.yml)[Feature]:title prefix. Renamed toFeature proposal.Provider or API compatibility (
provider_compatibility.yml) -- newprovider-compatibilitylabel to distinguish these from genericenhancementissues in the issue list (see Required maintainer action below).Documentation (
documentation.yml) -- newdocumentationlabel (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
blockerandexampleheadings.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)opened,edited,reopened.contents: read(checkout only),issues: write.Maintainer override protection (addresses review finding 1 from #225):
Reopen is allowed only when ALL of the following are true:
closed_atexactly matches the bot's stored timestamp.state_reasonmatches.closed_by.loginisgithub-actions[bot]-- a human closer blocks reopen unconditionally.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:testandnode: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_byguard.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)contents: write-- the workflow only needspull-requests: write.@mentionsthe PR author so they get a direct notification to retarget, instead of relying on them watching the repo.Verification
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
d019cfcfeat(issues): redesign OpenCodex issue forms1aab30frefactor(ci): extract and harden issue-quality validatione78c543test(ci): cover issue classification and reopening rules15a03b9chore(ci): minimise PR-target workflow permissionsa1c38aefix(ci): check closed_by before reopening (owner feedback on ci: enforce issue quality for feature requests + disable blank issues #225)596b200fix(ci): prevent false positives on legacy forms and misleading bot comment838e08efeat(issues): use provider-compatibility label on compat formRequired maintainer action
The
provider-compatibilitylabel does not exist in the repo yet. Please create it before merging so the provider/API compatibility form can apply it automatically:Until then, issues submitted via the provider/API compatibility form will not have a label applied. Everything else works without this step.