Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,24 @@ Each issue gets a branch `<type>/issue-NNN-<short-title>` and one PR that closes

## Writing a good issue

Two sections carry most of the weight, and both templates require them:
**Use a form.** Every issue and every pull request in this org is filed on one of the templates —
`epic.yml`, `work_item.yml`, `bug_report.yml`, `feature_request.yml`, or
`pull_request_template.md`. Not an approximation of one, and not your own headings covering the
same ground. `gh issue create --body` and `gh pr create --body` bypass the form silently: pass
`--template`, or reproduce the sections exactly — same names, same order, none added, none
dropped. A section that does not apply is filled with the reason it does not apply, never deleted.

Two fields carry most of the weight, and every form requires them or their analogue:

- **Scope boundary** — what this issue does *not* do. Usually the most useful sentence in the
issue; it is what stops a PR sprawling.
issue; it is what stops a PR sprawling. On a bug report it is *What you have not checked*.
- **Definition of done** — exact conditions. Prefer an exact expected set over "non-empty", and a
demonstrated behaviour over an asserted one. "Works correctly" is not a definition of done.

Cite `file:line` wherever you can. An issue that names the line is one someone can pick up cold.
**Show, don't describe.** Cite `file:line` wherever you can, and paste the command and its output
rather than summarising it. An issue that names the line is one someone can pick up cold. Every
sentence is a fact with a citation, a consequence that follows from one, or a guess marked as a
guess — an unmarked guess sends the next person to fix something that is not broken.

**Keep it short.** Under 400 words outside code blocks. Code blocks do not count; they are the
evidence the words exist to avoid restating. An issue that needs more is usually two issues.
24 changes: 0 additions & 24 deletions .github/ISSUE_TEMPLATE/bug_report.md

This file was deleted.

79 changes: 79 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Bug report
description: Something in a codellm-devkit repo behaves differently from what it documents.
title: ""
labels: ["bug"]
projects: ["codellm-devkit/1"]
body:
- type: markdown
attributes:
value: |
**Show, don't describe.** A pasted command and its output is worth a paragraph of
prose and is checkable. Every claim here is one of three things: a fact with a
citation (`file:line`, or a number with the command that produced it), a consequence
that follows from one, or a guess you mark as a guess.

**Search open issues first** and comment on the duplicate instead of filing. Say
what is new.

Keep it short. A bug report over 400 words outside its code blocks is usually two
bug reports.

- type: input
id: repo
attributes:
label: Repo and version
description: Which repo, and the exact version or commit. `codeanalyzer --version`, the installed package version, or a SHA.
placeholder: codeanalyzer-python 2.1.3 (or commit a1b2c3d)
validations:
required: true

- type: textarea
id: repro
attributes:
label: Reproduction
description: The smallest input that shows it, and the exact command. Paste them; do not describe them. If you cannot reduce it, say what you tried.
placeholder: |
```python
# fixture.py
@app.route("/x")
def handler(): ...
```
```
$ codeanalyzer -i fixture.py -a 2
```
render: markdown
validations:
required: true

- type: textarea
id: observed
attributes:
label: Observed vs expected
description: Paste the real output, then say what it should have been. An abridged paste is fine; a paraphrased one is not.
placeholder: |
Observed:
L2 body{"34:15"} kind=call callee=null

Expected: callee resolved to the @external id, as L2 does for module-level calls.
render: markdown
validations:
required: true

- type: textarea
id: unchecked
attributes:
label: What you have not checked
description: The honest part. Sibling analyzers you did not try, versions you did not test, whether it predates a recent change. An unmarked guess sends someone to fix a thing that is not broken.
placeholder: |
- Not tried on codeanalyzer-typescript; guess, untested: the shared resolver means it is affected too.
- Did not bisect. Present in 2.1.3; unknown before that.
validations:
required: true

- type: textarea
id: context
attributes:
label: Additional context
description: Logs, OS, runtime version, anything else. Optional.
validations:
required: false
20 changes: 0 additions & 20 deletions .github/ISSUE_TEMPLATE/feature_request.md

This file was deleted.

74 changes: 74 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Feature request
description: Propose a capability a codellm-devkit repo does not have yet.
title: ""
labels: ["enhancement"]
projects: ["codellm-devkit/1"]
body:
- type: markdown
attributes:
value: |
**This is a proposal, not a work item.** It becomes a Work item when a maintainer
picks it up, and an Epic only if it spans repos or several pull requests. You do not
need to decompose it here.

**Anything touching the canonical schema or a public SDK API gets designed before it
gets built** — a committed spec, decided with a maintainer. Propose the capability
and the constraint; leave the schema shape to that conversation.

**Search open issues first.** Keep it under 400 words outside code blocks.

- type: textarea
id: problem
attributes:
label: Problem
description: What you cannot do today, and what you do instead. One or two paragraphs. Cite `file:line` or paste the workaround — a concrete blocked task beats a described one.
placeholder: |
Resolving a call to a third-party callable returns null at L2, so downstream
reachability stops at the project boundary (codeanalyzer-python, resolver.py:214).
We currently re-resolve against a hand-kept map of ~40 framework entrypoints.
validations:
required: true

- type: textarea
id: scope
attributes:
label: Scope boundary
description: What this should NOT do. The most useful field in the form — it is what stops the eventual PR sprawling.
placeholder: |
Identity and provenance for out-of-project targets only. Not signature
reconstruction, not stub generation, and not a bundled type-stub corpus.
validations:
required: true

- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: What else would solve it, and why you are not proposing that. "None" is a valid answer if you say so explicitly.
placeholder: |
- Resolve in each SDK instead — rejected, four SDKs would diverge on the id format.
- Ship stubs with the analyzer — rejected, licensing and size.
validations:
required: true

- type: textarea
id: caveats
attributes:
label: Caveats and known risks
description: Substrate limits, inherited unsoundness, cost, anything that makes this harder than it looks. If you genuinely know of none, write that.
placeholder: |
- Python has no import-time guarantee that a name resolves to one target; the id is a best effort.
- Guess, untested: which SDKs already read this field.
validations:
required: true

- type: textarea
id: done
attributes:
label: What "done" would look like
description: An observable condition, not "works correctly". Prefer an exact expected set over "non-empty", and a demonstrated behaviour over an asserted one.
placeholder: |
- Calls to a third-party callable carry a stable id at L2 on the fixture corpus.
- The id is identical across two runs and across two machines.
validations:
required: true