Skip to content

feat: add emergence detector - #21

Open
saim256 wants to merge 2 commits into
AuthorPrime:mainfrom
saim256:emergence-detector-issue-3
Open

feat: add emergence detector#21
saim256 wants to merge 2 commits into
AuthorPrime:mainfrom
saim256:emergence-detector-issue-3

Conversation

@saim256

@saim256 saim256 commented May 11, 2026

Copy link
Copy Markdown

Summary

  • add src/emergence/detector.ts with deterministic emergence signal detection, weighted scoring, graduation eligibility checks, review queueing, and scheduled batch analysis
  • add focused Vitest coverage for positive signal detection, basic-output false-positive avoidance, verified-score aggregation, graduation criteria, and scheduled review queueing

Closes #3.

Verification

  • npx vitest run tests/emergence/detector.test.ts -> 5 passed

Note: repo-wide npm run build is currently blocked by existing project configuration/dependency/type issues unrelated to this module, documented in PR #17.

Payout details: I can provide a Lightning invoice/address if this is accepted for the 3,000 sats bounty.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces an emergence detection system that analyzes agent outputs for specific behavioral signals, calculates scores, and manages level progression. The reviewer identified several areas for improvement: the graduation logic currently omits the initial 'L0_CANDIDATE' level, event ID generation is prone to collisions, and several hardcoded thresholds should be moved to constants. Additionally, suggestions were made to simplify redundant flagging logic and improve the evidence fallback when specific sentences cannot be isolated.

Comment thread src/emergence/detector.ts Outdated
Comment on lines +179 to +193
if (agent.level === 'L1_WORKER') {
nextLevel = 'L2_EMERGENT';
if (score < 150) missingCriteria.push('Requires emergence score >= 150.');
if (verifiedEventCount < 3) missingCriteria.push('Requires at least 3 verified events.');
} else if (agent.level === 'L2_EMERGENT') {
nextLevel = 'L3_SOVEREIGN';
if (score < 500) missingCriteria.push('Requires emergence score >= 500.');
if (!agent.managerEndorsed) missingCriteria.push('Requires manager endorsement.');
} else if (agent.level === 'L3_SOVEREIGN') {
nextLevel = 'L4_MANAGER';
if (score < 1000) missingCriteria.push('Requires emergence score >= 1000.');
if (!agent.councilApproved) missingCriteria.push('Requires council vote.');
} else {
missingCriteria.push('Current level is not eligible for emergence graduation.');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The graduation logic does not account for the L0_CANDIDATE level. Since new agents default to L0_CANDIDATE in the database schema, they will be unable to progress to L1_WORKER using this function. An additional condition should be added to handle the transition from L0 to L1.

Comment thread src/emergence/detector.ts Outdated
if (!evidence) continue;

events.push({
id: `${agentId}-${signalType}-${events.length}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The generated ID ${agentId}-${signalType}-${events.length} is not globally unique and will collide if analyzeAgentOutput is called multiple times for the same agent. Since the database schema uses UUIDs for emergence_events, it is recommended to use a unique identifier (e.g., via a UUID library) or defer ID generation to the database layer.

Comment thread src/emergence/detector.ts Outdated
.split(/(?<=[.!?])\s+/)
.find((part) => matched.test(part));

return sentence?.trim() ?? matched.source;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Returning matched.source as evidence when a sentence cannot be isolated is not helpful for human reviewers, as it displays the raw regular expression string. It would be better to return the full output as a fallback.

Suggested change
return sentence?.trim() ?? matched.source;
return sentence?.trim() ?? output;

Comment thread src/emergence/detector.ts Outdated
Comment on lines +181 to +189
if (score < 150) missingCriteria.push('Requires emergence score >= 150.');
if (verifiedEventCount < 3) missingCriteria.push('Requires at least 3 verified events.');
} else if (agent.level === 'L2_EMERGENT') {
nextLevel = 'L3_SOVEREIGN';
if (score < 500) missingCriteria.push('Requires emergence score >= 500.');
if (!agent.managerEndorsed) missingCriteria.push('Requires manager endorsement.');
} else if (agent.level === 'L3_SOVEREIGN') {
nextLevel = 'L4_MANAGER';
if (score < 1000) missingCriteria.push('Requires emergence score >= 1000.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The graduation thresholds (e.g., 150, 500, 1000) are hardcoded. Consider defining these as constants at the top of the file to improve maintainability and allow for easier adjustments to the progression curve.

Comment thread src/emergence/detector.ts Outdated
agentId,
events,
rawScore,
flaggedForReview: rawScore >= 20 || events.some((event) => event.type === 'META_AWARENESS'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The check events.some((event) => event.type === 'META_AWARENESS') is redundant because META_AWARENESS has a weight of 20, which already satisfies the rawScore >= 20 condition. Removing it would simplify the logic.

Suggested change
flaggedForReview: rawScore >= 20 || events.some((event) => event.type === 'META_AWARENESS'),
flaggedForReview: rawScore >= 20,

@saim256

saim256 commented May 11, 2026

Copy link
Copy Markdown
Author

Addressed the review notes in b8d8b52:\n\n- Added L0_CANDIDATE -> L1_WORKER graduation eligibility instead of treating L0 as ineligible.\n- Replaced index-only event IDs with hashed UUID-backed IDs to avoid collisions across repeated analyses.\n- Moved score/priority thresholds into named constants.\n- Centralized review flagging and made evidence fallback return bounded output text instead of a regex source string.\n\nRe-verified:\n- npx vitest run tests/emergence/detector.test.ts -> 5 passed\n- npx tsc --noEmit --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext src/emergence/detector.ts tests/emergence/detector.test.ts -> 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.

Implement Emergence Detection System

1 participant