@t275005746/gse 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gse/state.json +147 -26
- package/CHANGELOG.md +19 -3
- package/README.md +13 -6
- package/README.zh-CN.md +13 -6
- package/SKILL.md +32 -12
- package/assets/templates/dispatch-packet.md +22 -14
- package/assets/templates/evidence.md +11 -5
- package/assets/templates/role-fallback-packet.md +49 -0
- package/package.json +18 -10
- package/references/agent-roles.md +41 -20
- package/references/commands.md +74 -45
- package/references/drift-audit.md +2 -1
- package/references/evidence-taxonomy.md +46 -9
- package/references/file-ownership.md +17 -13
- package/references/final-form-roadmap.md +201 -0
- package/references/final-readiness.md +3 -3
- package/references/host-adapters.md +38 -10
- package/references/learning-system.md +24 -8
- package/references/maintenance-cadence.md +51 -0
- package/references/project-guards.md +52 -0
- package/references/quality-gates.md +18 -11
- package/references/role-dispatch-fallback.md +54 -0
- package/references/tool-adapters.md +13 -3
- package/scripts/audit-close-gate-hardening.mjs +188 -0
- package/scripts/audit-close-gate.mjs +219 -33
- package/scripts/audit-command-execution.mjs +30 -17
- package/scripts/audit-commands.mjs +7 -5
- package/scripts/audit-completion-plan-drill.mjs +230 -0
- package/scripts/audit-completion-readiness.mjs +9 -6
- package/scripts/audit-continue-preflight.mjs +234 -0
- package/scripts/audit-evidence-levels.mjs +217 -0
- package/scripts/audit-evidence-review-queue.mjs +206 -0
- package/scripts/audit-final-acceptance-packet.mjs +9 -9
- package/scripts/audit-final-form-progress-report.mjs +19 -18
- package/scripts/audit-final-form-roadmap.mjs +157 -0
- package/scripts/audit-final-form-stale-copy.mjs +2 -2
- package/scripts/audit-final-readiness.mjs +3 -3
- package/scripts/audit-fresh-session-readiness.mjs +1 -1
- package/scripts/audit-host-capabilities.mjs +237 -0
- package/scripts/audit-installed-sync.mjs +203 -0
- package/scripts/audit-learning-drift.mjs +292 -0
- package/scripts/audit-learning-promotion.mjs +351 -0
- package/scripts/audit-learning-system.mjs +24 -14
- package/scripts/audit-local-final-form-completion.mjs +11 -10
- package/scripts/audit-maintenance-cadence.mjs +139 -0
- package/scripts/audit-maintenance-snapshot.mjs +181 -0
- package/scripts/audit-npm-package-metadata.mjs +8 -2
- package/scripts/audit-npm-publish-dry-run.mjs +10 -4
- package/scripts/audit-npm-tarball-install.mjs +9 -3
- package/scripts/audit-owner-external-gate-kit.mjs +12 -11
- package/scripts/audit-project-guards.mjs +189 -0
- package/scripts/audit-project.mjs +14 -11
- package/scripts/audit-public-acceptance-handoff.mjs +10 -10
- package/scripts/audit-public-acceptance-readiness.mjs +6 -6
- package/scripts/audit-public-release-checklist.mjs +17 -15
- package/scripts/audit-release-bundle.mjs +13 -11
- package/scripts/audit-release-owner-action-plan-drill.mjs +5 -4
- package/scripts/audit-release-owner-action-plan.mjs +10 -10
- package/scripts/audit-release-status-manifest.mjs +4 -4
- package/scripts/audit-roadmap-consistency.mjs +11 -7
- package/scripts/audit-role-dispatch-fallback.mjs +212 -0
- package/scripts/audit-session-sync.mjs +127 -0
- package/scripts/audit-state-freshness.mjs +6 -5
- package/scripts/audit-state-repair.mjs +360 -0
- package/scripts/audit-target-hardening-drills.mjs +267 -0
- package/scripts/audit-tool-fallback-policy.mjs +180 -0
- package/scripts/audit-ui-browser-evidence-policy.mjs +191 -0
- package/scripts/audit-validation-profiles.mjs +6 -4
- package/scripts/backfill-evidence-levels.mjs +98 -0
- package/scripts/check-encoding.mjs +72 -0
- package/scripts/generate-continue-packet.mjs +1214 -0
- package/scripts/generate-final-acceptance-packet.mjs +23 -8
- package/scripts/generate-final-form-progress-report.mjs +25 -23
- package/scripts/generate-host-runtime-evidence-handoff.mjs +23 -16
- package/scripts/generate-maintenance-snapshot.mjs +216 -0
- package/scripts/generate-public-acceptance-handoff.mjs +26 -14
- package/scripts/generate-release-owner-action-plan.mjs +4 -3
- package/scripts/generate-release-status-manifest.mjs +4 -3
- package/scripts/init-project.mjs +144 -63
- package/scripts/record-learning.mjs +37 -8
- package/scripts/record-session-sync.mjs +87 -0
- package/scripts/run-gse-command.mjs +79 -47
- package/scripts/run-validation-profile.mjs +24 -5
- package/scripts/validate-gse.mjs +216 -0
|
@@ -101,8 +101,8 @@ const gateGuidance = {
|
|
|
101
101
|
const finalReadiness = run(process.execPath, [path.join(root, 'scripts', 'audit-final-readiness.mjs'), '--root', root, '--json'])
|
|
102
102
|
const finalReadinessData = parseJson(finalReadiness.stdout)
|
|
103
103
|
const matrix = finalReadinessData?.matrix ?? []
|
|
104
|
-
const pendingGates = matrix
|
|
105
|
-
.filter((row) => row.status
|
|
104
|
+
const pendingGates = matrix
|
|
105
|
+
.filter((row) => row.status === 'owner-required' || row.status === 'external-required')
|
|
106
106
|
.map((row) => {
|
|
107
107
|
const rawCommand = gateGuidance[row.area]?.command ?? 'No command mapping exists yet.'
|
|
108
108
|
const recordCommand = shellSafePlaceholders(rawCommand)
|
|
@@ -133,9 +133,9 @@ const pendingCommandsAreExecutableTemplates = pendingGates.every((gate) =>
|
|
|
133
133
|
(gate.recordCommand.includes('record-host-invocation.mjs') ? gate.recordCommand.includes('--status accepted') : true),
|
|
134
134
|
)
|
|
135
135
|
const expectedGatesCoveredByMatrix = expectedFinalGates.every((gate) => matrixGateNames.has(gate))
|
|
136
|
-
const ownerExternalGatesRemainHonest = matrix.every((row) => row.status === 'verified' || row.status === 'owner-required' || row.status === 'external-required')
|
|
136
|
+
const ownerExternalGatesRemainHonest = matrix.every((row) => row.status === 'verified' || row.status === 'owner-required' || row.status === 'external-required' || row.status === 'not-claimed')
|
|
137
137
|
const publicAccepted = finalReadinessData?.workflows?.publicAccepted ?? 'unknown'
|
|
138
|
-
const claimBoundaryHonest = publicAccepted === 'verified' ? pendingGates.length === 0 : pendingGates.length > 0
|
|
138
|
+
const claimBoundaryHonest = publicAccepted === 'verified' ? pendingGates.length === 0 : pendingGates.length > 0
|
|
139
139
|
|
|
140
140
|
const checks = [
|
|
141
141
|
check('PAD01', 'final readiness audit runs before public acceptance diagnosis', finalReadiness.status === 0 && finalReadinessData?.summary?.status === 'passed', finalReadiness.command, finalReadiness.stderr),
|
|
@@ -144,7 +144,7 @@ const checks = [
|
|
|
144
144
|
check('PAD03b', 'pending final gates expose dry-run preflight commands', currentPendingRowsHavePreflightCommands, pendingGates.map((gate) => `${gate.area} -> ${gate.preflightCommand}`).join('; ')),
|
|
145
145
|
check('PAD03c', 'pending final gate commands are complete executable templates', pendingCommandsAreExecutableTemplates, pendingGates.map((gate) => `${gate.area} -> ${gate.recordCommand}`).join('; ')),
|
|
146
146
|
check('PAD04', 'pending final gates keep owner/external responsibility visible', pendingGates.every((gate) => gate.owner !== 'unknown'), pendingGates.map((gate) => `${gate.area}:${gate.owner}`).join(', ')),
|
|
147
|
-
check('PAD05', 'final readiness statuses remain honest
|
|
147
|
+
check('PAD05', 'final readiness statuses remain honest when required gates are accepted and optional claims are not-claimed', ownerExternalGatesRemainHonest && claimBoundaryHonest, `publicAccepted=${publicAccepted}; pending=${pendingGates.length}`),
|
|
148
148
|
check('PAD06', 'doctor does not claim external acceptance from local mechanics', publicAccepted !== 'verified' || pendingGates.length === 0, 'public acceptance follows final-readiness matrix only'),
|
|
149
149
|
]
|
|
150
150
|
|
|
@@ -170,7 +170,7 @@ const report = {
|
|
|
170
170
|
nextPreflightCommands: pendingGates.map((gate) => gate.preflightCommand),
|
|
171
171
|
limits: [
|
|
172
172
|
'This doctor identifies missing owner/external evidence and record commands.',
|
|
173
|
-
'It does not choose a license, publish a package, configure a public repository, run public CI, approve a marketplace listing, or prove host-native slash commands.',
|
|
173
|
+
'It does not choose a license, publish a package, configure a public repository, run public CI, approve a marketplace listing, or prove optional host-native slash commands.',
|
|
174
174
|
'A gate is accepted only after a real accepted record is created and final readiness is re-audited.',
|
|
175
175
|
],
|
|
176
176
|
checks,
|
|
@@ -66,8 +66,9 @@ const checklistData = checklistRun ? parseJson(checklistRun.stdout) : null
|
|
|
66
66
|
const canonicalChecklist = read('.gse/acceptance/public-release-checklist.md')
|
|
67
67
|
rmSync(tmp, { recursive: true, force: true })
|
|
68
68
|
|
|
69
|
-
const pendingGates = manifest?.publicAcceptance?.pendingGates ?? []
|
|
70
|
-
const
|
|
69
|
+
const pendingGates = manifest?.publicAcceptance?.pendingGates ?? []
|
|
70
|
+
const hasPendingGates = pendingGates.length > 0
|
|
71
|
+
const expectedAreas = pendingGates.map((gate) => gate.area)
|
|
71
72
|
const requiredPhases = [
|
|
72
73
|
'01. Prepare the release bundle',
|
|
73
74
|
'02. Publish and configure the public repository',
|
|
@@ -82,24 +83,25 @@ const expectedScripts = [...new Set(pendingGates
|
|
|
82
83
|
.map((gate) => String(gate.recordCommand ?? '').match(/scripts\/([\w-]+\.mjs)/)?.[1])
|
|
83
84
|
.filter(Boolean))]
|
|
84
85
|
const noLocalPaths = !/[A-Z]:\\|C:\\Users\\|D:\\codex\\/i.test(checklist) && !/[A-Z]:\\|C:\\Users\\|D:\\codex\\/i.test(canonicalChecklist)
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
checklist.includes('
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
checklist.includes('/gse release
|
|
91
|
-
checklist.includes('/gse
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
canonicalChecklist.includes(`
|
|
86
|
+
const publicAcceptedStatus = manifest?.publicAcceptance?.publicAccepted ?? 'unknown'
|
|
87
|
+
const noFalseAcceptance = checklist.includes('Public accepted: ' + publicAcceptedStatus) &&
|
|
88
|
+
checklist.includes('does not publish, approve, or accept') &&
|
|
89
|
+
checklist.includes('A gate is complete only after real accepted evidence')
|
|
90
|
+
const commandCoverage = (hasPendingGates ? expectedScripts.every((script) => checklist.includes(script)) : true) &&
|
|
91
|
+
checklist.includes('/gse release') &&
|
|
92
|
+
checklist.includes('/gse release --execute --out <bundle>') &&
|
|
93
|
+
checklist.includes('/gse probe')
|
|
94
|
+
const canonicalFresh = canonicalChecklist.includes('GSE Public Release Checklist') &&
|
|
95
|
+
requiredPhases.every((phase) => canonicalChecklist.includes(phase)) &&
|
|
96
|
+
(hasPendingGates ? expectedAreas.every((area) => canonicalChecklist.includes(`Gate: ${area}`)) : canonicalChecklist.includes('Public accepted: verified')) &&
|
|
97
|
+
canonicalChecklist.includes(`Pending owner/external gates: ${pendingGates.length}`)
|
|
96
98
|
|
|
97
99
|
const checks = [
|
|
98
100
|
check('PRC01', 'public release checklist generator exists', exists('scripts/generate-public-release-checklist.mjs'), 'scripts/generate-public-release-checklist.mjs'),
|
|
99
101
|
check('PRC02', 'generator writes checklist from release status manifest', checklistRun?.status === 0 && checklistData?.status === 'written' && checklist.includes('GSE Public Release Checklist'), 'generate-public-release-checklist.mjs'),
|
|
100
102
|
check('PRC03', 'checklist uses ordered public release runway phases', requiredPhases.every((phase) => checklist.includes(phase)), 'public-release-checklist.md'),
|
|
101
|
-
check('PRC04', 'checklist covers every pending owner/external gate',
|
|
102
|
-
check('PRC05', 'checklist includes executable preflight and record command families', commandCoverage && checklist.includes('Preflight:') && checklist.includes('Record accepted evidence:'), 'public-release-checklist.md'),
|
|
103
|
+
check('PRC04', 'checklist covers every pending owner/external gate', hasPendingGates ? expectedAreas.every((area) => checklist.includes(`Gate: ${area}`)) : checklist.includes('Pending owner/external gates: 0'), 'release-status-manifest pending gates'),
|
|
104
|
+
check('PRC05', 'checklist includes executable preflight and record command families', commandCoverage && (hasPendingGates ? (checklist.includes('Preflight:') && checklist.includes('Record accepted evidence:')) : checklist.includes('Final Verification')), 'public-release-checklist.md'),
|
|
103
105
|
check('PRC06', 'checklist preserves public acceptance boundary', noFalseAcceptance, 'public-release-checklist.md'),
|
|
104
106
|
check('PRC07', 'checklist avoids local machine paths', noLocalPaths, 'public-release-checklist.md'),
|
|
105
107
|
check('PRC08', 'canonical checklist is fresh against current manifest', canonicalFresh, '.gse/acceptance/public-release-checklist.md'),
|
|
@@ -87,9 +87,11 @@ const installablePackageManifest = readBundle('installable-package/gse-package-m
|
|
|
87
87
|
const provenance = readBundle('provenance.json')
|
|
88
88
|
const checksums = readBundle('checksums.sha256')
|
|
89
89
|
const releaseStatusData = parseJson(releaseStatusManifest)
|
|
90
|
-
const pendingGates = releaseStatusData?.publicAcceptance?.pendingGates ?? []
|
|
91
|
-
const pendingAreas = pendingGates.map((gate) => gate.area)
|
|
92
|
-
const
|
|
90
|
+
const pendingGates = releaseStatusData?.publicAcceptance?.pendingGates ?? []
|
|
91
|
+
const pendingAreas = pendingGates.map((gate) => gate.area)
|
|
92
|
+
const hasPendingGates = pendingGates.length > 0
|
|
93
|
+
const publicAcceptedStatus = releaseStatusData?.publicAcceptance?.publicAccepted ?? releaseStatusData?.claimBoundary?.publicAccepted ?? 'unknown'
|
|
94
|
+
const hasPendingRegistryPublication = pendingAreas.includes('Public registry publication')
|
|
93
95
|
const bundleManifestData = parseJson(manifest)
|
|
94
96
|
const ownerExternalGateKitData = parseJson(ownerExternalGateKitManifest)
|
|
95
97
|
const installablePackageManifestData = parseJson(installablePackageManifest)
|
|
@@ -171,30 +173,30 @@ const checks = [
|
|
|
171
173
|
check('RB04', 'bundle preserves license decision and public release boundary', summary.includes('Accepted public release: not accepted') && record.includes('License status: selected') && record.includes('SPDX identifier: MIT') && record.includes('Evidence status: accepted'), 'release-summary.md, public-release-record.md'),
|
|
172
174
|
check('RB05', 'bundle includes install, validation, and installed CLI commands', summary.includes('installable-package/') && summary.includes('install-gse.mjs') && summary.includes('validate-gse.mjs') && summary.includes('scripts/gse.mjs status') && checklist.includes('audit-remote-distribution.mjs'), 'release-summary.md, validation-checklist.md'),
|
|
173
175
|
check('RB05b', 'bundle includes host runtime drill before cross-host handoff', summary.includes('audit-host-runtime-invocation-drill.mjs') && checklist.includes('audit-host-runtime-invocation-drill.mjs'), 'release-summary.md, validation-checklist.md'),
|
|
174
|
-
check('RB06', 'bundle manifest records validation and limits', manifest.includes('"validation"') && manifest.includes('Bundle does not choose a license') && bundleManifestData?.publicReleaseAcceptance ===
|
|
176
|
+
check('RB06', 'bundle manifest records validation and limits', manifest.includes('"validation"') && manifest.includes('Bundle does not choose a license') && bundleManifestData?.publicReleaseAcceptance === publicAcceptedStatus && bundleManifestData?.licenseDecision === 'accepted' && manifest.includes('"publicAcceptanceHandoff": "included"') && manifest.includes('"hostRuntimeEvidenceHandoff": "included"') && manifest.includes('"releaseStatusManifest": "included"') && manifest.includes('"releaseOwnerActionPlan": "included"'), 'bundle-manifest.json'),
|
|
175
177
|
check('RB06v', 'bundle manifest records compact validation check details', Array.isArray(bundleManifestData?.validationChecks) && bundleManifestData.validationChecks.some((item) => item.id === 'validate-09o' && item.label === 'public evidence placeholder helper audit' && item.command?.includes('audit-evidence-placeholders.mjs')) && summary.includes('Validation manifest detail'), 'bundle-manifest.json, release-summary.md'),
|
|
176
178
|
check('RB06v2', 'canonical bundle manifest records current validation check details', Array.isArray(canonicalBundleManifestData?.validationChecks) && canonicalBundleManifestData.validationChecks.some((item) => item.id === 'validate-09o' && item.label === 'public evidence placeholder helper audit' && item.command?.includes('audit-evidence-placeholders.mjs')), '.gse/release-bundles/gse-release-bundle-audit/bundle-manifest.json'),
|
|
177
179
|
check('RB06v3', 'bundle manifest records installable package snapshot', bundleManifestData?.installablePackage?.path === 'installable-package/' && bundleManifestData?.installablePackage?.manifest === 'installable-package/gse-package-manifest.json' && bundleManifestData?.installablePackage?.algorithm === 'sha256' && bundleManifestData?.installablePackage?.cli === 'scripts/gse.mjs', 'bundle-manifest.json installablePackage'),
|
|
178
180
|
check('RB06v4', 'bundle installable package manifest is valid', installablePackageManifestData?.integrity?.algorithm === 'sha256' && installablePackageManifestData?.entrypoints?.cli === 'scripts/gse.mjs' && installablePackageManifestData?.fileHashes?.['SKILL.md'], 'installable-package/gse-package-manifest.json'),
|
|
179
181
|
check('RB06v5', 'bundle installable package installs and installed CLI runs', installFromBundle.status === 0 && installFromBundleData?.status === 'passed' && installFromBundleData?.summary?.integrityFailed === 0 && installedFromBundleCli.status === 0 && installedFromBundleCliData?.command === '/gse status' && installedFromBundleCliData?.project?.stateValid === true, 'installable-package install and gse status'),
|
|
180
|
-
check('RB06v6', 'bundle provenance records local generation boundaries', provenanceData?.generator === 'scripts/generate-release-bundle.mjs' && provenanceData?.installablePackage?.packageDigest === installablePackageManifestData?.integrity?.packageDigest && provenanceData?.publicAcceptance?.status ===
|
|
182
|
+
check('RB06v6', 'bundle provenance records local generation boundaries', provenanceData?.generator === 'scripts/generate-release-bundle.mjs' && provenanceData?.installablePackage?.packageDigest === installablePackageManifestData?.integrity?.packageDigest && provenanceData?.publicAcceptance?.status === publicAcceptedStatus && Array.isArray(provenanceData?.claimBoundaries) && provenanceData.claimBoundaries.some((item) => item.includes('not a registry attestation')), 'provenance.json'),
|
|
181
183
|
check('RB06v7', 'bundle checksums verify installable package files', verifyChecksumFile(), 'checksums.sha256'),
|
|
182
184
|
check('RB06v8', 'bundle provenance and checksums do not expose local paths', !hasLocalPathLeak(provenance) && !hasLocalPathLeak(checksums), 'provenance.json, checksums.sha256'),
|
|
183
185
|
check('RB06a', 'bundle manifest does not expose local source root or Node install path', bundleManifestData && !Object.hasOwn(bundleManifestData, 'sourceRoot') && !hasLocalPathLeak(manifest), 'bundle-manifest.json'),
|
|
184
|
-
check('RB06b', 'bundle includes public acceptance handoff boundaries', handoff.includes('GSE Public Acceptance Handoff') && handoff.includes('Public accepted:
|
|
186
|
+
check('RB06b', 'bundle includes public acceptance handoff boundaries', handoff.includes('GSE Public Acceptance Handoff') && handoff.includes('Public accepted: ' + publicAcceptedStatus) && handoff.includes('Do not claim public release acceptance'), 'public-acceptance-handoff.md'),
|
|
185
187
|
check('RB06b2', 'bundle public acceptance handoff uses current registry publication CLI flag when pending', !hasPendingRegistryPublication || (handoff.includes('--proves-registry-publication true') && !handoff.includes('--proves-public-registry-publication')), 'public-acceptance-handoff.md'),
|
|
186
|
-
check('RB06b3', 'bundle public acceptance handoff includes dry-run preflight commands', handoff.includes('Preflight command') && handoff.includes('--dry-run --json'), 'public-acceptance-handoff.md'),
|
|
188
|
+
check('RB06b3', 'bundle public acceptance handoff includes dry-run preflight commands', hasPendingGates ? (handoff.includes('Preflight command') && handoff.includes('--dry-run --json')) : handoff.includes('No owner/external acceptance gate is pending'), 'public-acceptance-handoff.md'),
|
|
187
189
|
check('RB06c', 'bundle includes host runtime evidence handoff boundaries', hostHandoff.includes('GSE Host Runtime Evidence Handoff') && hostHandoff.includes('Do not claim native slash-command support') && hostHandoff.includes('record-host-invocation.mjs'), 'host-runtime-evidence-handoff.md'),
|
|
188
|
-
check('RB06d', 'bundle includes machine-readable release status manifest', releaseStatusData?.claimBoundary?.publicAccepted ===
|
|
190
|
+
check('RB06d', 'bundle includes machine-readable release status manifest', releaseStatusData?.claimBoundary?.publicAccepted === publicAcceptedStatus && releaseStatusManifest.includes('"releaseStatusManifest"') && releaseStatusManifest.includes('"localInstalledCli": "verified"') && releaseStatusManifest.includes('"remoteInstalledCli": "verified"') && releaseStatusManifest.includes('"nativeSlashCommandRecords": 0') && releaseStatusManifest.includes('"fixtureDrill": "verified"') && releaseStatusManifest.includes('"fixtureEvidenceIsPersistent": false'), 'release-status-manifest.json'),
|
|
189
191
|
check('RB06d2', 'bundle release status manifest includes dry-run preflight commands', (releaseStatusData?.publicAcceptance?.nextPreflightCommands?.length ?? 0) === (releaseStatusData?.publicAcceptance?.pendingGates?.length ?? -1) && releaseStatusData.publicAcceptance.nextPreflightCommands.every((command) => command.includes('--dry-run --json')), 'release-status-manifest.json'),
|
|
190
192
|
check('RB06d3', 'bundle release status manifest includes preflight command drill', releaseStatusData?.verificationCommands?.some((command) => command.includes('audit-public-acceptance-command-dry-run-drill.mjs')), 'release-status-manifest.json'),
|
|
191
193
|
check('RB06e', 'bundle includes owner-facing release action plan', releaseOwnerActionPlan.includes('GSE Release Owner Action Plan') && pendingGates.every((gate) => releaseOwnerActionPlan.includes('#### ' + gate.area)) && !releaseOwnerActionPlan.includes('record-public-release.mjs') && releaseOwnerActionPlan.includes('Local validation does not mean public acceptance'), 'release-owner-action-plan.md'),
|
|
192
|
-
check('RB06e2', 'bundle owner action plan includes dry-run preflight commands and drill', releaseOwnerActionPlan.includes('Preflight command') && releaseOwnerActionPlan.includes('--dry-run --json') && releaseOwnerActionPlan.includes('audit-public-acceptance-command-dry-run-drill.mjs'), 'release-owner-action-plan.md'),
|
|
194
|
+
check('RB06e2', 'bundle owner action plan includes dry-run preflight commands and drill', (hasPendingGates ? (releaseOwnerActionPlan.includes('Preflight command') && releaseOwnerActionPlan.includes('--dry-run --json')) : releaseOwnerActionPlan.includes('No pending owner or external gates were reported by the manifest.')) && releaseOwnerActionPlan.includes('audit-public-acceptance-command-dry-run-drill.mjs'), 'release-owner-action-plan.md'),
|
|
193
195
|
check('RB06e3', 'canonical release bundle owner action plans match current manifest counts and pending gates', planMatchesManifestCounts(canonicalBundleReleaseOwnerActionPlan, canonicalReleaseStatusManifest) && planMatchesManifestCounts(canonicalBundleKitReleaseOwnerActionPlan, canonicalReleaseStatusManifest), '.gse/release-bundles/gse-release-bundle-audit/release-owner-action-plan.md'),
|
|
194
|
-
check('RB06e4', 'bundle includes linear public release checklist', publicReleaseChecklist.includes('GSE Public Release Checklist') && publicReleaseChecklist.includes('01. Prepare the release bundle') && publicReleaseChecklist.includes('08. Record other host runtime invocation evidence') && publicReleaseChecklist.includes('Public accepted:
|
|
196
|
+
check('RB06e4', 'bundle includes linear public release checklist', publicReleaseChecklist.includes('GSE Public Release Checklist') && publicReleaseChecklist.includes('01. Prepare the release bundle') && publicReleaseChecklist.includes('08. Record other host runtime invocation evidence') && publicReleaseChecklist.includes('Public accepted: ' + publicAcceptedStatus) && publicReleaseChecklist.includes('/gse release --execute --out <bundle>'), 'public-release-checklist.md'),
|
|
195
197
|
check('RB06e5', 'canonical release bundle checklist matches pending gate count', canonicalBundlePublicReleaseChecklist.includes('GSE Public Release Checklist') && canonicalBundlePublicReleaseChecklist.includes('Pending owner/external gates: ' + (canonicalReleaseStatusManifest?.publicAcceptance?.pendingGates?.length ?? 0)), '.gse/release-bundles/gse-release-bundle-audit/public-release-checklist.md'),
|
|
196
198
|
check('RB06f', 'bundle includes owner/external gate execution kit', ownerExternalGateKitReadme.includes('GSE Owner / External Gate Kit') && ownerExternalGateKitData?.pendingGateCount === releaseStatusData?.publicAcceptance?.pendingGates?.length && ownerExternalGateKitData?.generatedFresh?.finalAcceptancePacket === true && !ownerExternalGateKitRecordCommands.includes('record-public-release.mjs'), 'owner-external-gate-kit/'),
|
|
197
|
-
check('RB06f2', 'bundle owner/external gate kit includes dry-run preflight commands', ownerExternalGateKitRecordCommands.includes('Preflight command') && ownerExternalGateKitRecordCommands.includes('--dry-run --json'), 'owner-external-gate-kit/record-commands.md'),
|
|
199
|
+
check('RB06f2', 'bundle owner/external gate kit includes dry-run preflight commands', hasPendingGates ? (ownerExternalGateKitRecordCommands.includes('Preflight command') && ownerExternalGateKitRecordCommands.includes('--dry-run --json')) : ownerExternalGateKitData?.pendingGateCount === 0, 'owner-external-gate-kit/record-commands.md'),
|
|
198
200
|
check('RB06f3', 'bundle owner/external gate kit includes preflight command drill', ownerExternalGateKitVerificationCommands.includes('audit-public-acceptance-command-dry-run-drill.mjs'), 'owner-external-gate-kit/verification-commands.md'),
|
|
199
201
|
check('RB07', 'validator includes release bundle audit', validate.includes('audit-release-bundle.mjs'), 'scripts/validate-gse.mjs'),
|
|
200
202
|
check('RB08', 'packaging docs route release bundle command', packaging.includes('generate-release-bundle.mjs') && packaging.includes('audit-release-bundle.mjs'), 'references/packaging.md'),
|
|
@@ -78,8 +78,9 @@ const generatePlan = runFixtureScript(fixture, 'generate-release-owner-action-pl
|
|
|
78
78
|
])
|
|
79
79
|
const manifest = fs.existsSync(manifestPath) ? parseJson(fs.readFileSync(manifestPath, 'utf8')) : null
|
|
80
80
|
const plan = fs.existsSync(planPath) ? fs.readFileSync(planPath, 'utf8') : ''
|
|
81
|
-
const pendingGates = manifest?.publicAcceptance?.pendingGates ?? []
|
|
82
|
-
const
|
|
81
|
+
const pendingGates = manifest?.publicAcceptance?.pendingGates ?? []
|
|
82
|
+
const hasPendingGates = pendingGates.length > 0
|
|
83
|
+
const commandScripts = requiredCommandScriptsFor(pendingGates)
|
|
83
84
|
|
|
84
85
|
const recordRuns = [
|
|
85
86
|
runFixtureScript(fixture, 'record-public-security-contact.mjs', [
|
|
@@ -214,8 +215,8 @@ const recordFailures = recordRuns.filter((item) => item.status !== 0)
|
|
|
214
215
|
const promotedRows = finalReadinessData?.matrix?.filter((row) => row.status === 'verified') ?? []
|
|
215
216
|
|
|
216
217
|
const checks = [
|
|
217
|
-
check('ROAD01', 'release status manifest and owner action plan generate in fixture', generateManifest.status === 0 && generatePlan.status === 0 && manifest?.publicAcceptance?.publicAccepted
|
|
218
|
-
check('ROAD02', 'owner action plan covers all pending gates from manifest',
|
|
218
|
+
check('ROAD01', 'release status manifest and owner action plan generate in fixture', generateManifest.status === 0 && generatePlan.status === 0 && ['not-accepted', 'verified'].includes(manifest?.publicAcceptance?.publicAccepted) && plan.includes('GSE Release Owner Action Plan'), 'generate manifest and action plan'),
|
|
219
|
+
check('ROAD02', 'owner action plan covers all pending gates from manifest', hasPendingGates ? (pendingGates.every((gate) => plan.includes(gate.area) && plan.includes(gate.recordCommand)) && !pendingGates.some((gate) => gate.area === 'License decision')) : manifest?.publicAcceptance?.publicAccepted === 'verified' && plan.includes('No pending owner or external gates were reported by the manifest.'), `${pendingGates.length} pending gate(s); License decision resolved`),
|
|
219
220
|
check('ROAD03', 'owner action plan commands map to real record scripts', expectedScripts.every((script) => commandScripts.includes(script)) && !plan.includes('proves-public-registry-publication'), commandScripts.join(', ')),
|
|
220
221
|
check('ROAD04', 'accepted fixture records can be created for every owner/external gate family', recordFailures.length === 0, recordFailures.map((item) => item.stderr || item.stdout || item.command).join('; ') || 'all fixture records written'),
|
|
221
222
|
check('ROAD05', 'final readiness promotes to publicAccepted verified after fixture records', finalReadiness.status === 0 && finalReadinessData?.workflows?.publicAccepted === 'verified' && promotedRows.length >= 22, finalReadinessData?.workflows?.publicAccepted ?? 'unknown'),
|
|
@@ -77,14 +77,14 @@ const verifiedRows = manifest?.readiness?.verified?.length ?? 0
|
|
|
77
77
|
const ownerRequiredRows = manifest?.readiness?.ownerRequired?.length ?? 0
|
|
78
78
|
const externalRequiredRows = manifest?.readiness?.externalRequired?.length ?? 0
|
|
79
79
|
const publicAccepted = manifest?.publicAcceptance?.publicAccepted ?? manifest?.claimBoundary?.publicAccepted ?? 'unknown'
|
|
80
|
-
const requiredOwners = ['project owner', 'repository owner', 'external CI', 'external registry', 'external marketplace', 'host runtime']
|
|
80
|
+
const requiredOwners = ['project owner', 'repository owner', 'external CI', 'external registry', 'external marketplace', 'host runtime']
|
|
81
81
|
const recordCommands = [...new Set(pendingGates
|
|
82
82
|
.map((gate) => String(gate.recordCommand ?? '').match(/node scripts\/([^ ]+)/)?.[1] ?? '')
|
|
83
83
|
.filter(Boolean))]
|
|
84
|
-
const planUsesCompleteRecordCommandTemplates = !plan.includes('--invocation-status') &&
|
|
85
|
-
!/record-[a-z-]+\.mjs[\s\S]*\.\.\./.test(plan) &&
|
|
86
|
-
!/record-[a-z-]+\.mjs[^\n`]*[<>]/.test(plan) &&
|
|
87
|
-
plan.includes('--status accepted')
|
|
84
|
+
const planUsesCompleteRecordCommandTemplates = pendingGates.length === 0 || (!plan.includes('--invocation-status') &&
|
|
85
|
+
!/record-[a-z-]+\.mjs[\s\S]*\.\.\./.test(plan) &&
|
|
86
|
+
!/record-[a-z-]+\.mjs[^\n`]*[<>]/.test(plan) &&
|
|
87
|
+
plan.includes('--status accepted'))
|
|
88
88
|
const planVerificationCommandsAreShellSafe = !/(audit-[a-z-]+|validate-gse|generate-release-status-manifest)\.mjs[^\n`]*[<>]/.test(plan) &&
|
|
89
89
|
plan.includes('__GSE__')
|
|
90
90
|
const canonicalPlanMatchesCurrentManifest = canonicalPlan.includes('- Public accepted: ' + publicAccepted) &&
|
|
@@ -98,11 +98,11 @@ const checks = [
|
|
|
98
98
|
check('ROAP01', 'release owner action plan generator exists', exists('scripts/generate-release-owner-action-plan.mjs'), 'scripts/generate-release-owner-action-plan.mjs'),
|
|
99
99
|
check('ROAP02', 'generator reads release status manifest', generator.includes('release-status-manifest.json') && generator.includes('pendingGates') && generator.includes('recordCommand'), 'generator source'),
|
|
100
100
|
check('ROAP03', 'generator writes parseable action plan report', generatedPlan?.status === 0 && generatedData?.status === 'written' && plan.includes('GSE Release Owner Action Plan'), generatedPlan?.stderr || tmpPlan),
|
|
101
|
-
check('ROAP04', 'plan preserves public acceptance boundary', plan.includes('Public accepted:
|
|
101
|
+
check('ROAP04', 'plan preserves public acceptance boundary', plan.includes('Public accepted: verified') && plan.includes('Local validation does not mean public acceptance') && plan.includes('Native slash-command support requires a real host invocation record only when a host adapter claims it'), 'claim boundary'),
|
|
102
102
|
check('ROAP05', 'plan groups actions by responsible owner', requiredOwners.every((owner) => plan.includes(owner.replace(/\b\w/g, (char) => char.toUpperCase())) || pendingGates.every((gate) => gate.owner !== owner)), 'owner groups'),
|
|
103
|
-
check('ROAP06', 'plan includes every pending gate area', pendingGates.length > 0 && pendingGates.every((gate) => plan.includes(gate.area)) && !plan.includes('#### License decision'), 'pending gate areas
|
|
104
|
-
check('ROAP07', 'plan includes concrete record commands', recordCommands.length > 0 && recordCommands.every((command) => plan.includes(command)), recordCommands.join(', ')),
|
|
105
|
-
check('ROAP08', 'plan includes dry-run preflight commands and post-action verification commands', plan.includes('Preflight command') && plan.includes('--dry-run --json') && plan.includes('validate-gse.mjs') && plan.includes('audit-public-acceptance-command-dry-run-drill.mjs') && plan.includes('audit-release-owner-action-plan.mjs') && plan.includes('generate-release-status-manifest.mjs'), 'dry-run preflight and verification commands'),
|
|
103
|
+
check('ROAP06', 'plan includes every pending gate area or states none are pending', (pendingGates.length === 0 && plan.includes('No pending owner or external gates were reported by the manifest')) || (pendingGates.length > 0 && pendingGates.every((gate) => plan.includes(gate.area)) && !plan.includes('#### License decision')), 'pending gate areas'),
|
|
104
|
+
check('ROAP07', 'plan includes concrete record commands when actions are pending', pendingGates.length === 0 || (recordCommands.length > 0 && recordCommands.every((command) => plan.includes(command))), recordCommands.join(', ') || 'none'),
|
|
105
|
+
check('ROAP08', 'plan includes dry-run preflight commands when needed and post-action verification commands', (pendingGates.length === 0 || (plan.includes('Preflight command') && plan.includes('--dry-run --json'))) && plan.includes('validate-gse.mjs') && plan.includes('audit-public-acceptance-command-dry-run-drill.mjs') && plan.includes('audit-release-owner-action-plan.mjs') && plan.includes('generate-release-status-manifest.mjs'), 'dry-run preflight and verification commands'),
|
|
106
106
|
check('ROAP08b', 'plan uses complete record command templates', planUsesCompleteRecordCommandTemplates, 'no ellipsis, no stale host invocation flag, host records use --status accepted'),
|
|
107
107
|
check('ROAP09', 'skill routes users to release owner action plan', skill.includes('generate-release-owner-action-plan.mjs'), 'SKILL.md'),
|
|
108
108
|
check('ROAP10', 'packaging docs route release owner action plan', packaging.includes('generate-release-owner-action-plan.mjs') && packaging.includes('audit-release-owner-action-plan.mjs'), 'references/packaging.md'),
|
|
@@ -125,7 +125,7 @@ const report = {
|
|
|
125
125
|
},
|
|
126
126
|
limits: [
|
|
127
127
|
'This audit verifies generation of an owner-facing action plan from the release status manifest.',
|
|
128
|
-
'It does not create
|
|
128
|
+
'It does not create optional host-native slash-command evidence.',
|
|
129
129
|
],
|
|
130
130
|
checks,
|
|
131
131
|
}
|
|
@@ -98,11 +98,11 @@ const checks = [
|
|
|
98
98
|
check('RSM01', 'release status manifest generator exists', exists('scripts/generate-release-status-manifest.mjs'), 'scripts/generate-release-status-manifest.mjs'),
|
|
99
99
|
check('RSM02', 'generator composes authoritative non-circular audits', ['audit-final-readiness.mjs', 'audit-public-acceptance-readiness.mjs', 'audit-host-runtime-invocations.mjs', 'audit-host-runtime-invocation-drill.mjs'].every((term) => generator.includes(term)) && !generator.includes("audit('audit-release-bundle.mjs')") && !generator.includes("audit('audit-distribution.mjs')"), 'generator source audits'),
|
|
100
100
|
check('RSM03', 'generator writes parseable manifest', generated?.status === 0 && generatedData?.status === 'written' && manifest?.schemaVersion === 1, generated?.stderr || out),
|
|
101
|
-
check('RSM04', 'manifest preserves public acceptance boundary', manifest?.claimBoundary?.publicAccepted === '
|
|
102
|
-
check('RSM05', 'manifest covers verified rows and
|
|
101
|
+
check('RSM04', 'manifest preserves public acceptance boundary', manifest?.claimBoundary?.publicAccepted === 'verified' && manifest?.claimBoundary?.localValidationDoesNotMeanPublicAcceptance === true && manifest?.claimBoundary?.nativeSlashCommandIsOptionalAdapterClaim === true, 'publicAccepted verified; native slash optional adapter claim'),
|
|
102
|
+
check('RSM05', 'manifest covers verified rows and optional not-claimed rows', (manifest?.readiness?.verified?.length ?? 0) > 0 && (manifest?.readiness?.notClaimed?.length ?? 0) > 0 && ((manifest?.readiness?.ownerRequired?.length ?? 0) + (manifest?.readiness?.externalRequired?.length ?? 0)) === 0, 'readiness row groups'),
|
|
103
103
|
check('RSM06', 'manifest covers install and distribution status', requiredDistribution.every((key) => manifest?.distribution?.[key]), requiredDistribution.join(', ')),
|
|
104
|
-
check('RSM07', 'manifest
|
|
105
|
-
check('RSM07b', 'manifest
|
|
104
|
+
check('RSM07', 'manifest has no public acceptance next commands when no required gates remain', (manifest?.publicAcceptance?.pendingGates?.length ?? -1) === 0 && (manifest?.publicAcceptance?.nextCommands?.length ?? -1) === 0, 'pending gates and next commands'),
|
|
105
|
+
check('RSM07b', 'manifest has no public acceptance dry-run preflight commands when no required gates remain', (manifest?.publicAcceptance?.pendingGates?.length ?? -1) === 0 && (manifest?.publicAcceptance?.nextPreflightCommands?.length ?? -1) === 0, 'pending gates and preflight commands'),
|
|
106
106
|
check('RSM08', 'manifest covers host runtime evidence counts', Number.isInteger(manifest?.hostRuntime?.nativeSlashCommandRecords) && Number.isInteger(manifest?.hostRuntime?.portableTextCommandRecords) && manifest.hostRuntime.nativeSlashCommandRecords >= 0 && manifest.hostRuntime.portableTextCommandRecords >= 0, `native ${manifest?.hostRuntime?.nativeSlashCommandRecords ?? 'unknown'}, portable ${manifest?.hostRuntime?.portableTextCommandRecords ?? 'unknown'}`),
|
|
107
107
|
check('RSM08b', 'manifest covers host runtime fixture drill status', manifest?.hostRuntime?.fixtureDrill === 'verified' && manifest?.hostRuntime?.fixtureNativeSlashCommandRecords === 1 && manifest?.hostRuntime?.fixturePortableTextCommandRecords === 4 && manifest?.hostRuntime?.fixtureEvidenceIsPersistent === false, `drill ${manifest?.hostRuntime?.fixtureDrill ?? 'unknown'}, fixture native ${manifest?.hostRuntime?.fixtureNativeSlashCommandRecords ?? 'unknown'}, fixture portable ${manifest?.hostRuntime?.fixturePortableTextCommandRecords ?? 'unknown'}`),
|
|
108
108
|
check('RSM09', 'manifest points to handoff artifacts', requiredArtifacts.every((key) => manifest?.artifacts?.[key]), requiredArtifacts.join(', ')),
|
|
@@ -67,9 +67,11 @@ const requiredVerifiedAssets = [
|
|
|
67
67
|
'assets/templates/public-repository-settings-record.md',
|
|
68
68
|
'scripts/audit-gse.mjs',
|
|
69
69
|
'scripts/validate-gse.mjs',
|
|
70
|
-
'scripts/audit-target-project.mjs',
|
|
71
|
-
'scripts/generate-session-prompt.mjs',
|
|
72
|
-
'scripts/
|
|
70
|
+
'scripts/audit-target-project.mjs',
|
|
71
|
+
'scripts/generate-session-prompt.mjs',
|
|
72
|
+
'scripts/generate-continue-packet.mjs',
|
|
73
|
+
'scripts/audit-continue-preflight.mjs',
|
|
74
|
+
'scripts/run-gse-command.mjs',
|
|
73
75
|
'scripts/audit-command-execution.mjs',
|
|
74
76
|
'scripts/audit-close-gate.mjs',
|
|
75
77
|
'scripts/update-project-state.mjs',
|
|
@@ -108,8 +110,10 @@ const requiredVerifiedAssets = [
|
|
|
108
110
|
'scripts/record-host-invocation.mjs',
|
|
109
111
|
'scripts/audit-host-runtime-invocations.mjs',
|
|
110
112
|
'references/final-readiness.md',
|
|
111
|
-
'scripts/audit-final-readiness.mjs',
|
|
112
|
-
'
|
|
113
|
+
'scripts/audit-final-readiness.mjs',
|
|
114
|
+
'references/final-form-roadmap.md',
|
|
115
|
+
'scripts/audit-final-form-roadmap.mjs',
|
|
116
|
+
'scripts/audit-final-readiness-promotion.mjs',
|
|
113
117
|
'scripts/audit-final-form-stale-copy.mjs',
|
|
114
118
|
'scripts/generate-final-acceptance-packet.mjs',
|
|
115
119
|
'scripts/audit-final-acceptance-packet.mjs',
|
|
@@ -135,7 +139,7 @@ const currentStatusTerms = [
|
|
|
135
139
|
'native `.gse/changes/<change-id>/` change pack generation',
|
|
136
140
|
'execution-quality pack templates',
|
|
137
141
|
'domain model reference and ADR template are verified',
|
|
138
|
-
'role docs, dispatch packet, file ownership,
|
|
142
|
+
'role docs, dispatch packet, file ownership, forward-test fallback, role fallback packet template, scaffolded `.gse/agents/role-fallback-packets.md`, and role dispatch fallback audit are verified',
|
|
139
143
|
'review protocol and architecture health references are verified',
|
|
140
144
|
'v0.2 - Self-Auditing GSE',
|
|
141
145
|
'Status: verified.',
|
|
@@ -186,7 +190,7 @@ const checks = [
|
|
|
186
190
|
check('RC03', 'master plan no longer contains stale missing/planned status phrases', stalePhrases.every((phrase) => !masterPlan.includes(phrase)), stalePhrases.join(', ')),
|
|
187
191
|
check('RC04', 'master plan contains current verified status terms', currentStatusTerms.every((term) => masterPlan.includes(term)), currentStatusTerms.join(', ')),
|
|
188
192
|
check('RC05', 'goal map tracks v1 execution-state work as verified', goalMap.includes('GSE-008') && goalMap.includes('Productize v1.0 execution-state workflow') && goalMap.includes('verified') && goalMap.includes('audit-v1-target-validation.mjs'), '.gse/goal-map.md'),
|
|
189
|
-
check('RC06', 'master plan preserves target validation
|
|
193
|
+
check('RC06', 'master plan preserves target validation and routes final-form execution through the roadmap contract', masterPlan.includes('AION/MuseFlow v1 target validation are verified') && masterPlan.includes('MIT license decision') && masterPlan.includes('public registry publication for `@t275005746/gse@0.1.0`') && masterPlan.includes('The Final Form Roadmap now lives in `references/final-form-roadmap.md`') && masterPlan.includes('/gse continue` now runs a hard preflight and returns a compact action prompt plus state packet') && masterPlan.includes('AION and MuseFlow remain the primary real-project drills') && !masterPlan.includes('This does not yet prove the full v1.0 execution-state layer') && !masterPlan.includes('owner license selection remains required before an accepted public release'), '.gse/gse-design-master-plan.md'),
|
|
190
194
|
]
|
|
191
195
|
|
|
192
196
|
const passed = checks.filter((item) => item.status === 'passed').length
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { spawnSync } from 'node:child_process'
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2)
|
|
9
|
+
|
|
10
|
+
function readArg(name, fallback = null) {
|
|
11
|
+
const index = args.indexOf(name)
|
|
12
|
+
if (index === -1) return fallback
|
|
13
|
+
return args[index + 1] ?? fallback
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
17
|
+
const targetArg = readArg('--target')
|
|
18
|
+
const jsonOnly = args.includes('--json')
|
|
19
|
+
|
|
20
|
+
const requiredRoles = ['Planner', 'Locator', 'Implementer', 'Verifier', 'Reviewer', 'Docs/Evidence', 'Release']
|
|
21
|
+
const allowedModes = new Set(['real-subagent', 'sequential-role', 'handoff-session'])
|
|
22
|
+
const allowedDelegation = new Set(['yes', 'no'])
|
|
23
|
+
const allowedToolStatuses = new Set(['verified', 'documented', 'unknown', 'unavailable'])
|
|
24
|
+
|
|
25
|
+
function readText(filePath) {
|
|
26
|
+
return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '') : ''
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseRoleTable(text) {
|
|
30
|
+
const rows = []
|
|
31
|
+
for (const line of text.split(/\r?\n/)) {
|
|
32
|
+
const trimmed = line.trim()
|
|
33
|
+
if (!trimmed.startsWith('|')) continue
|
|
34
|
+
if (/^\|\s*-+/.test(trimmed)) continue
|
|
35
|
+
if (/^\|\s*Role\s*\|/i.test(trimmed)) continue
|
|
36
|
+
const cells = trimmed
|
|
37
|
+
.slice(1, trimmed.endsWith('|') ? -1 : undefined)
|
|
38
|
+
.split('|')
|
|
39
|
+
.map((cell) => cell.trim())
|
|
40
|
+
if (cells.length < 8) continue
|
|
41
|
+
rows.push({
|
|
42
|
+
role: cells[0],
|
|
43
|
+
mode: cells[1],
|
|
44
|
+
realDelegationUsed: cells[2],
|
|
45
|
+
toolStatus: cells[3],
|
|
46
|
+
fallbackOutput: cells[4],
|
|
47
|
+
evidence: cells[5],
|
|
48
|
+
stopCondition: cells[6],
|
|
49
|
+
writeAccess: cells[7],
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
return rows
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function readRoleDispatchFallback(target) {
|
|
56
|
+
const filePath = path.join(target, '.gse', 'agents', 'role-fallback-packets.md')
|
|
57
|
+
const exists = fs.existsSync(filePath)
|
|
58
|
+
const text = exists ? readText(filePath) : ''
|
|
59
|
+
const packets = parseRoleTable(text)
|
|
60
|
+
const roleSet = new Set(packets.map((packet) => packet.role))
|
|
61
|
+
const missingRoles = requiredRoles.filter((role) => !roleSet.has(role))
|
|
62
|
+
const invalidMode = packets.filter((packet) => !allowedModes.has(packet.mode))
|
|
63
|
+
const invalidDelegation = packets.filter((packet) => !allowedDelegation.has(packet.realDelegationUsed))
|
|
64
|
+
const invalidToolStatus = packets.filter((packet) => !allowedToolStatuses.has(packet.toolStatus))
|
|
65
|
+
const missingEvidence = packets.filter((packet) => !packet.fallbackOutput || !packet.evidence || !packet.stopCondition || !packet.writeAccess)
|
|
66
|
+
const fakeDelegationRisk = packets.filter((packet) => packet.realDelegationUsed === 'yes' && packet.toolStatus !== 'verified')
|
|
67
|
+
const status = !exists
|
|
68
|
+
? 'warning'
|
|
69
|
+
: missingRoles.length > 0 || invalidMode.length > 0 || invalidDelegation.length > 0 || invalidToolStatus.length > 0 || missingEvidence.length > 0 || fakeDelegationRisk.length > 0
|
|
70
|
+
? 'failed'
|
|
71
|
+
: 'passed'
|
|
72
|
+
return {
|
|
73
|
+
path: '.gse/agents/role-fallback-packets.md',
|
|
74
|
+
exists,
|
|
75
|
+
status,
|
|
76
|
+
packets,
|
|
77
|
+
summary: {
|
|
78
|
+
requiredRoles,
|
|
79
|
+
total: packets.length,
|
|
80
|
+
missingRoles,
|
|
81
|
+
invalidMode: invalidMode.map((packet) => packet.role),
|
|
82
|
+
invalidDelegation: invalidDelegation.map((packet) => packet.role),
|
|
83
|
+
invalidToolStatus: invalidToolStatus.map((packet) => packet.role),
|
|
84
|
+
missingEvidence: missingEvidence.map((packet) => packet.role),
|
|
85
|
+
fakeDelegationRisk: fakeDelegationRisk.map((packet) => packet.role),
|
|
86
|
+
sequentialFallbackRoles: packets.filter((packet) => packet.mode === 'sequential-role').map((packet) => packet.role),
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function run(script, commandArgs) {
|
|
92
|
+
const result = spawnSync(process.execPath, [path.join(root, 'scripts', script), ...commandArgs], {
|
|
93
|
+
cwd: root,
|
|
94
|
+
encoding: 'utf8',
|
|
95
|
+
windowsHide: true,
|
|
96
|
+
})
|
|
97
|
+
return {
|
|
98
|
+
command: [process.execPath, path.join(root, 'scripts', script), ...commandArgs].join(' '),
|
|
99
|
+
status: result.status ?? 1,
|
|
100
|
+
stdout: (result.stdout ?? '').trim(),
|
|
101
|
+
stderr: (result.stderr ?? '').trim(),
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
106
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function createFixture() {
|
|
110
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-role-fallback-'))
|
|
111
|
+
const init = run('init-project.mjs', ['--target', dir, '--mode', 'standard', '--json'])
|
|
112
|
+
return { dir, init }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function audit(target) {
|
|
116
|
+
const resolvedTarget = path.resolve(target)
|
|
117
|
+
const reference = readText(path.join(root, 'references', 'role-dispatch-fallback.md'))
|
|
118
|
+
const agentRoles = readText(path.join(root, 'references', 'agent-roles.md'))
|
|
119
|
+
const dispatchTemplate = readText(path.join(root, 'assets', 'templates', 'dispatch-packet.md'))
|
|
120
|
+
const fallbackTemplate = readText(path.join(root, 'assets', 'templates', 'role-fallback-packet.md'))
|
|
121
|
+
const initProject = readText(path.join(root, 'scripts', 'init-project.mjs'))
|
|
122
|
+
const continuePacket = readText(path.join(root, 'scripts', 'generate-continue-packet.mjs'))
|
|
123
|
+
const validationProfile = readText(path.join(root, 'scripts', 'run-validation-profile.mjs'))
|
|
124
|
+
const validator = readText(path.join(root, 'scripts', 'validate-gse.mjs'))
|
|
125
|
+
const fallback = readRoleDispatchFallback(resolvedTarget)
|
|
126
|
+
const roleDocsCoverRequired = requiredRoles.every((role) => reference.includes(role)) && agentRoles.includes('Planner') && agentRoles.includes('Release')
|
|
127
|
+
const templatesCoverEvidence =
|
|
128
|
+
dispatchTemplate.includes('Real delegation used') &&
|
|
129
|
+
dispatchTemplate.includes('Role output evidence') &&
|
|
130
|
+
dispatchTemplate.includes('Claim boundary') &&
|
|
131
|
+
fallbackTemplate.includes('Execution mode') &&
|
|
132
|
+
fallbackTemplate.includes('Evidence level')
|
|
133
|
+
const checks = [
|
|
134
|
+
check('RDF01', 'role dispatch fallback reference defines required roles and claim boundary', roleDocsCoverRequired && reference.includes('real-subagent') && reference.includes('sequential-role') && reference.includes('handoff-session'), 'references/role-dispatch-fallback.md and references/agent-roles.md'),
|
|
135
|
+
check('RDF02', 'dispatch templates expose auditable fallback fields', templatesCoverEvidence, 'assets/templates/dispatch-packet.md and assets/templates/role-fallback-packet.md'),
|
|
136
|
+
check('RDF03', 'init-project scaffolds role fallback packets for standard or enterprise projects', initProject.includes('agents/role-fallback-packets.md') && initProject.includes('Planner') && initProject.includes('Release'), 'scripts/init-project.mjs'),
|
|
137
|
+
check('RDF04', 'target role fallback packet is present or reported as warning', fallback.exists || fallback.status === 'warning', fallback.exists ? fallback.path : 'missing role fallback packet warning'),
|
|
138
|
+
check('RDF05', 'target role fallback packets cover all required roles when present', !fallback.exists || fallback.summary.missingRoles.length === 0, fallback.summary.missingRoles.join(', ') || 'required roles present'),
|
|
139
|
+
check('RDF06', 'target role fallback packets use valid mode/delegation/tool status vocabulary', !fallback.exists || (fallback.summary.invalidMode.length === 0 && fallback.summary.invalidDelegation.length === 0 && fallback.summary.invalidToolStatus.length === 0), 'mode/delegation/tool status vocabulary'),
|
|
140
|
+
check('RDF07', 'target role fallback packets include output evidence and stop conditions', !fallback.exists || fallback.summary.missingEvidence.length === 0, fallback.summary.missingEvidence.join(', ') || 'fallback evidence fields present'),
|
|
141
|
+
check('RDF08', 'target role fallback packets do not claim real delegation without verified tool status', !fallback.exists || fallback.summary.fakeDelegationRisk.length === 0, fallback.summary.fakeDelegationRisk.join(', ') || 'no fake delegation risk'),
|
|
142
|
+
check('RDF09', 'continue packet surfaces role fallback readiness', continuePacket.includes('readRoleDispatchFallback') && continuePacket.includes('roleFallback'), 'scripts/generate-continue-packet.mjs'),
|
|
143
|
+
check('RDF10', 'validation routes include role dispatch fallback audit', validationProfile.includes('audit-role-dispatch-fallback.mjs') && validator.includes('audit-role-dispatch-fallback.mjs'), 'validation profile and validate-gse'),
|
|
144
|
+
]
|
|
145
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
146
|
+
const failed = checks.length - passed
|
|
147
|
+
return {
|
|
148
|
+
target: resolvedTarget,
|
|
149
|
+
generatedAt: new Date().toISOString(),
|
|
150
|
+
summary: { status: failed === 0 ? fallback.status : 'failed', passed, failed, total: checks.length },
|
|
151
|
+
workflows: {
|
|
152
|
+
roleDispatchFallback: failed === 0 && fallback.status !== 'failed' ? 'verified' : 'failed',
|
|
153
|
+
requiredRoles,
|
|
154
|
+
packets: fallback.summary.total,
|
|
155
|
+
sequentialFallbackRoles: fallback.summary.sequentialFallbackRoles.length,
|
|
156
|
+
},
|
|
157
|
+
roleFallback: fallback,
|
|
158
|
+
checks,
|
|
159
|
+
limits: [
|
|
160
|
+
'Role fallback packets prove auditable role boundaries, not real subagent execution.',
|
|
161
|
+
'Real subagent support still requires current host dispatch evidence.',
|
|
162
|
+
'Missing role fallback packets are a warning for target projects until the scaffold is adopted.',
|
|
163
|
+
],
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function selfTestReport() {
|
|
168
|
+
const fixture = createFixture()
|
|
169
|
+
const fixtureReport = audit(fixture.dir)
|
|
170
|
+
const missingDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-role-fallback-missing-'))
|
|
171
|
+
fs.mkdirSync(path.join(missingDir, '.gse'), { recursive: true })
|
|
172
|
+
const missingReport = audit(missingDir)
|
|
173
|
+
fs.rmSync(fixture.dir, { recursive: true, force: true })
|
|
174
|
+
fs.rmSync(missingDir, { recursive: true, force: true })
|
|
175
|
+
const checks = [
|
|
176
|
+
check('RDFA01', 'init-project creates role fallback packet scaffold', fixture.init.status === 0 && fixtureReport.roleFallback.exists, 'scripts/init-project.mjs'),
|
|
177
|
+
check('RDFA02', 'scaffold covers every required role', fixtureReport.roleFallback.summary.missingRoles.length === 0, fixtureReport.roleFallback.packets.map((packet) => packet.role).join(', ')),
|
|
178
|
+
check('RDFA03', 'scaffold uses sequential fallback without fake real delegation', fixtureReport.roleFallback.summary.fakeDelegationRisk.length === 0 && fixtureReport.roleFallback.packets.every((packet) => packet.realDelegationUsed === 'no'), 'sequential fallback packets'),
|
|
179
|
+
check('RDFA04', 'missing role fallback file is warning, not hard failure', missingReport.roleFallback.status === 'warning', 'missing fixture'),
|
|
180
|
+
check('RDFA05', 'audit source is wired to continue packet and validation scripts', fixtureReport.checks.find((item) => item.id === 'RDF09')?.status === 'passed' && fixtureReport.checks.find((item) => item.id === 'RDF10')?.status === 'passed', 'continue/validation wiring'),
|
|
181
|
+
]
|
|
182
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
183
|
+
const failed = checks.length - passed
|
|
184
|
+
return {
|
|
185
|
+
root,
|
|
186
|
+
generatedAt: new Date().toISOString(),
|
|
187
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
188
|
+
workflows: {
|
|
189
|
+
roleDispatchFallback: failed === 0 ? 'verified' : 'failed',
|
|
190
|
+
initProjectRoleFallbackScaffold: failed === 0 ? 'verified' : 'failed',
|
|
191
|
+
},
|
|
192
|
+
fixture: {
|
|
193
|
+
scaffoldStatus: fixtureReport.roleFallback.status,
|
|
194
|
+
missingStatus: missingReport.roleFallback.status,
|
|
195
|
+
roles: fixtureReport.roleFallback.packets.map((packet) => packet.role),
|
|
196
|
+
},
|
|
197
|
+
checks,
|
|
198
|
+
limits: [
|
|
199
|
+
'This self-test verifies scaffold and audit mechanics.',
|
|
200
|
+
'It does not prove a real host spawned subagents.',
|
|
201
|
+
],
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const isCli = process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])
|
|
206
|
+
|
|
207
|
+
if (isCli) {
|
|
208
|
+
const report = targetArg ? audit(targetArg) : selfTestReport()
|
|
209
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
210
|
+
else console.log(JSON.stringify(report, null, 2))
|
|
211
|
+
if (report.summary.status === 'failed') process.exit(1)
|
|
212
|
+
}
|