Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Security-sensitive report
url: https://github.com/dkritarth/Vellum/security/advisories/new
about: Report vulnerabilities privately. Never place secrets in public issues.
96 changes: 96 additions & 0 deletions .github/ISSUE_TEMPLATE/vellum-task.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Vellum implementation task
description: Create one independently verifiable Vellum task or bug.
title: "[AREA-NN] "
labels:
- status:blocked
body:
- type: markdown
attributes:
value: |
GitHub Issues are Vellum's sole executable backlog. New issues default to blocked. Maintainer adds `status:ready` only when every dependency and prior phase gate is closed.
- type: textarea
id: outcome
attributes:
label: User outcome
description: Describe observable value for Kritarth's paper-reading workflow.
placeholder: After this closes, user can...
validations:
required: true
- type: textarea
id: dependencies
attributes:
label: Dependencies and gate
description: List exact blocking issue numbers. Write None only when maintainer intentionally makes this first ready task.
placeholder: Blocked by #123 and gate #120. Do not start until both close.
validations:
required: true
- type: textarea
id: current
attributes:
label: Current behavior and evidence
description: Include reproduction, expected/actual result, screenshots, logs, or current code seam. Never include credentials.
validations:
required: true
- type: textarea
id: scope
attributes:
label: In scope
description: Define one vertical slice and likely files/seams.
validations:
required: true
- type: textarea
id: non_goals
attributes:
label: Explicit non-goals
description: State what this issue must not absorb.
validations:
required: true
- type: textarea
id: acceptance
attributes:
label: Acceptance criteria
description: Use concrete checkboxes for user-visible behavior, errors, persistence, accessibility, and safety.
placeholder: |
- [ ] Observable behavior...
- [ ] Failure behavior...
- [ ] Persistence/restart behavior...
validations:
required: true
- type: textarea
id: automated
attributes:
label: Automated verification
description: Name failing test first, focused tests, full suite, typecheck, build, and diff check.
placeholder: |
- [ ] Regression test fails before fix and passes after
- [ ] npm test
- [ ] npm run typecheck
- [ ] npm run build
- [ ] git diff --check
validations:
required: true
- type: textarea
id: live
attributes:
label: Live Electron verification
description: Exact clicks/typing, data setup, expected visible state, console inspection, screenshots, real-paper/ACP checks, and restart steps.
validations:
required: true
- type: textarea
id: pr_evidence
attributes:
label: Required PR evidence
description: State what reviewer must see and repeat independently. PR must use Closes #N.
validations:
required: true
- type: checkboxes
id: guardrails
attributes:
label: Guardrail acknowledgement
options:
- label: First-party ACP only; no raw API keys or OAuth bridge.
required: true
- label: Pure Node/TypeScript; no Python or custom RAG.
required: true
- label: I will not start this issue while it has `status:blocked`.
required: true
43 changes: 43 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Closes #<!-- exactly one authoritative issue number -->

## User outcome

<!-- What observable research workflow now works? -->

## Scope

<!-- Summarize focused change and explicit non-goals. -->

## Acceptance criteria

- [ ] Copy each criterion from linked issue and mark only from evidence.

## Automated verification

- [ ] Failing regression test or reproducible baseline recorded before fix
- [ ] Focused tests: `...`
- [ ] `npm test`
- [ ] `npm run typecheck`
- [ ] `npm run build`
- [ ] `git diff --check`

## Live Electron verification

<!-- Exact setup, clicks/typing, observed results, error/empty/restart paths. -->

## Visual and console evidence

<!-- Attach screenshots. State console errors/warnings exactly; write None only after checking. -->

## Real-paper / ACP evidence

<!-- Required for reader, ingest, and ACP work. Mocks are not live proof. -->

## Limitations and follow-ups

<!-- Disclose every unverified path or linked follow-up issue. -->

## Independent review

- [ ] Reviewer repeated applicable live procedure
- [ ] Linked issue had `status:ready` or `status:in-progress`, never `status:blocked`
68 changes: 68 additions & 0 deletions .github/workflows/issue-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Issue and verification gate

on:
pull_request:
types: [opened, edited, synchronize, reopened, ready_for_review]

permissions:
contents: read
issues: read
pull-requests: read

jobs:
enforce:
runs-on: ubuntu-latest
steps:
- name: Validate linked issue and evidence
uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || '';
const closeMatches = [...body.matchAll(/\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi)];
const issueNumbers = [...new Set(closeMatches.map((match) => Number(match[1])))];

if (issueNumbers.length !== 1) {
core.setFailed(`PR must close exactly one authoritative issue; found ${issueNumbers.length}. Use: Closes #<issue>.`);
return;
}

const issueNumber = issueNumbers[0];
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});

if (issue.pull_request) {
core.setFailed(`#${issueNumber} is a pull request, not an issue.`);
return;
}

const labels = issue.labels.map((label) => typeof label === 'string' ? label : label.name);
if (labels.includes('status:blocked')) {
core.setFailed(`Issue #${issueNumber} is status:blocked. Close dependencies and have maintainer unlock it before work or merge.`);
}
if (!labels.includes('status:ready') && !labels.includes('status:in-progress') && !labels.includes('status:verification')) {
core.setFailed(`Issue #${issueNumber} lacks an allowed active status label.`);
}

const requiredSections = [
'## User outcome',
'## Acceptance criteria',
'## Automated verification',
'## Live Electron verification',
'## Visual and console evidence',
'## Limitations and follow-ups',
'## Independent review',
];
const missing = requiredSections.filter((heading) => !body.includes(heading));
if (missing.length > 0) {
core.setFailed(`PR body missing required sections: ${missing.join(', ')}`);
}

// Reject placeholders, but allow explicit disclosure that an
// inapplicable path was not run. Hiding limitations is worse than
// stating them in the required evidence sections.
if (/\b(?:TODO|TBD)\b/i.test(body) && !context.payload.pull_request.draft) {
core.setFailed('Ready PR still contains TODO/TBD placeholders. Keep draft or complete evidence.');
}
Loading
Loading