Skip to content

Add open source project intake system (supersedes #4)#6

Open
michaeloboyle wants to merge 118 commits into
agenticsorg:mainfrom
michaeloboyle:feature/p0-state-guards-submitter-exclusion-idempotency
Open

Add open source project intake system (supersedes #4)#6
michaeloboyle wants to merge 118 commits into
agenticsorg:mainfrom
michaeloboyle:feature/p0-state-guards-submitter-exclusion-idempotency

Conversation

@michaeloboyle
Copy link
Copy Markdown
Collaborator

Summary

This PR adds a GitHub-native intake and governance pipeline for open source project submissions to the Agentics Foundation. Members open an issue using the project-submission template; GitHub Actions workflows handle scoring, escalation voting, validation voting, registration of approved projects, and retraction. Decisions are recorded as immutable comments plus an append-only attestation log. Committee composition and quorum come from data/committee-config.json, not from code.

This work was originally proposed in #4. After review three classes of issue surfaced: governance gaps that allowed phase bypass, spec drift surfaced by Copilot bot on 2026-04-30, and branch-hygiene constraints (#4 was opened with michaeloboyle:main as head, which couples every update to the fork's main branch and conflicts with our safety policy of blocking direct pushes to main). This PR addresses all three on a feature branch and supersedes #4.

What's in the pipeline

Component File
Submission form .github/ISSUE_TEMPLATE/project-submission.yml
Scoring (25-point rubric) .github/workflows/scoring.yml
Two-step voting .github/workflows/escalation-vote.yml, validation-vote.yml
Registry write on approval .github/workflows/approve-project.yml
/retract flow .github/workflows/retraction.yml
Phase + idempotency primitives lib/workflow-guards.js
Committee config data/committee-config.json
Attestation log (append-only) data/rvf/attestation.jsonl
Scoring rubric reference docs/scoring-template.md

P0 governance fixes

These three close bypass and replay holes. They are not refactors.

  • Phase guards on every state-changing workflow. scoring, escalation-vote, validation-vote, approve-project, and retraction each verify the issue is in the correct phase before acting. Without this, anyone with write access could manually apply status:approved and skip voting entirely.
  • Submitter exclusion in retraction tallies. The original submitter cannot vote on their own retraction; their vote is filtered before the tally so they cannot block community-initiated removal.
  • Idempotency on registry writes. approve-project checks for existing registry entries; retraction checks for existing label transitions. Re-running a workflow no longer creates duplicates in approved-projects.json.

Supporting changes that emerged during P0 work:

  • workflow-guards library with 129 passing tests across 13 suites
  • Queue-instead-of-cancel on concurrent vote workflow runs (prevents lost tallies under burst comments)
  • CI workflow running npm test on every PR
  • Approve-with-conditions trigger wired through approve-project.yml (was a documented state with no transition path)
  • Dynamic quorum sourced from data/committee-config.json instead of hardcoded 3

Copilot review dispositions

Copilot bot posted 13 file-line comments on #4 head 263000a on 2026-04-30. 5 are directly fixed on this branch. 8 are already resolved by intermediate work, outdated against rewritten files, or filed as follow-ups.

# File:Line Issue (summary) Disposition Where
1 scripts/simulate-scoring.sh:90 --flags syntax mismatch with documented format Resolved commit 8ca5e0e
2 lib/state-machine.js:45 rescoring and retraction_escalated states not modeled Backlog (follow-up) fork issue #31
3 .github/workflows/retraction.yml:168 core undefined in shell step Outdated; file rewritten, core auto-injected via github-script n/a
4 .github/workflows/retraction.yml:107 Missing submitter exclusion in retraction tally Resolved (already addressed by P0 set) commits b539e7e + a79600d
5 .github/workflows/validation-vote.yml:123 Strict majority not enforced; tie behavior undefined Resolved commit 0d88f27
6 .github/workflows/scoring.yml:46 Multi-digit out-of-range scores accepted Resolved commit 75f1455
7 scripts/setup-labels.sh:29 4 status labels referenced by workflows but not created Resolved commit 7e7c4d6
8 README.md:56 Command list missing approve-with-conditions and no-retract Resolved commit b00caac
9 data/rvf/attestation.jsonl:5 Signature field schema vs data drift Backlog (follow-up) new issue to be filed
10 .github/workflows/retraction.yml:17 /retract exact-match vs /retract <reason> BDD spec mismatch Backlog (follow-up) new issue to be filed
11 .github/workflows/approve-project.yml:14 No transition path from approve-with-conditions Resolved commit c90188b
12 README.md:68 Documented commands lacked retract subcommand variants Resolved (covered by b00caac) commit b00caac
13 docs/scoring-template.md:88 Score interpretation table out of date Resolved by intermediate work; current template matches governance doc n/a

Tests

npm test reports 129/129 passing across 13 suites on this branch HEAD (b00caac). CI is wired to run on every PR via .github/workflows/ci.yml.

Test Plan (committee verification)

  • Copilot re-review on the new PR head
  • Confirm setup-labels.sh creates all required labels in the upstream repo
  • Validation vote scenario: 2 Approve + 1 Decline + 1 Defer → outcome is DEFERRED (default-on-tie behavior)
  • Scoring rejection: a comment containing mission:10 is rejected as out-of-range, not silently truncated
  • Retraction tally: when the submitter casts /vote retract no-retract, the vote is excluded and the tally proceeds without their input

Follow-ups (filed separately)

  • data/rvf/attestation.jsonl:5 schema drift — signatures referenced in records do not match the schema fields actually written
  • .github/workflows/retraction.yml:17 /retract exact-match — current trigger does not accept the documented /retract <reason> form per the BDD spec
  • lib/state-machine.js:45 rescoring and retraction_escalated — tracked at fork issue #31

michaeloboyle and others added 30 commits March 5, 2026 08:20
Add GitHub issue template for project submissions, 6 workflows for
the full intake lifecycle (triage, scoring, escalation vote, validation
vote, approval registration, retraction), scoring template, label
setup script, and approved projects registry.

Implements the process defined in the Open Source Committee governance doc.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…gex, harden script

- SEC-013: Add bot filtering to validation-vote.yml vote tallying
- SEC-012: Exclude issue author from voting in validation-vote.yml
- SEC-014: Add repo format validation and confirmation prompt to setup-labels.sh

Note: escalation-vote.yml and retraction.yml fixes were applied in prior commits.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
RFC-001 proposes an intelligent governance agent for the Agentics Foundation
Open Source Committee. The agent perceives submissions, relates them to
precedent, prepares case briefs for the committee, and records decisions.
Humans hold all decision authority.

Deliverables:
- RFC-001-governance-agent.md: the proposal
- 5 Gherkin feature files (98 scenarios, all RED): eligibility, scoring,
  voting, retraction, and the 4 GDoc scored examples
- spec/constitution.yaml: complete GDoc encoding (every element traceable
  via gdoc_ref)
- spec/retraction.yaml: retraction lifecycle spec
- data/rvf/: seed graph (with CoI detection path), embeddings, attestation
- .github/workflows/governance-agent.yml: intelligence layer workflow

Co-Authored-By: Claude Opus 4.6 <[email protected]>
… scripts

Local test infrastructure (82 tests, all passing):
- lib/state-machine.js: 14-state governance engine with guard evaluation
- lib/rvf.js: graph BFS for CoI detection, embedding similarity, attestation
- lib/commands.js: slash command parser (/score, /vote, /coi, /override)
- test/state-machine.test.js: 33 tests covering all paths and guards
- test/rvf.test.js: 20 tests including CoI path verification
- test/commands.test.js: 29 tests for command parsing and validation

Fork simulation scripts:
- simulate-submission.sh: create test issues for 4 GDoc scenarios
- simulate-scoring.sh: post /score comments
- simulate-voting.sh: post /vote comments
- simulate-full-lifecycle.sh: end-to-end simulation
- simulate-cleanup.sh: close test issues
- verify-workflows.sh: validate workflow YAML syntax

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Multiple case-brief jobs running simultaneously caused merge conflicts
on the attestation.jsonl append-only log. Added a 3-attempt retry loop
that resolves conflicts by accepting both versions (since JSONL is
append-only, all entries are valid).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The 60-second rate limit window was too aggressive, causing /status and
/coi responses to be suppressed when posted shortly after a /score
command (which triggers the scoring workflow's bot comment). Reduced to
10 seconds, which still prevents duplicate bot tallies from concurrent
workflow re-triggers while allowing distinct commands to respond.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Ran 4 simulated submissions through the full governance pipeline on
the fork. Case briefs, scoring, /status, /coi, and /override all
verified working. Two bugs found and fixed (attestation race condition,
rate limiter window). Full voting requires multiple GitHub users.

82/82 local tests passing, 49/49 workflow structural checks passing.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Ran 4 simulated submissions through the full governance pipeline on
the fork. Case briefs, scoring, /status, /coi, and /override all
verified working. Two bugs found and fixed (attestation race condition,
rate limiter window). Full voting requires multiple GitHub users.

82/82 local tests passing, 49/49 workflow structural checks passing.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The /coi workflow adds recused_from edges pointing to issue IDs (e.g.,
issue-1) that are not seed graph nodes. Updated the integrity test to
skip dynamic edges when checking referential integrity.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Allows single-user simulation of the full voting lifecycle by
bypassing the submitter-exclusion check when the repository
variable GOVERNANCE_TEST_MODE is set to "true". This is a
temporary fork-only change for simulation testing.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
github-actions Bot and others added 18 commits April 18, 2026 20:44
All panel criticisms addressed:
- Split votes (2-1), ties (1-1-1), vote changes tested
- Quorum enforcement and collapse via recusal verified
- SEC-012 real multi-user enforcement confirmed
- Retraction success and failure lifecycle complete
- Approve-with-conditions outcome working
- Score prediction returns ranges from enriched data
- CoI detection flags real graph paths

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Introduce lib/workflow-guards.js with reusable functions for:
- P0-1: State machine phase guards (checkPhaseGuard)
- P0-2: Submitter exclusion from voting (excludeSubmitter, isSubmitterExcluded)
- P0-3: Idempotency checks (checkRegistryDuplicate, checkAlreadyRetracted)

46 unit tests covering all guard functions, edge cases, and
the PHASE_REQUIREMENTS mapping for every workflow action.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
P0-1 (State Machine Guards):
- scoring.yml: requires status:triaged, status:scoring, or status:pending-review
- escalation-vote.yml: requires status:scoring or status:escalation-vote
- validation-vote.yml: requires status:validation-vote
- approve-project.yml: requires status:approved or status:approved-with-conditions,
  plus a bot validation vote result comment (prevents manual label bypass)
- retraction.yml (propose): requires status:approved, status:approved-with-conditions, or status:monitoring
- retraction.yml (vote): requires status:retraction-proposed

All phase guards post an informative comment explaining why the action was
blocked and what phase the issue needs to be in.

P0-2 (Submitter Exclusion in Retraction):
- retraction.yml: excludes the issue author (project submitter) from
  retraction vote tallies. If the submitter tries to vote, a comment
  explains they are excluded. Tally messages note the exclusion.
- Note: escalation-vote.yml and validation-vote.yml already had SEC-012
  submitter exclusion. The retraction workflow was the gap.

P0-3 (Idempotency):
- approve-project.yml: checks registry for existing entry by issue_number
  before adding. Skips silently on re-run.
- retraction.yml: checks if entry is already retracted before modifying.
  Skips registry update on re-run.
- Both workflows use the concurrency group "registry-update" for
  serialized access.

Also fixed: retraction proposal now applies status:retraction-proposed label,
and failed retraction votes restore status:monitoring label.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
cancel-in-progress: true was dropping concurrent vote runs. The
concurrency group already serializes execution, so switching to
false queues runs instead of cancelling in-flight ones.

Closes #23

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The job-level if condition only matched status:approved, so projects
approved with conditions were never added to the registry.

Closes #24

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Runs npm ci and npm test on push to main and pull requests.
Uses Node.js 20 with minimal read-only permissions. Actions
pinned to SHA consistent with existing workflows.

Closes #25

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Create data/committee-config.json with the committee roster and
quorum rule. Update validation-vote, escalation-vote, and retraction
workflows to compute quorum as simple_majority from config.members
instead of hardcoding QUORUM=3. The env var is kept as a fallback
if the config file is missing.

Scoring workflow does not use quorum, so it is unchanged.

Closes #26

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Workflows reference status:approved-with-conditions (validation-vote),
status:monitoring and status:retraction-proposed (retraction), and
status:triaged (scoring phase guard), but setup-labels.sh did not create
them. First run on a fresh repo would leave these workflows unable to
apply their labels at runtime.

Caught by Copilot review on PR #4 (one comment on approved-with-conditions);
the same root cause affects three other labels. Fixing all four together.

Also normalizes pre-existing em dash in deferred description.
The score parser used /(\d)/ which captured a single digit, so an input
like "mission:10" silently parsed as 1 and was accepted. Switching to
\d+ lets the existing 0-5 validation reject values like 10 with the
"Could not parse your score" error.

Caught by Copilot review on PR #4 (scoring.yml:46 of the reviewed SHA).

The lib/commands.parseScore helper already handles this correctly. The
inline workflow regex stayed in place to avoid a refactor; once we route
scoring.yml through lib/commands.parseScore we can drop the inline regex.
The SEC-010 comment in the script said "strict majority required, ties
default to DEFERRED" but the code only checked which bucket had the
highest count, not whether that bucket exceeded 50% of votes cast.
Concrete failure: 2 approve + 1 decline + 1 defer (4 total) yielded
APPROVED on a 50% plurality.

Switch to a Math.floor(totalVotes/2)+1 threshold. If combined approve
plus approve-with-conditions reaches threshold, prefer with-conditions
when its count is >= unconditional approves (preserves prior tie-break
direction). If decline reaches threshold, decline. Otherwise defer.

Caught by Copilot review on PR #4 (validation-vote.yml:123 of the
reviewed SHA).
The script's usage banner advertises "--flags <flags>" but the emitted
/score comment used "flags:X". lib/commands.parseScore expects
"--flags X", so flags coming through this simulation helper were
silently dropped by the workflow regex.

Caught by Copilot review on PR #4.
The README voting table and the scoring template's voting commands list
both omitted /vote approve-with-conditions and /vote no-retract, even
though both are accepted by validation-vote.yml and retraction.yml.

Also adds the four status labels that were missing from the README label
table to match what setup-labels.sh now creates: status:triaged,
status:approved-with-conditions, status:monitoring,
status:retraction-proposed.

Caught by Copilot review on PR #4 (README.md:56, README.md:68,
docs/scoring-template.md:88).
Copilot AI review requested due to automatic review settings May 3, 2026 15:38
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a GitHub-native intake and governance pipeline for open-source project submissions, including automated scoring, voting, approval registration, retraction handling, and audit/attestation artifacts.

Changes:

  • Introduces GitHub Actions workflows for submission triage, scoring, escalation/validation voting, approval registry updates, retraction, and CI.
  • Adds a small Node.js governance library (state machine, workflow guards, command parsing, RVF utilities) plus unit tests.
  • Adds governance specs, BDD feature files, documentation, and seed data (committee config, RVF graph/attestation log, approved-projects registry).

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
.github/ISSUE_TEMPLATE/config.yml Disables blank issues and adds a contact link.
.github/ISSUE_TEMPLATE/project-submission.yml Adds structured issue form for project submissions with required fields.
.github/dependabot.yml Enables Dependabot updates for GitHub Actions.
.github/workflows/approve-project.yml Registers approved submissions into data/approved-projects.json.
.github/workflows/ci.yml Runs Node tests on PRs and main.
.github/workflows/escalation-vote.yml Tallies escalation votes and advances phase/outcome.
.github/workflows/on-submission.yml Auto-triages new submission issues and applies category label + welcome comment.
.github/workflows/retraction.yml Implements /retract and retraction vote flow + registry update.
.github/workflows/scoring.yml Parses /score comments and posts a score summary.
.github/workflows/validation-vote.yml Tallies validation votes and applies final decision labels (and closes on decline).
README.md Documents submission flow, commands, labels, and admin setup.
data/approved-projects.json Adds the approved-projects registry (initialized empty).
data/committee-config.json Defines committee membership and quorum rule (data-driven).
data/rvf/attestation.jsonl Adds an append-only attestation log with example entries + schema header.
data/rvf/graph.json Seeds an RVF knowledge graph for CoI and example submissions.
docs/scoring-template.md Provides committee-facing scoring template and command reference.
features/eligibility.feature BDD spec for eligibility/intake gates.
features/gdoc-examples.feature BDD spec for end-to-end examples from the governance doc.
features/retraction.feature BDD spec for retraction lifecycle and edge cases.
features/scoring.feature BDD spec for scoring rubric rules and interpretation.
features/voting.feature BDD spec for escalation + validation voting behavior and constraints.
lib/commands.js Implements parsers for /score, /vote, /coi, /override.
lib/rvf.js Implements RVF graph/embedding helpers plus attestation read/append helpers.
lib/state-machine.js Implements a hardcoded governance state machine engine with guard evaluation.
lib/workflow-guards.js Adds reusable guard helpers for phase checks, submitter exclusion, and idempotency checks.
package.json Adds Node test scripts using node --test.
scripts/setup-labels.sh Creates required status/category labels in a target repo.
scripts/simulate-cleanup.sh Closes test issues created by simulation scripts.
scripts/simulate-full-lifecycle.sh Runs a multi-scenario fork-based simulation of the workflows.
scripts/simulate-scoring.sh Posts /score comments for simulations.
scripts/simulate-submission.sh Creates submission issues matching the issue-form output format.
scripts/simulate-voting.sh Posts /vote comments for simulations.
scripts/verify-workflows.sh Adds a local workflow-yaml structure/sanity validator script.
spec/retraction.yaml Adds a retraction-focused governance spec document.
test/commands.test.js Unit tests for slash command parsing.
test/rvf.test.js Unit tests for RVF graph/embeddings and attestation helpers.
test/state-machine.test.js Unit tests for the governance state machine transitions/guards.
test/workflow-guards.test.js Unit tests for phase guards, submitter exclusion, and idempotency helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +51 to +58
if [[ "$DELETE" == true ]]; then
echo " Deleting issue #${number}..."
gh api \
--method DELETE \
"/repos/${REPO}/issues/${number}" 2>/dev/null || {
echo " NOTE: Issue deletion requires admin access. Issue closed but not deleted."
}
DELETED=$((DELETED + 1))
Comment on lines +1 to +6
{"type":"schema","version":"1.1.0","fields":{"type":"string: transition|decision|attestation","submission_id":"string","from_state":"string","to_state":"string","actor":"string: github_username or 'agent'","timestamp":"string: ISO 8601","gdoc_revision":"string","payload":"object: state-specific data"},"note":"This entry documents the schema. Real entries follow this format. Each line is a single JSON object. This file is append-only. Never edit or delete existing entries. Signature field removed in v1.1.0 -- will be re-added when Ed25519 signing is implemented."}

{"type":"transition","submission_id":"issue-1","from_state":"new","to_state":"case-brief-generated","actor":"agent","timestamp":"2026-04-18T04:07:47.770Z","gdoc_revision":"","signature":"","payload":{"coi_flags":0,"similar_count":3,"category":"donation"}}
{"type":"transition","submission_id":"issue-2","from_state":"new","to_state":"case-brief-generated","actor":"agent","timestamp":"2026-04-18T04:07:54.270Z","gdoc_revision":"","signature":"","payload":{"coi_flags":0,"similar_count":3,"category":"website-listing"}}
{"type":"decision","submission_id":"issue-2","from_state":"active","to_state":"blocked","actor":"michaeloboyle","timestamp":"2026-04-18T04:09:50.551Z","gdoc_revision":"","signature":"","payload":{"action":"self_vote_blocked","command":"/score mission:4 quality:4 clarity:4 impact:4 risk:3"}}
{"type":"decision","submission_id":"issue-1","from_state":"active","to_state":"coi-recusal","actor":"michaeloboyle","timestamp":"2026-04-18T04:10:00.109Z","gdoc_revision":"","signature":"","payload":{"action":"coi_recusal","reason":"I am affiliated with Acme AI Labs, the submitting organization"}}
Comment on lines +260 to +263
it('is case-sensitive (GitHub logins are case-sensitive)', () => {
const result = isSubmitterExcluded('Alice', 'alice');
assert.equal(result.excluded, false);
});
Comment thread .github/workflows/ci.yml
node-version: '20'

- name: Install dependencies
run: npm ci
issue_number: context.issue.number
})).data.map(l => l.name);

const allowedPhases = ['status:triaged', 'status:scoring', 'status:pending-review'];
Comment on lines +121 to +124
const name = extract('Full Name');
const repoUrl = extract('Repository URL');
const description = body.match(/### Project Description & Request\s*\n\s*([\s\S]*?)(?=\n###|\n---|\Z)/i);
const descText = description ? description[1].trim().split('\n')[0] : '';
Comment on lines +376 to +378
# Vote retract (SEC-012 does not apply to retraction -- retraction.yml
# does not exclude the submitter from retraction votes)
post_vote "$ISSUE4" "retract"
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.

6 participants