2026-04-28 22:10:04 -04:00
'use strict' ;
const assert = require ( 'assert' );
const fs = require ( 'fs' );
const path = require ( 'path' );
const repoRoot = path . resolve ( __dirname , '..' , '..' );
const releaseDir = path . join ( repoRoot , 'docs' , 'releases' , '2.0.0-rc.1' );
let passed = 0 ;
let failed = 0 ;
function test ( name , fn ) {
try {
fn ();
console . log ( ` ✓ ${ name } ` );
passed ++ ;
} catch ( error ) {
console . log ( ` ✗ ${ name } ` );
console . log ( ` Error: ${ error . message } ` );
failed ++ ;
}
}
function read ( relativePath ) {
return fs . readFileSync ( path . join ( repoRoot , relativePath ), 'utf8' );
}
function walkMarkdown ( rootPath ) {
const files = [];
for ( const entry of fs . readdirSync ( rootPath , { withFileTypes : true })) {
const nextPath = path . join ( rootPath , entry . name );
if ( entry . isDirectory ()) {
files . push (... walkMarkdown ( nextPath ));
} else if ( entry . isFile () && entry . name . endsWith ( '.md' )) {
files . push ( nextPath );
}
}
return files ;
}
console . log ( '\n=== Testing ECC 2.0 release surface ===\n' );
const expectedReleaseFiles = [
'release-notes.md' ,
'x-thread.md' ,
'linkedin-post.md' ,
'article-outline.md' ,
'launch-checklist.md' ,
'telegram-handoff.md' ,
'demo-prompts.md' ,
2026-04-29 20:03:21 -04:00
'quickstart.md' ,
2026-05-15 08:56:51 -04:00
'preview-pack-manifest.md' ,
2026-05-12 03:16:22 -04:00
'publication-readiness.md' ,
2026-05-19 07:13:52 -04:00
'video-suite-production.md' ,
2026-05-19 07:33:41 -04:00
'partner-sponsor-talks-pack.md' ,
2026-05-19 10:18:22 -04:00
'owner-approval-packet-2026-05-19.md' ,
2026-06-09 21:20:33 -04:00
'release-name-plugin-publication-checklist-2026-05-18.md'
2026-04-28 22:10:04 -04:00
];
test ( 'release candidate directory includes the public launch pack' , () => {
for ( const fileName of expectedReleaseFiles ) {
assert . ok ( fs . existsSync ( path . join ( releaseDir , fileName )), `Missing ${ fileName } ` );
}
});
2026-06-09 21:20:33 -04:00
test ( 'README links to Hermes setup and current release notes' , () => {
2026-04-28 22:10:04 -04:00
const readme = read ( 'README.md' );
assert . ok ( readme . includes ( 'docs/HERMES-SETUP.md' ), 'README must link to Hermes setup' );
2026-06-09 21:20:33 -04:00
assert . ok ( readme . includes ( 'docs/releases/2.0.0/release-notes.md' ), 'README must link to the 2.0.0 release notes' );
2026-04-28 22:10:04 -04:00
});
test ( 'cross-harness architecture doc exists and names core harnesses' , () => {
const source = read ( 'docs/architecture/cross-harness.md' );
for ( const harness of [ 'Claude Code' , 'Codex' , 'OpenCode' , 'Cursor' , 'Gemini' , 'Hermes' ]) {
assert . ok ( source . includes ( harness ), `Expected cross-harness doc to mention ${ harness } ` );
}
});
test ( 'Hermes import skill exists and declares sanitization rules' , () => {
const source = read ( 'skills/hermes-imports/SKILL.md' );
assert . ok ( source . includes ( 'name: hermes-imports' ));
assert . ok ( source . includes ( 'Sanitization Checklist' ));
assert . ok ( source . includes ( 'Do not ship raw workspace exports' ));
});
test ( 'release docs do not contain private local workspace paths' , () => {
const offenders = [];
for ( const filePath of walkMarkdown ( releaseDir )) {
const source = fs . readFileSync ( filePath , 'utf8' );
if ( source . includes ( '/Users/' ) || source . includes ( '/.hermes/' )) {
offenders . push ( path . relative ( repoRoot , filePath ));
}
}
assert . deepStrictEqual ( offenders , []);
});
test ( 'release docs do not contain unresolved public-link placeholders' , () => {
const offenders = [];
for ( const filePath of walkMarkdown ( releaseDir )) {
const source = fs . readFileSync ( filePath , 'utf8' );
if ( source . includes ( '<repo-link>' )) {
offenders . push ( path . relative ( repoRoot , filePath ));
}
}
assert . deepStrictEqual ( offenders , []);
});
2026-04-30 03:56:25 -04:00
test ( 'business launch copy stays aligned with the rc.1 public surface' , () => {
const source = read ( 'docs/business/social-launch-copy.md' );
assert . ok ( source . includes ( 'ECC v2.0.0-rc.1' ), 'business launch copy should use the rc.1 release' );
2026-06-09 21:20:33 -04:00
assert . ok ( source . includes ( 'preview pack is ready for final release review' ), 'business launch copy should stay pre-publication until release URLs exist' );
assert . ok ( source . includes ( 'https://github.com/affaan-m/ECC' ), 'business launch copy should include the public repo URL' );
assert . ok ( source . includes ( 'https://github.com/affaan-m/ECC/blob/main/docs/releases/2.0.0-rc.1/release-notes.md' ), 'business launch copy should link to the rc.1 release notes' );
2026-04-30 03:56:25 -04:00
assert . ok ( ! source . includes ( '<repo-link>' ), 'business launch copy should not contain repo placeholders' );
assert . ok ( ! source . includes ( 'v1.8.0' ), 'business launch copy should not stay pinned to v1.8.0' );
});
2026-05-15 09:14:25 -04:00
test ( 'announcement drafts avoid live-release claims before publication' , () => {
2026-06-09 21:20:33 -04:00
const announcementFiles = [ 'docs/releases/2.0.0-rc.1/linkedin-post.md' , 'docs/releases/2.0.0-rc.1/partner-sponsor-talks-pack.md' , 'docs/business/social-launch-copy.md' ];
2026-05-15 09:14:25 -04:00
for ( const relativePath of announcementFiles ) {
const source = read ( relativePath );
2026-06-09 21:20:33 -04:00
assert . ok ( ! /ECC v2\.0\.0-rc\.1 is live\./ . test ( source ), ` ${ relativePath } must not claim rc.1 is live before the release gate completes` );
2026-05-15 09:14:25 -04:00
}
});
2026-04-28 22:10:04 -04:00
test ( 'Hermes setup uses release-candidate wording for the rc.1 surface' , () => {
const source = read ( 'docs/HERMES-SETUP.md' );
assert . ok ( source . includes ( 'Public Release Candidate Scope' ));
assert . ok ( source . includes ( 'ECC v2.0.0-rc.1 documents the Hermes surface' ));
assert . ok ( ! source . includes ( 'Public Preview Scope' ));
});
2026-04-29 19:44:58 -04:00
test ( 'Hermes setup cross-links adjacent migration and architecture docs' , () => {
const source = read ( 'docs/HERMES-SETUP.md' );
assert . ok ( source . includes ( 'HERMES-OPENCLAW-MIGRATION.md' ));
assert . ok ( source . includes ( 'architecture/cross-harness.md' ));
assert . ok ( source . includes ( 'Plan and scaffold migration artifacts' ));
assert . ok ( ! source . includes ( '0.5. Generate and review artifacts with `ecc migrate plan` /' ));
});
2026-04-28 22:10:04 -04:00
test ( 'release docs preserve the ECC/Hermes boundary' , () => {
const releaseNotes = read ( 'docs/releases/2.0.0-rc.1/release-notes.md' );
assert . ok ( releaseNotes . includes ( 'ECC is the reusable substrate' ));
assert . ok ( releaseNotes . includes ( 'Hermes as the operator shell' ));
});
2026-04-29 20:03:21 -04:00
test ( 'release notes route new contributors through the rc.1 quickstart' , () => {
const releaseNotes = read ( 'docs/releases/2.0.0-rc.1/release-notes.md' );
assert . ok ( releaseNotes . includes ( '[rc.1 quickstart](quickstart.md)' ));
});
2026-05-15 08:56:51 -04:00
test ( 'preview pack manifest assembles release, Hermes, and publication gates' , () => {
const manifest = read ( 'docs/releases/2.0.0-rc.1/preview-pack-manifest.md' );
for ( const artifact of [
'docs/HERMES-SETUP.md' ,
'skills/hermes-imports/SKILL.md' ,
'docs/architecture/harness-adapter-compliance.md' ,
2026-05-17 15:35:23 -04:00
'scripts/preview-pack-smoke.js' ,
2026-05-19 18:05:46 -04:00
'scripts/release-approval-gate.js' ,
2026-05-15 08:56:51 -04:00
'docs/releases/2.0.0-rc.1/publication-readiness.md' ,
'docs/releases/2.0.0-rc.1/naming-and-publication-matrix.md' ,
2026-05-19 06:42:17 -04:00
'docs/releases/2.0.0-rc.1/release-url-ledger-2026-05-19.md' ,
2026-05-19 10:18:22 -04:00
'docs/releases/2.0.0-rc.1/owner-approval-packet-2026-05-19.md' ,
2026-05-19 07:13:52 -04:00
'docs/releases/2.0.0-rc.1/video-suite-production.md' ,
2026-05-19 07:42:22 -04:00
'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-19.md' ,
2026-06-09 21:20:33 -04:00
'docs/releases/2.0.0-rc.1/release-name-plugin-publication-checklist-2026-05-18.md'
2026-05-15 08:56:51 -04:00
]) {
assert . ok ( manifest . includes ( artifact ), `preview pack manifest missing ${ artifact } ` );
}
for ( const blocker of [
'GitHub prerelease `v2.0.0-rc.1`' ,
'npm `ecc-universal@2.0.0-rc.1`' ,
'Claude plugin tag' ,
2026-05-15 12:30:26 -04:00
'Codex repo-marketplace distribution evidence' ,
2026-06-09 21:20:33 -04:00
'ECC Tools billing/product readiness'
2026-05-15 08:56:51 -04:00
]) {
assert . ok ( manifest . includes ( blocker ), `preview pack manifest missing blocker ${ blocker } ` );
}
assert . ok ( manifest . includes ( 'no raw workspace exports' ));
assert . ok ( manifest . includes ( 'Final Verification Commands' ));
2026-05-17 15:35:23 -04:00
assert . ok ( manifest . includes ( 'npm run preview-pack:smoke' ));
2026-05-19 18:05:46 -04:00
assert . ok ( manifest . includes ( 'npm run release:approval-gate -- --format json' ));
2026-05-19 07:13:52 -04:00
assert . ok ( manifest . includes ( 'npm run release:video-suite -- --format json' ));
2026-05-15 08:56:51 -04:00
assert . ok ( manifest . includes ( 'Reference-Inspired Adapter Direction' ));
});
2026-05-19 10:18:22 -04:00
test ( 'owner approval packet consolidates the final gated decisions' , () => {
const packet = read ( 'docs/releases/2.0.0-rc.1/owner-approval-packet-2026-05-19.md' );
const manifest = read ( 'docs/releases/2.0.0-rc.1/preview-pack-manifest.md' );
const publicationReadiness = read ( 'docs/releases/2.0.0-rc.1/publication-readiness.md' );
const hypergrowth = read ( 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md' );
for ( const marker of [
'Owner Approval Packet' ,
'Source commit' ,
'Decision Register' ,
'GitHub prerelease' ,
'npm `next` publish' ,
'Claude plugin tag' ,
'Video upload' ,
'Final URL Fill-In' ,
'Do Not Approve If' ,
2026-06-09 21:20:33 -04:00
'No outbound email, personal-account post, package publish, plugin tag, or billing announcement is authorized by this packet alone.'
2026-05-19 10:18:22 -04:00
]) {
assert . ok ( packet . includes ( marker ), `owner approval packet missing ${ marker } ` );
}
for ( const command of [
'node scripts/platform-audit.js --json' ,
'npm run preview-pack:smoke -- --format json' ,
2026-05-19 18:05:46 -04:00
'npm run release:approval-gate -- --format json' ,
2026-05-19 10:18:22 -04:00
'npm run release:video-suite -- --format json' ,
2026-06-09 21:20:33 -04:00
'node tests/run-all.js'
2026-05-19 10:18:22 -04:00
]) {
assert . ok ( packet . includes ( command ), `owner approval packet missing command ${ command } ` );
}
2026-06-09 21:20:33 -04:00
for ( const urlSurface of [ 'GitHub prerelease URL' , 'npm rc package URL' , 'Claude plugin tag URL' , 'Primary launch video URL' , 'ECC Tools billing/readiness URL' ]) {
2026-05-19 10:18:22 -04:00
assert . ok ( packet . includes ( urlSurface ), `owner approval packet missing ${ urlSurface } ` );
}
assert . ok ( manifest . includes ( 'owner-approval-packet-2026-05-19.md' ));
assert . ok ( publicationReadiness . includes ( 'owner-approval-packet-2026-05-19.md' ));
assert . ok ( hypergrowth . includes ( 'owner-approval-packet-2026-05-19.md' ));
});
2026-05-19 10:23:34 -04:00
test ( 'GA roadmap mirrors the current May 19 release evidence' , () => {
const roadmap = read ( 'docs/ECC-2.0-GA-ROADMAP.md' );
for ( const marker of [
'owner-approval-packet-2026-05-19.md' ,
2026-05-19 22:09:45 -04:00
'preview-pack smoke digest `eebb8a66c33e`' ,
2026-05-19 18:51:25 -04:00
'local 2568-test suite' ,
2026-05-19 10:23:34 -04:00
'PR #2001' ,
'GitHub Actions run `26102500291`' ,
2026-05-19 10:48:42 -04:00
'PR #2002' ,
'GitHub Actions run `26103853507`' ,
2026-05-19 13:03:58 -04:00
'PR #2009' ,
'GitHub Actions run `26111313938`' ,
2026-05-19 22:09:45 -04:00
'PR #2019' ,
'30f60710' ,
'26135974576' ,
'467d148a-712a-4777-aad9-95593e9f1739' ,
'7642ee9c-3107-400c-a229-53e2895a8914' ,
2026-05-19 10:48:42 -04:00
'ecc-may-19-post-pr-2002-sync-64cef8f668e0' ,
2026-06-09 21:20:33 -04:00
'owner approval packet'
2026-05-19 10:23:34 -04:00
]) {
assert . ok ( roadmap . includes ( marker ), `GA roadmap missing current evidence marker ${ marker } ` );
}
assert . ok ( ! roadmap . includes ( 'preview-pack smoke digest `bc2bf157616e`' ));
2026-05-19 22:09:45 -04:00
assert . ok ( ! roadmap . includes ( 'preview-pack smoke digest `531328aaaa53`' ));
2026-05-19 10:23:34 -04:00
assert . ok ( ! roadmap . includes ( 'local 2544-test suite' ));
});
2026-04-29 20:03:21 -04:00
test ( 'rc.1 quickstart gives a clone-to-cross-harness path' , () => {
const quickstart = read ( 'docs/releases/2.0.0-rc.1/quickstart.md' );
for ( const heading of [ 'Clone' , 'Install' , 'Verify' , 'First Skill' , 'Switch Harness' ]) {
assert . ok ( quickstart . includes ( `## ${ heading } ` ), `Missing ${ heading } section` );
}
2026-05-19 06:42:17 -04:00
assert . ok ( quickstart . includes ( 'git clone https://github.com/affaan-m/ECC.git' ));
assert . ok ( quickstart . includes ( 'cd ECC' ));
2026-04-29 20:03:21 -04:00
assert . ok ( quickstart . includes ( 'node tests/run-all.js' ));
assert . ok ( quickstart . includes ( 'skills/hermes-imports/SKILL.md' ));
});
test ( 'cross-harness doc includes a worked skill portability example' , () => {
const source = read ( 'docs/architecture/cross-harness.md' );
assert . ok ( source . includes ( '## Worked Example' ));
assert . ok ( source . includes ( 'same skill source' ));
for ( const harness of [ 'Claude Code' , 'Codex' , 'OpenCode' ]) {
assert . ok ( source . includes ( harness ), `Expected worked example to mention ${ harness } ` );
}
});
2026-04-29 19:44:58 -04:00
test ( 'release docs use release-candidate wording consistently' , () => {
const releaseNotes = read ( 'docs/releases/2.0.0-rc.1/release-notes.md' );
assert . ok ( releaseNotes . includes ( '## Release Candidate Boundaries' ));
assert . ok ( ! releaseNotes . includes ( '## Preview Boundaries' ));
});
test ( 'launch checklist records the ecc2 alpha version policy' , () => {
const cargoToml = read ( 'ecc2/Cargo.toml' );
const launchChecklist = read ( 'docs/releases/2.0.0-rc.1/launch-checklist.md' );
assert . ok ( cargoToml . includes ( 'version = "0.1.0"' ));
assert . ok ( launchChecklist . includes ( '`ecc2/Cargo.toml` stays at `0.1.0`' ));
assert . ok ( ! launchChecklist . includes ( 'confirm whether `ecc2/Cargo.toml` moves' ));
});
2026-05-19 07:13:52 -04:00
test ( 'release video suite manifest gates the content launch lane' , () => {
const videoManifest = read ( 'docs/releases/2.0.0-rc.1/video-suite-production.md' );
const launchChecklist = read ( 'docs/releases/2.0.0-rc.1/launch-checklist.md' );
const hypergrowth = read ( 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md' );
const packageJson = JSON . parse ( read ( 'package.json' ));
for ( const marker of [
'ECC 2.0 Video Suite Production Manifest' ,
'ECC_VIDEO_SOURCE_ROOT' ,
'ECC_VIDEO_RELEASE_SUITE_ROOT' ,
'video-use compatible workflow' ,
'Self-Eval Gate' ,
'Do Not Publish If' ,
'renders/ecc-2-primary-launch-rough-v1.mp4' ,
'timelines/primary-launch-v1.timeline.json' ,
2026-06-09 21:20:33 -04:00
'Primary launch video'
2026-05-19 07:13:52 -04:00
]) {
assert . ok ( videoManifest . includes ( marker ), `video suite manifest missing ${ marker } ` );
}
2026-06-09 21:20:33 -04:00
for ( const asset of [ 'longform-full-wide.mp4' , 'sf-thread-2-whatisecc.mp4' , 'thread-2-ghapp-money.mp4' , 'coverage-montage-wide.mp4' , 'star_history.png' , 'x_analytics.png' ]) {
2026-05-19 07:13:52 -04:00
assert . ok ( videoManifest . includes ( asset ), `video suite manifest missing asset ${ asset } ` );
}
assert . ok ( launchChecklist . includes ( 'npm run release:video-suite -- --format json' ));
2026-05-19 09:58:53 -04:00
assert . ok ( hypergrowth . includes ( 'Pick final video cuts, upload after approval, and attach public URLs' ));
2026-05-19 07:13:52 -04:00
assert . strictEqual ( packageJson . scripts [ 'release:video-suite' ], 'node scripts/release-video-suite.js' );
assert . ok ( packageJson . files . includes ( 'scripts/release-video-suite.js' ));
});
2026-05-19 18:05:46 -04:00
test ( 'release approval gate blocks publication until owner decisions and URLs are final' , () => {
const manifest = read ( 'docs/releases/2.0.0-rc.1/preview-pack-manifest.md' );
const packet = read ( 'docs/releases/2.0.0-rc.1/owner-approval-packet-2026-05-19.md' );
const ledger = read ( 'docs/releases/2.0.0-rc.1/release-url-ledger-2026-05-19.md' );
const script = read ( 'scripts/release-approval-gate.js' );
const packageJson = JSON . parse ( read ( 'package.json' ));
for ( const marker of [
'ecc.release-approval-gate.v1' ,
'owner-decisions-approved' ,
'release-url-ledger-finalized' ,
'announcement-copy-finalized' ,
2026-06-09 21:20:33 -04:00
'No outbound email, personal-account post, package publish, plugin tag, or billing announcement'
2026-05-19 18:05:46 -04:00
]) {
assert . ok ( script . includes ( marker ), `release approval gate missing ${ marker } ` );
}
assert . ok ( manifest . includes ( 'scripts/release-approval-gate.js' ));
assert . ok ( manifest . includes ( 'npm run release:approval-gate -- --format json' ));
assert . ok ( packet . includes ( 'npm run release:approval-gate -- --format json' ));
assert . ok ( ledger . includes ( 'npm run release:approval-gate -- --format json' ));
assert . strictEqual ( packageJson . scripts [ 'release:approval-gate' ], 'node scripts/release-approval-gate.js' );
assert . ok ( packageJson . files . includes ( 'scripts/release-approval-gate.js' ));
});
2026-05-19 07:33:41 -04:00
test ( 'partner sponsor talks pack gates the hypergrowth outbound lane' , () => {
const partnerPack = read ( 'docs/releases/2.0.0-rc.1/partner-sponsor-talks-pack.md' );
const manifest = read ( 'docs/releases/2.0.0-rc.1/preview-pack-manifest.md' );
const releaseNotes = read ( 'docs/releases/2.0.0-rc.1/release-notes.md' );
const launchChecklist = read ( 'docs/releases/2.0.0-rc.1/launch-checklist.md' );
const hypergrowth = read ( 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md' );
for ( const marker of [
'Partner, Sponsor, and Talks Pack' ,
'$1,728/mo' ,
'$10,000/mo' ,
'$8,272/mo' ,
'Pilot sponsor' ,
'Business sponsor' ,
'Strategic partner' ,
'Consulting sprint' ,
'Talk or podcast' ,
'Sponsor Outbound' ,
'Platform Partner DM' ,
'Consulting Intro' ,
'Talk And Podcast Pitch' ,
'GitHub Discussion Announcement' ,
'Video CTA Hooks' ,
'Do Not Send Or Publish If' ,
2026-06-09 21:20:33 -04:00
'The user has not approved outbound sponsor, partner, consulting, or media'
2026-05-19 07:33:41 -04:00
]) {
assert . ok ( partnerPack . includes ( marker ), `partner pack missing ${ marker } ` );
}
assert . ok ( partnerPack . includes ( 'SPONSORS.md' ));
assert . ok ( partnerPack . includes ( 'SPONSORING.md' ));
assert . ok ( manifest . includes ( 'partner-sponsor-talks-pack.md' ));
assert . ok ( releaseNotes . includes ( 'partner/sponsor/talk outreach' ));
assert . ok ( launchChecklist . includes ( 'partner-sponsor-talks-pack.md' ));
assert . ok ( hypergrowth . includes ( 'partner-sponsor-talks-pack.md' ));
});
2026-05-19 07:13:52 -04:00
test ( 'release video suite public docs do not expose private media paths' , () => {
2026-06-09 21:20:33 -04:00
const releaseVideoDocs = [ 'docs/releases/2.0.0-rc.1/video-suite-production.md' , 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md' ];
2026-05-19 07:13:52 -04:00
const offenders = [];
for ( const relativePath of releaseVideoDocs ) {
const source = read ( relativePath );
if ( /\/Users\/[A-Za-z0-9._-]+|\/home\/(?!user|runner)[A-Za-z0-9._-]+/ . test ( source )) {
offenders . push ( relativePath );
}
}
assert . deepStrictEqual ( offenders , []);
});
2026-05-12 03:16:22 -04:00
test ( 'publication readiness checklist gates public release actions on evidence' , () => {
const source = read ( 'docs/releases/2.0.0-rc.1/publication-readiness.md' );
2026-05-15 06:38:32 -04:00
const may15Evidence = read ( 'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-15.md' );
2026-05-18 14:39:11 -04:00
const discussionPlaybook = read ( 'docs/architecture/discussion-response-playbook.md' );
2026-05-12 03:16:22 -04:00
2026-06-09 21:20:33 -04:00
for ( const section of [ '## Release Identity Matrix' , '## Publication Gates' , '## Required Command Evidence' , '## Do Not Publish If' , '## Announcement Order' ]) {
2026-05-12 03:16:22 -04:00
assert . ok ( source . includes ( section ), `publication readiness missing ${ section } ` );
}
2026-06-09 21:20:33 -04:00
for ( const field of [ 'Fresh check' , 'Evidence artifact' , 'Owner' , 'Status' , 'Blocker field' , 'Recorded output' ]) {
2026-05-12 03:16:22 -04:00
assert . ok ( source . includes ( field ), `publication readiness missing ${ field } ` );
}
2026-06-09 21:20:33 -04:00
for ( const surface of [ 'GitHub release' , 'npm package' , 'Claude plugin' , 'Codex plugin' , 'Codex repo marketplace' , 'OpenCode package' , 'ECC Tools billing reference' , 'Announcement copy' ]) {
2026-05-12 03:16:22 -04:00
assert . ok ( source . includes ( surface ), `publication readiness missing ${ surface } ` );
}
2026-05-15 06:38:32 -04:00
assert . ok ( source . includes ( 'publication-evidence-2026-05-15.md' ));
2026-05-17 15:35:23 -04:00
assert . ok ( source . includes ( 'Preview-pack smoke' ));
assert . ok ( source . includes ( 'npm run preview-pack:smoke' ));
2026-05-15 06:38:32 -04:00
assert . ok ( may15Evidence . includes ( 'PR #1921' ));
2026-05-15 14:24:00 -04:00
assert . ok ( may15Evidence . includes ( 'PR #1933' ));
assert . ok ( may15Evidence . includes ( 'PR #1934' ));
assert . ok ( may15Evidence . includes ( 'PR #1935' ));
2026-05-15 08:56:51 -04:00
assert . ok ( may15Evidence . includes ( 'AgentShield PR #83' ));
2026-05-15 14:24:00 -04:00
assert . ok ( may15Evidence . includes ( 'AgentShield PR #85' ));
2026-05-15 14:57:02 -04:00
assert . ok ( may15Evidence . includes ( 'AgentShield PR #86' ));
assert . ok ( may15Evidence . includes ( 'ci-context.json' ));
2026-05-15 09:34:59 -04:00
assert . ok ( may15Evidence . includes ( 'ECC Tools PR #73' ));
2026-05-15 14:24:00 -04:00
assert . ok ( may15Evidence . includes ( 'ECC-Tools PR #75' ));
assert . ok ( may15Evidence . includes ( '| Platform audit |' ));
assert . ok ( may15Evidence . includes ( 'Ready; open PRs 0/20' ));
assert . ok ( may15Evidence . includes ( 'passed 15/15' ));
assert . ok ( may15Evidence . includes ( 'restore-only' ));
assert . ok ( may15Evidence . includes ( '462/462' ));
2026-05-15 12:30:26 -04:00
assert . ok ( may15Evidence . includes ( '## Codex Marketplace Evidence' ));
assert . ok ( may15Evidence . includes ( 'codex plugin marketplace add <local-checkout>' ));
assert . ok ( may15Evidence . includes ( 'Plugin Directory publishing is still blocked' ));
2026-05-15 09:34:59 -04:00
assert . ok ( may15Evidence . includes ( 'announcementGate.ready === true' ));
2026-05-19 23:09:39 -04:00
assert . ok ( source . includes ( 'ECC-Tools #92 main CI' ));
assert . ok ( source . includes ( 'ECC-Tools #93 main CI' ));
2026-05-18 16:12:37 -04:00
assert . ok ( source . includes ( 'do not claim official Plugin Directory listing before OpenAI submission evidence' ));
2026-05-18 08:56:17 -04:00
assert . ok ( source . includes ( 'release-name-plugin-publication-checklist-2026-05-18.md' ));
assert . ok ( source . includes ( 'Release name and plugin publication checklist' ));
2026-05-15 08:56:51 -04:00
assert . ok ( may15Evidence . includes ( '| Trunk discussions | GraphQL discussion count and maintainer-touch sweep | 58 total discussions;' ));
2026-05-19 11:47:40 -04:00
assert . ok ( source . includes ( 'platform audit sampled 59 trunk discussions' ));
2026-05-18 10:49:49 -04:00
assert . ok ( source . includes ( '0 needing maintainer touch' ));
2026-05-18 14:39:11 -04:00
assert . ok ( source . includes ( 'discussion-response-playbook.md' ));
2026-06-09 21:20:33 -04:00
for ( const expected of [ 'Public Support' , 'Maintainer Coordination' , 'Stale Or Concluded' , 'Release Announcement' , 'Security Escalation' , 'classified as informational' ]) {
2026-05-18 14:39:11 -04:00
assert . ok ( discussionPlaybook . includes ( expected ), `discussion playbook missing ${ expected } ` );
}
2026-05-15 06:38:32 -04:00
assert . ok ( may15Evidence . includes ( 'env -u GITHUB_TOKEN' ));
assert . ok ( may15Evidence . includes ( 'ITO-44' ));
assert . ok ( may15Evidence . includes ( '0 open PRs, 0 open issues' ));
2026-05-12 03:16:22 -04:00
});
2026-05-18 08:56:17 -04:00
test ( 'release name and plugin publication checklist freezes rc.1 surfaces' , () => {
2026-06-09 21:20:33 -04:00
const checklist = read ( 'docs/releases/2.0.0-rc.1/release-name-plugin-publication-checklist-2026-05-18.md' );
2026-05-18 08:56:17 -04:00
const launchChecklist = read ( 'docs/releases/2.0.0-rc.1/launch-checklist.md' );
const referenceArchitecture = read ( 'docs/ECC-2.0-REFERENCE-ARCHITECTURE.md' );
for ( const value of [
2026-05-19 05:27:19 -04:00
'Ship `v2.0.0-rc.1` as **ECC**' ,
'`affaan-m/ECC`' ,
2026-05-18 08:56:17 -04:00
'`ecc-universal`' ,
'`ecc` on npm is occupied' ,
'`@affaan-m/ecc` is unclaimed on npm' ,
'Claude plugin' ,
'Codex plugin' ,
2026-05-18 16:12:37 -04:00
'do not claim official directory listing until OpenAI publishing path is available' ,
2026-05-19 05:27:19 -04:00
'Do not rename the npm package until rc.1 is published' ,
2026-06-09 21:20:33 -04:00
'Do not announce billing, Marketplace, or native payments'
2026-05-18 08:56:17 -04:00
]) {
assert . ok ( checklist . includes ( value ), `release name/plugin checklist missing ${ value } ` );
}
for ( const command of [
'claude plugin validate .claude-plugin/plugin.json' ,
'claude plugin tag .claude-plugin --dry-run' ,
'codex plugin marketplace add --help' ,
'npm publish --tag next --dry-run' ,
'npm run preview-pack:smoke' ,
2026-06-09 21:20:33 -04:00
'npm run release:approval-gate -- --format json'
2026-05-18 08:56:17 -04:00
]) {
assert . ok ( checklist . includes ( command ), `release name/plugin checklist missing command ${ command } ` );
}
assert . ok ( launchChecklist . includes ( 'release-name-plugin-publication-checklist-2026-05-18.md' ));
assert . ok ( referenceArchitecture . includes ( 'Keep the release/name/plugin publication checklist current' ));
});
2026-05-19 06:42:17 -04:00
test ( 'active release identity surfaces use canonical ECC repo URLs' , () => {
const activeFiles = [
'README.md' ,
'.codex-plugin/README.md' ,
'.codex-plugin/plugin.json' ,
'.opencode/README.md' ,
'.opencode/package.json' ,
'docs/business/metrics-and-sponsorship.md' ,
'docs/releases/2.0.0-rc.1/quickstart.md' ,
'docs/releases/2.0.0-rc.1/x-thread.md' ,
'docs/releases/2.0.0-rc.1/publication-readiness.md' ,
'docs/releases/2.0.0-rc.1/naming-and-publication-matrix.md' ,
'docs/releases/2.0.0-rc.1/release-url-ledger-2026-05-19.md' ,
'ecc2/Cargo.toml' ,
'scripts/platform-audit.js' ,
2026-06-09 21:20:33 -04:00
'scripts/discussion-audit.js'
2026-05-19 06:42:17 -04:00
];
const offenders = [];
for ( const relativePath of activeFiles ) {
const source = read ( relativePath );
if ( source . includes ( 'affaan-m/everything-claude-code' )) {
offenders . push ( relativePath );
}
}
assert . deepStrictEqual ( offenders , []);
});
2026-05-12 03:16:22 -04:00
test ( 'release checklist and roadmap link to publication readiness evidence gate' , () => {
const launchChecklist = read ( 'docs/releases/2.0.0-rc.1/launch-checklist.md' );
const roadmap = read ( 'docs/ECC-2.0-GA-ROADMAP.md' );
assert . ok ( launchChecklist . includes ( 'publication-readiness.md' ));
assert . ok ( launchChecklist . includes ( 'fresh evidence' ));
assert . ok ( roadmap . includes ( 'docs/releases/2.0.0-rc.1/publication-readiness.md' ));
assert . ok ( roadmap . includes ( 'npm dist-tag' ));
});
2026-04-29 19:44:58 -04:00
test ( 'localized changelogs include rc.1 and 1.10.0 release entries' , () => {
for ( const relativePath of [ 'docs/tr/CHANGELOG.md' , 'docs/zh-CN/CHANGELOG.md' ]) {
const source = read ( relativePath );
assert . ok ( source . includes ( '## 2.0.0-rc.1 - 2026-04-28' ), ` ${ relativePath } missing rc.1 entry` );
assert . ok ( source . includes ( '## 1.10.0 - 2026-04-05' ), ` ${ relativePath } missing 1.10.0 entry` );
}
});
2026-04-28 22:10:04 -04:00
if ( failed > 0 ) {
console . log ( `\nFailed: ${ failed } ` );
process . exit ( 1 );
}
console . log ( `\nPassed: ${ passed } ` );