@t275005746/gse 0.1.0 → 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/.github/ISSUE_TEMPLATE/bug_report.yml +42 -42
- package/.github/ISSUE_TEMPLATE/change_request.yml +50 -50
- package/.github/ISSUE_TEMPLATE/config.yml +5 -5
- package/.github/PULL_REQUEST_TEMPLATE.md +38 -38
- package/.github/workflows/validate-gse.yml +33 -33
- package/.gse/README.md +18 -18
- package/.gse/gse-development-protocol.md +50 -50
- package/.gse/project-profile.md +29 -29
- package/.gse/quality-gates.md +25 -25
- package/.gse/releases/public-registry-publication-npm.md +49 -0
- package/.gse/releases/public-release-owner-required.md +65 -65
- package/.gse/releases/public-security-contact-owner-required.md +45 -45
- package/.gse/state.json +147 -27
- package/CHANGELOG.md +31 -15
- package/CONTRIBUTING.md +64 -64
- package/LICENSE +21 -21
- package/README.md +14 -7
- package/README.zh-CN.md +14 -7
- package/SECURITY.md +41 -41
- package/SKILL.md +32 -12
- package/SUPPORT.md +38 -38
- package/assets/marketplace/README.md +7 -7
- package/assets/marketplace/gse-listing.json +75 -75
- package/assets/templates/acceptance-execution-packet.md +73 -73
- package/assets/templates/adr.md +14 -14
- package/assets/templates/change-brief.md +16 -16
- package/assets/templates/design.md +18 -18
- package/assets/templates/dispatch-packet.md +100 -92
- package/assets/templates/evidence.md +15 -9
- package/assets/templates/execution-quality-pack.md +65 -65
- package/assets/templates/goal-map.md +21 -21
- package/assets/templates/host-adapter.md +48 -48
- package/assets/templates/host-ui-invocation-record.md +42 -42
- package/assets/templates/incident-review.md +60 -60
- package/assets/templates/public-channel-publication-record.md +49 -49
- package/assets/templates/public-ci-run-record.md +53 -53
- package/assets/templates/public-release-record.md +65 -65
- package/assets/templates/public-repository-settings-record.md +59 -59
- package/assets/templates/public-security-contact-record.md +45 -45
- package/assets/templates/release-trust-record.md +32 -32
- package/assets/templates/review.md +18 -18
- package/assets/templates/role-fallback-packet.md +49 -0
- package/assets/templates/spec.md +16 -16
- package/assets/templates/target-adoption-evidence.md +29 -29
- package/assets/templates/tasks.md +17 -17
- package/assets/templates/update-release-acceptance-record.md +58 -58
- package/examples/README.md +22 -22
- package/examples/agent-runtime-host/.claude/gse-adapter.md +6 -6
- package/examples/agent-runtime-host/.codex/gse-adapter.md +7 -7
- package/examples/agent-runtime-host/.gse/goal-map.md +7 -7
- package/examples/agent-runtime-host/.gse/project-profile.md +27 -27
- package/examples/agent-runtime-host/.gse/tooling.md +5 -5
- package/examples/agent-runtime-host/.mcp.json +9 -9
- package/examples/agent-runtime-host/AGENTS.md +5 -5
- package/examples/agent-runtime-host/README.md +10 -10
- package/examples/agent-runtime-host/docs/model-routing.md +5 -5
- package/examples/cli-tool/.gse/project-profile.md +21 -21
- package/examples/cli-tool/AGENTS.md +5 -5
- package/examples/cli-tool/README.md +12 -12
- package/examples/cli-tool/package.json +21 -21
- package/examples/small-app/.env.example +2 -2
- package/examples/small-app/.github/workflows/ci.yml +8 -8
- package/examples/small-app/AGENTS.md +5 -5
- package/examples/small-app/README.md +12 -12
- package/examples/small-app/package.json +26 -26
- package/examples/small-app/playwright.config.ts +4 -4
- package/package.json +52 -44
- package/references/adoption-recipes.md +171 -171
- package/references/agent-roles.md +42 -21
- package/references/architecture-health.md +101 -101
- package/references/benchmark-audit.md +73 -73
- package/references/commands.md +74 -45
- package/references/community-channels.md +46 -46
- package/references/compatibility.md +70 -70
- package/references/design-basis.md +38 -38
- package/references/domain-model.md +129 -129
- package/references/domain-quality-gates.md +75 -75
- package/references/drift-audit.md +81 -80
- package/references/evidence-taxonomy.md +145 -108
- package/references/file-ownership.md +97 -93
- package/references/final-form-roadmap.md +201 -0
- package/references/final-readiness.md +84 -84
- package/references/forward-test.md +133 -133
- package/references/goal-map.md +36 -36
- package/references/host-adapters.md +129 -101
- package/references/learning-system.md +42 -26
- package/references/maintenance-cadence.md +51 -0
- package/references/marketplace-discovery.md +46 -46
- package/references/model-routing.md +103 -103
- package/references/open-source-defaults.md +39 -39
- package/references/operating-model.md +52 -52
- package/references/packaging.md +277 -277
- package/references/project-agent-workspace.md +89 -89
- package/references/project-bootstrap.md +122 -122
- package/references/project-guards.md +52 -0
- package/references/project-profile.md +57 -57
- package/references/public-release.md +174 -174
- package/references/quality-gates.md +96 -89
- package/references/recovery.md +176 -176
- package/references/release-trust.md +43 -43
- package/references/release.md +126 -126
- package/references/review.md +141 -141
- package/references/role-dispatch-fallback.md +54 -0
- package/references/router.md +90 -90
- package/references/spec-workflow.md +66 -66
- package/references/task-levels.md +81 -81
- package/references/tool-adapters.md +80 -70
- package/scripts/audit-acceptance-execution-packet.mjs +133 -133
- package/scripts/audit-adoption-recipes.mjs +99 -99
- package/scripts/audit-change-lifecycle.mjs +77 -77
- package/scripts/audit-change-system.mjs +134 -134
- package/scripts/audit-ci-readiness.mjs +107 -107
- package/scripts/audit-close-gate-hardening.mjs +188 -0
- package/scripts/audit-close-gate.mjs +448 -262
- package/scripts/audit-command-adapters.mjs +91 -91
- package/scripts/audit-command-execution.mjs +212 -199
- package/scripts/audit-commands.mjs +7 -5
- package/scripts/audit-compatibility.mjs +149 -149
- package/scripts/audit-completion-plan-drill.mjs +230 -0
- package/scripts/audit-completion-readiness.mjs +290 -287
- package/scripts/audit-continue-preflight.mjs +234 -0
- package/scripts/audit-distribution.mjs +251 -251
- package/scripts/audit-domain-quality-gates.mjs +108 -108
- package/scripts/audit-evidence-levels.mjs +217 -0
- package/scripts/audit-evidence-placeholders.mjs +126 -126
- 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-promotion.mjs +255 -255
- package/scripts/audit-final-readiness.mjs +226 -226
- package/scripts/audit-fixtures.mjs +154 -154
- package/scripts/audit-fresh-session-readiness.mjs +177 -177
- package/scripts/audit-host-capabilities.mjs +237 -0
- package/scripts/audit-host-runtime-evidence-handoff.mjs +159 -159
- package/scripts/audit-host-runtime-invocation-drill.mjs +240 -240
- package/scripts/audit-host-runtime-invocations.mjs +254 -254
- package/scripts/audit-host-ui-invocation.mjs +132 -132
- 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-marketplace-discovery.mjs +122 -122
- package/scripts/audit-npm-package-metadata.mjs +160 -154
- package/scripts/audit-npm-publish-dry-run.mjs +194 -166
- package/scripts/audit-npm-tarball-install.mjs +195 -189
- package/scripts/audit-open-source-defaults.mjs +92 -92
- package/scripts/audit-open-source-readiness.mjs +97 -97
- package/scripts/audit-owner-external-gate-kit.mjs +12 -11
- package/scripts/audit-project-guards.mjs +189 -0
- package/scripts/audit-project.mjs +144 -141
- package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -203
- package/scripts/audit-public-acceptance-handoff.mjs +10 -10
- package/scripts/audit-public-acceptance-readiness.mjs +222 -222
- package/scripts/audit-public-channel-publication.mjs +248 -248
- package/scripts/audit-public-ci-run.mjs +184 -184
- package/scripts/audit-public-collaboration-templates.mjs +98 -98
- package/scripts/audit-public-external-gate-probe.mjs +206 -206
- package/scripts/audit-public-release-checklist.mjs +17 -15
- package/scripts/audit-public-release-decision.mjs +201 -201
- package/scripts/audit-public-release-metadata.mjs +176 -176
- package/scripts/audit-public-repository-settings.mjs +237 -237
- package/scripts/audit-public-security-contact.mjs +171 -171
- package/scripts/audit-readme-docs.mjs +6 -4
- package/scripts/audit-recovery-readiness.mjs +98 -98
- 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-readiness.mjs +106 -106
- package/scripts/audit-release-status-manifest.mjs +4 -4
- package/scripts/audit-release-trust.mjs +62 -62
- package/scripts/audit-remote-distribution.mjs +266 -266
- package/scripts/audit-roadmap-consistency.mjs +234 -230
- package/scripts/audit-role-dispatch-fallback.mjs +212 -0
- package/scripts/audit-session-sync.mjs +127 -0
- package/scripts/audit-signing.mjs +147 -147
- package/scripts/audit-state-freshness.mjs +20 -14
- package/scripts/audit-state-repair.mjs +360 -0
- package/scripts/audit-target-adoption-evidence.mjs +117 -117
- package/scripts/audit-target-hardening-drills.mjs +267 -0
- package/scripts/audit-target-project.mjs +507 -507
- package/scripts/audit-tool-fallback-policy.mjs +180 -0
- package/scripts/audit-ui-browser-evidence-policy.mjs +191 -0
- package/scripts/audit-update-release-acceptance.mjs +136 -136
- package/scripts/audit-v1-target-validation.mjs +269 -269
- package/scripts/audit-validation-profiles.mjs +125 -123
- package/scripts/backfill-evidence-levels.mjs +98 -0
- package/scripts/check-encoding.mjs +72 -0
- package/scripts/close-change.mjs +116 -116
- package/scripts/discover-project-profile.mjs +307 -307
- package/scripts/generate-command-adapter.mjs +231 -231
- package/scripts/generate-continue-packet.mjs +1214 -0
- package/scripts/generate-final-acceptance-packet.mjs +188 -173
- package/scripts/generate-final-form-progress-report.mjs +191 -189
- package/scripts/generate-host-runtime-evidence-handoff.mjs +198 -191
- package/scripts/generate-maintenance-snapshot.mjs +216 -0
- package/scripts/generate-owner-external-gate-kit.mjs +295 -295
- package/scripts/generate-public-acceptance-handoff.mjs +168 -156
- package/scripts/generate-public-release-checklist.mjs +207 -207
- package/scripts/generate-release-bundle.mjs +505 -505
- package/scripts/generate-release-owner-action-plan.mjs +172 -171
- package/scripts/generate-release-status-manifest.mjs +199 -198
- package/scripts/generate-session-prompt.mjs +188 -188
- package/scripts/gse.mjs +67 -67
- package/scripts/init-change.mjs +265 -265
- package/scripts/init-project.mjs +793 -712
- package/scripts/install-gse.mjs +234 -234
- package/scripts/lib/evidence-placeholders.mjs +28 -28
- package/scripts/package-gse.mjs +174 -174
- package/scripts/probe-public-external-gates.mjs +167 -167
- package/scripts/record-host-invocation.mjs +151 -151
- package/scripts/record-learning.mjs +37 -8
- package/scripts/record-public-channel-publication.mjs +178 -178
- package/scripts/record-public-ci-run.mjs +180 -180
- package/scripts/record-public-release.mjs +175 -175
- package/scripts/record-public-repository-settings.mjs +209 -209
- package/scripts/record-public-security-contact.mjs +157 -157
- 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/sign-gse-package.mjs +83 -83
- package/scripts/update-project-state.mjs +223 -223
- package/scripts/validate-gse.mjs +216 -0
- package/scripts/verify-gse-package.mjs +85 -85
|
@@ -1,323 +1,509 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import os from 'node:os'
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { spawnSync } from 'node:child_process'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
import { analyzeEvidenceLevels } from './audit-evidence-levels.mjs'
|
|
7
|
+
import { readRoleDispatchFallback } from './audit-role-dispatch-fallback.mjs'
|
|
8
|
+
|
|
9
|
+
const args = process.argv.slice(2)
|
|
10
|
+
|
|
11
|
+
function readArg(name, fallback = null) {
|
|
12
|
+
const index = args.indexOf(name)
|
|
13
|
+
if (index === -1) return fallback
|
|
14
|
+
return args[index + 1] ?? fallback
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const jsonOnly = args.includes('--json')
|
|
18
|
+
const selfTest = args.includes('--self-test') || !args.includes('--target')
|
|
19
|
+
const targetArg = readArg('--target')
|
|
20
|
+
|
|
21
|
+
function readText(filePath) {
|
|
22
|
+
return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '') : ''
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readJson(filePath) {
|
|
26
|
+
if (!fs.existsSync(filePath)) return { exists: false, ok: false, data: null, error: 'missing' }
|
|
27
|
+
try {
|
|
28
|
+
return { exists: true, ok: true, data: JSON.parse(readText(filePath)), error: '' }
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return { exists: true, ok: false, data: null, error: error.message }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function readJsonl(filePath) {
|
|
35
|
+
if (!fs.existsSync(filePath)) return { exists: false, ok: false, records: [], error: 'missing' }
|
|
36
|
+
const lines = readText(filePath)
|
|
37
|
+
.split(/\r?\n/)
|
|
38
|
+
.map((line) => line.trim())
|
|
39
|
+
.filter(Boolean)
|
|
40
|
+
const records = []
|
|
41
|
+
for (const [index, line] of lines.entries()) {
|
|
42
|
+
try {
|
|
43
|
+
records.push(JSON.parse(line))
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return { exists: true, ok: false, records, error: `line ${index + 1}: ${error.message}` }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { exists: true, ok: true, records, error: '' }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function exists(target, relativePath) {
|
|
52
|
+
return fs.existsSync(path.join(target, relativePath))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function runGit(target, commandArgs) {
|
|
56
|
+
const result = spawnSync('git', commandArgs, {
|
|
57
|
+
cwd: target,
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
windowsHide: true,
|
|
60
|
+
})
|
|
61
|
+
return {
|
|
62
|
+
status: result.status ?? 1,
|
|
63
|
+
stdout: (result.stdout ?? '').trim(),
|
|
64
|
+
stderr: (result.stderr ?? '').trim(),
|
|
65
|
+
}
|
|
21
66
|
}
|
|
22
67
|
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return { exists: true, ok: false, data: null, error: error.message }
|
|
29
|
-
}
|
|
68
|
+
function normalizeGitPath(rawPath) {
|
|
69
|
+
const normalized = rawPath.replace(/\\/g, '/')
|
|
70
|
+
const renameMarker = ' -> '
|
|
71
|
+
if (normalized.includes(renameMarker)) return normalized.split(renameMarker).pop()
|
|
72
|
+
return normalized
|
|
30
73
|
}
|
|
31
74
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
75
|
+
function parseGitPorcelain(text) {
|
|
76
|
+
const entries = []
|
|
77
|
+
for (const line of text.split(/\r?\n/).filter(Boolean)) {
|
|
78
|
+
const x = line[0] ?? ' '
|
|
79
|
+
const y = line[1] ?? ' '
|
|
80
|
+
const rawPath = line.slice(3).trim()
|
|
81
|
+
const filePath = normalizeGitPath(rawPath)
|
|
82
|
+
const untracked = x === '?' && y === '?'
|
|
83
|
+
const staged = !untracked && x !== ' '
|
|
84
|
+
const unstaged = !untracked && y !== ' '
|
|
85
|
+
const conflict = x === 'U' || y === 'U' || ['AA', 'DD', 'AU', 'UA', 'DU', 'UD', 'UU'].includes(x + y)
|
|
86
|
+
entries.push({ code: x + y, path: filePath, staged, unstaged, untracked, conflict })
|
|
45
87
|
}
|
|
46
|
-
return
|
|
88
|
+
return entries
|
|
47
89
|
}
|
|
48
90
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
91
|
+
const generatedArtifactPatterns = [
|
|
92
|
+
/^output\//,
|
|
93
|
+
/^playwright-report\//,
|
|
94
|
+
/^test-results\//,
|
|
95
|
+
/^coverage\//,
|
|
96
|
+
/^\.nyc_output\//,
|
|
97
|
+
/^node_modules\//,
|
|
98
|
+
/^\.turbo\//,
|
|
99
|
+
/^\.next\//,
|
|
100
|
+
/^dist\//,
|
|
101
|
+
]
|
|
52
102
|
|
|
53
|
-
function
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
encoding: 'utf8',
|
|
57
|
-
windowsHide: true,
|
|
58
|
-
})
|
|
59
|
-
return {
|
|
60
|
-
status: result.status ?? 1,
|
|
61
|
-
stdout: (result.stdout ?? '').trim(),
|
|
62
|
-
stderr: (result.stderr ?? '').trim(),
|
|
63
|
-
}
|
|
103
|
+
function isGeneratedArtifact(relativePath) {
|
|
104
|
+
const normalized = relativePath.replace(/\\/g, '/')
|
|
105
|
+
return generatedArtifactPatterns.some((pattern) => pattern.test(normalized))
|
|
64
106
|
}
|
|
65
107
|
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
108
|
+
function summarizeGitEntries(entries) {
|
|
109
|
+
const staged = entries.filter((entry) => entry.staged)
|
|
110
|
+
const unstaged = entries.filter((entry) => entry.unstaged)
|
|
111
|
+
const untracked = entries.filter((entry) => entry.untracked)
|
|
112
|
+
const conflicts = entries.filter((entry) => entry.conflict)
|
|
113
|
+
const mixed = entries.filter((entry) => entry.staged && entry.unstaged)
|
|
114
|
+
const stagedGenerated = staged.filter((entry) => isGeneratedArtifact(entry.path))
|
|
115
|
+
const dirtyGenerated = entries.filter((entry) => !entry.staged && isGeneratedArtifact(entry.path))
|
|
116
|
+
return { staged, unstaged, untracked, conflicts, mixed, stagedGenerated, dirtyGenerated }
|
|
70
117
|
}
|
|
71
|
-
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
118
|
+
|
|
119
|
+
function statusFrom(ok, warn = false) {
|
|
120
|
+
if (ok) return 'passed'
|
|
121
|
+
if (warn) return 'warning'
|
|
122
|
+
return 'failed'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function check(id, label, status, evidence, recommendation = '') {
|
|
126
|
+
return { id, label, status, evidence, recommendation }
|
|
127
|
+
}
|
|
128
|
+
|
|
76
129
|
function createFixture() {
|
|
77
130
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-close-gate-'))
|
|
78
131
|
fs.mkdirSync(path.join(dir, '.gse', 'evidence'), { recursive: true })
|
|
79
|
-
fs.
|
|
80
|
-
fs.writeFileSync(path.join(dir, '.gse', '
|
|
81
|
-
fs.writeFileSync(path.join(dir, '.gse', '
|
|
82
|
-
fs.writeFileSync(path.join(dir, '.gse', '
|
|
83
|
-
fs.writeFileSync(path.join(dir, '.gse', '
|
|
84
|
-
fs.writeFileSync(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
'
|
|
113
|
-
|
|
132
|
+
fs.mkdirSync(path.join(dir, '.gse', 'agents'), { recursive: true })
|
|
133
|
+
fs.writeFileSync(path.join(dir, '.gse', 'README.md'), '# GSE\n', 'utf8')
|
|
134
|
+
fs.writeFileSync(path.join(dir, '.gse', 'project-profile.md'), '# Project Profile\n', 'utf8')
|
|
135
|
+
fs.writeFileSync(path.join(dir, '.gse', 'goal-map.md'), '# Goal Map\n\nNext action: archive slice.\n', 'utf8')
|
|
136
|
+
fs.writeFileSync(path.join(dir, '.gse', 'quality-gates.md'), '# Quality Gates\n\n## Universal\n\n- Evidence required.\n', 'utf8')
|
|
137
|
+
fs.writeFileSync(path.join(dir, '.gse', 'evidence', '2026-07-06.md'), '# Evidence\n\nEvidence status: verified.\n', 'utf8')
|
|
138
|
+
fs.writeFileSync(
|
|
139
|
+
path.join(dir, '.gse', 'state.json'),
|
|
140
|
+
JSON.stringify(
|
|
141
|
+
{
|
|
142
|
+
schemaVersion: 1,
|
|
143
|
+
projectName: 'fixture-product',
|
|
144
|
+
mode: 'standard',
|
|
145
|
+
canonicalPlan: '',
|
|
146
|
+
phase: 'verify',
|
|
147
|
+
currentSlice: {
|
|
148
|
+
id: 'fixture-close',
|
|
149
|
+
outcome: 'Fixture close gate.',
|
|
150
|
+
status: 'verified',
|
|
151
|
+
nextAction: 'Archive slice.',
|
|
152
|
+
},
|
|
153
|
+
toolStatuses: {
|
|
154
|
+
browser: 'unknown',
|
|
155
|
+
lsp: 'unknown',
|
|
156
|
+
mcp: 'unknown',
|
|
157
|
+
subagents: 'unknown',
|
|
158
|
+
ci: 'unknown',
|
|
159
|
+
},
|
|
160
|
+
lastEvidence: '.gse/evidence/2026-07-06.md',
|
|
161
|
+
residualRisks: ['Fixture residual risk.'],
|
|
162
|
+
},
|
|
163
|
+
null,
|
|
164
|
+
2,
|
|
165
|
+
) + '\n',
|
|
166
|
+
'utf8',
|
|
167
|
+
)
|
|
114
168
|
fs.writeFileSync(
|
|
115
169
|
path.join(dir, '.gse', 'evidence', 'index.jsonl'),
|
|
116
|
-
JSON.stringify({
|
|
117
|
-
date: '2026-07-06',
|
|
170
|
+
JSON.stringify({
|
|
171
|
+
date: '2026-07-06',
|
|
118
172
|
recordType: 'slice',
|
|
119
173
|
status: 'verified',
|
|
174
|
+
evidenceLevel: 'verified-unit',
|
|
175
|
+
requiredEvidenceLevel: 'verified-unit',
|
|
120
176
|
summary: 'Fixture close gate evidence.',
|
|
121
177
|
evidenceFile: '.gse/evidence/2026-07-06.md',
|
|
122
|
-
commands: ['node scripts/audit-close-gate.mjs --self-test'],
|
|
123
|
-
nextAction: 'Archive slice.',
|
|
124
|
-
}) + '\n',
|
|
178
|
+
commands: ['node scripts/audit-close-gate.mjs --self-test'],
|
|
179
|
+
nextAction: 'Archive slice.',
|
|
180
|
+
}) + '\n',
|
|
181
|
+
'utf8',
|
|
182
|
+
)
|
|
183
|
+
fs.writeFileSync(
|
|
184
|
+
path.join(dir, '.gse', 'agents', 'role-fallback-packets.md'),
|
|
185
|
+
[
|
|
186
|
+
'# Role Fallback Packets',
|
|
187
|
+
'',
|
|
188
|
+
'| Role | Mode | Real delegation used | Tool status | Fallback output | Evidence | Stop condition | Write access |',
|
|
189
|
+
'|---|---|---|---|---|---|---|---|',
|
|
190
|
+
'| Planner | sequential-role | no | unknown | Plan | fixture plan | Plan accepted | read-only |',
|
|
191
|
+
'| Locator | sequential-role | no | unknown | File map | fixture map | Files identified | read-only |',
|
|
192
|
+
'| Implementer | sequential-role | no | unknown | Patch | fixture patch | Patch complete | assigned files |',
|
|
193
|
+
'| Verifier | sequential-role | no | unknown | Test results | fixture tests | Focused checks pass | evidence only |',
|
|
194
|
+
'| Reviewer | sequential-role | no | unknown | Review notes | fixture review | No blocking findings | read-only |',
|
|
195
|
+
'| Docs/Evidence | sequential-role | no | unknown | Evidence log | fixture evidence | Evidence recorded | docs/evidence only |',
|
|
196
|
+
'| Release | sequential-role | no | unknown | Claim boundary | fixture release | External gates visible | read-only |',
|
|
197
|
+
'',
|
|
198
|
+
].join('\n'),
|
|
125
199
|
'utf8',
|
|
126
200
|
)
|
|
127
201
|
runGit(dir, ['init'])
|
|
128
|
-
runGit(dir, ['config', 'user.email', 'gse-fixture@example.local'])
|
|
129
|
-
runGit(dir, ['config', 'user.name', 'GSE Fixture'])
|
|
130
|
-
runGit(dir, ['add', '.'])
|
|
131
|
-
runGit(dir, ['commit', '-m', 'fixture'])
|
|
132
|
-
return dir
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function auditCloseGate(target) {
|
|
136
|
-
const resolvedTarget = path.resolve(target)
|
|
137
|
-
const gseDir = path.join(resolvedTarget, '.gse')
|
|
202
|
+
runGit(dir, ['config', 'user.email', 'gse-fixture@example.local'])
|
|
203
|
+
runGit(dir, ['config', 'user.name', 'GSE Fixture'])
|
|
204
|
+
runGit(dir, ['add', '.'])
|
|
205
|
+
runGit(dir, ['commit', '-m', 'fixture'])
|
|
206
|
+
return dir
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function auditCloseGate(target) {
|
|
210
|
+
const resolvedTarget = path.resolve(target)
|
|
211
|
+
const gseDir = path.join(resolvedTarget, '.gse')
|
|
138
212
|
const state = readJson(path.join(gseDir, 'state.json'))
|
|
139
213
|
const evidenceIndex = readJsonl(path.join(gseDir, 'evidence', 'index.jsonl'))
|
|
214
|
+
const evidenceLevelAnalysis = analyzeEvidenceLevels(evidenceIndex.records)
|
|
140
215
|
const checks = []
|
|
141
|
-
|
|
142
|
-
checks.push(
|
|
143
|
-
check(
|
|
144
|
-
'CG01',
|
|
145
|
-
'.gse directory exists',
|
|
146
|
-
statusFrom(exists(resolvedTarget, '.gse')),
|
|
147
|
-
exists(resolvedTarget, '.gse') ? '.gse exists' : '.gse missing',
|
|
148
|
-
exists(resolvedTarget, '.gse') ? '' : 'Initialize or adopt GSE before closing a slice.',
|
|
149
|
-
),
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
const stateValid =
|
|
153
|
-
state.ok &&
|
|
154
|
-
state.data?.schemaVersion === 1 &&
|
|
155
|
-
typeof state.data?.phase === 'string' &&
|
|
156
|
-
typeof state.data?.currentSlice?.status === 'string' &&
|
|
157
|
-
typeof state.data?.currentSlice?.nextAction === 'string'
|
|
216
|
+
|
|
217
|
+
checks.push(
|
|
218
|
+
check(
|
|
219
|
+
'CG01',
|
|
220
|
+
'.gse directory exists',
|
|
221
|
+
statusFrom(exists(resolvedTarget, '.gse')),
|
|
222
|
+
exists(resolvedTarget, '.gse') ? '.gse exists' : '.gse missing',
|
|
223
|
+
exists(resolvedTarget, '.gse') ? '' : 'Initialize or adopt GSE before closing a slice.',
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
const stateValid =
|
|
228
|
+
state.ok &&
|
|
229
|
+
state.data?.schemaVersion === 1 &&
|
|
230
|
+
typeof state.data?.phase === 'string' &&
|
|
231
|
+
typeof state.data?.currentSlice?.status === 'string' &&
|
|
232
|
+
typeof state.data?.currentSlice?.nextAction === 'string'
|
|
233
|
+
checks.push(
|
|
234
|
+
check(
|
|
235
|
+
'CG02',
|
|
236
|
+
'state.json is valid',
|
|
237
|
+
statusFrom(stateValid),
|
|
238
|
+
state.exists ? state.ok ? `phase:${state.data.phase}, status:${state.data.currentSlice?.status}` : 'invalid ' + state.error : 'missing',
|
|
239
|
+
stateValid ? '' : 'Repair .gse/state.json before closing the slice.',
|
|
240
|
+
),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
const indexValid =
|
|
244
|
+
evidenceIndex.ok &&
|
|
245
|
+
evidenceIndex.records.length > 0 &&
|
|
246
|
+
evidenceIndex.records.every(
|
|
247
|
+
(record) =>
|
|
248
|
+
typeof record.date === 'string' &&
|
|
249
|
+
typeof record.recordType === 'string' &&
|
|
250
|
+
typeof record.status === 'string' &&
|
|
251
|
+
typeof record.summary === 'string' &&
|
|
252
|
+
typeof record.evidenceFile === 'string' &&
|
|
253
|
+
Array.isArray(record.commands) &&
|
|
254
|
+
typeof record.nextAction === 'string',
|
|
255
|
+
)
|
|
256
|
+
checks.push(
|
|
257
|
+
check(
|
|
258
|
+
'CG03',
|
|
259
|
+
'evidence index is valid',
|
|
260
|
+
statusFrom(indexValid),
|
|
261
|
+
evidenceIndex.exists ? evidenceIndex.ok ? `${evidenceIndex.records.length} record(s)` : 'invalid ' + evidenceIndex.error : 'missing',
|
|
262
|
+
indexValid ? '' : 'Record at least one evidence index entry before closing.',
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
const closeableState = ['verified', 'accepted'].includes(state.data?.currentSlice?.status)
|
|
267
|
+
checks.push(
|
|
268
|
+
check(
|
|
269
|
+
'CG04',
|
|
270
|
+
'current slice status is closeable',
|
|
271
|
+
statusFrom(closeableState),
|
|
272
|
+
`currentSlice.status:${state.data?.currentSlice?.status ?? 'unknown'}`,
|
|
273
|
+
closeableState ? '' : 'Set currentSlice.status to verified or accepted only after focused evidence exists.',
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
const closeableEvidenceRecords = evidenceIndex.records.filter((record) => ['verified', 'accepted'].includes(record.status))
|
|
278
|
+
const evidenceFilesExist =
|
|
279
|
+
closeableEvidenceRecords.length > 0 &&
|
|
280
|
+
closeableEvidenceRecords.every((record) => exists(resolvedTarget, record.evidenceFile))
|
|
281
|
+
checks.push(
|
|
282
|
+
check(
|
|
283
|
+
'CG05',
|
|
284
|
+
'verified or accepted evidence record exists',
|
|
285
|
+
statusFrom(evidenceFilesExist),
|
|
286
|
+
closeableEvidenceRecords.length
|
|
287
|
+
? closeableEvidenceRecords.map((record) => `${record.status}:${record.evidenceFile}:${exists(resolvedTarget, record.evidenceFile) ? 'exists' : 'missing'}`).join('; ')
|
|
288
|
+
: 'no verified/accepted evidence index record',
|
|
289
|
+
evidenceFilesExist ? '' : 'Add verified evidence and ensure the referenced evidence file exists.',
|
|
290
|
+
),
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
const requiredDocs = ['.gse/README.md', '.gse/project-profile.md', '.gse/goal-map.md', '.gse/quality-gates.md']
|
|
294
|
+
const missingDocs = requiredDocs.filter((relativePath) => !exists(resolvedTarget, relativePath))
|
|
295
|
+
checks.push(
|
|
296
|
+
check(
|
|
297
|
+
'CG06',
|
|
298
|
+
'required workflow docs exist',
|
|
299
|
+
statusFrom(missingDocs.length === 0),
|
|
300
|
+
missingDocs.length ? 'missing: ' + missingDocs.join(', ') : `${requiredDocs.length}/${requiredDocs.length} present`,
|
|
301
|
+
missingDocs.length ? 'Restore required workflow docs before closing.' : '',
|
|
302
|
+
),
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
const residualRisksOk = Array.isArray(state.data?.residualRisks)
|
|
306
|
+
checks.push(
|
|
307
|
+
check(
|
|
308
|
+
'CG07',
|
|
309
|
+
'residual risks are explicit',
|
|
310
|
+
statusFrom(residualRisksOk),
|
|
311
|
+
residualRisksOk ? `${state.data.residualRisks.length} residual risk(s)` : 'missing residualRisks array',
|
|
312
|
+
residualRisksOk ? '' : 'Use an empty array if there is no known residual risk.',
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
const gitRoot = runGit(resolvedTarget, ['rev-parse', '--show-toplevel'])
|
|
317
|
+
const isGitRepo = gitRoot.status === 0
|
|
318
|
+
const gseStatus = isGitRepo ? runGit(resolvedTarget, ['status', '--short', '.gse']) : { status: 1, stdout: '', stderr: 'not a git repository' }
|
|
158
319
|
checks.push(
|
|
159
320
|
check(
|
|
160
|
-
'
|
|
161
|
-
'
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
),
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
const indexValid =
|
|
169
|
-
evidenceIndex.ok &&
|
|
170
|
-
evidenceIndex.records.length > 0 &&
|
|
171
|
-
evidenceIndex.records.every(
|
|
172
|
-
(record) =>
|
|
173
|
-
typeof record.date === 'string' &&
|
|
174
|
-
typeof record.recordType === 'string' &&
|
|
175
|
-
typeof record.status === 'string' &&
|
|
176
|
-
typeof record.summary === 'string' &&
|
|
177
|
-
typeof record.evidenceFile === 'string' &&
|
|
178
|
-
Array.isArray(record.commands) &&
|
|
179
|
-
typeof record.nextAction === 'string',
|
|
180
|
-
)
|
|
181
|
-
checks.push(
|
|
182
|
-
check(
|
|
183
|
-
'CG03',
|
|
184
|
-
'evidence index is valid',
|
|
185
|
-
statusFrom(indexValid),
|
|
186
|
-
evidenceIndex.exists ? evidenceIndex.ok ? `${evidenceIndex.records.length} record(s)` : 'invalid ' + evidenceIndex.error : 'missing',
|
|
187
|
-
indexValid ? '' : 'Record at least one evidence index entry before closing.',
|
|
188
|
-
),
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
const closeableState = ['verified', 'accepted'].includes(state.data?.currentSlice?.status)
|
|
192
|
-
checks.push(
|
|
193
|
-
check(
|
|
194
|
-
'CG04',
|
|
195
|
-
'current slice status is closeable',
|
|
196
|
-
statusFrom(closeableState),
|
|
197
|
-
`currentSlice.status:${state.data?.currentSlice?.status ?? 'unknown'}`,
|
|
198
|
-
closeableState ? '' : 'Set currentSlice.status to verified or accepted only after focused evidence exists.',
|
|
321
|
+
'CG08',
|
|
322
|
+
'.gse git state is known',
|
|
323
|
+
isGitRepo ? (gseStatus.stdout ? 'warning' : 'passed') : 'warning',
|
|
324
|
+
isGitRepo ? gseStatus.stdout || 'clean' : 'not a git repository',
|
|
325
|
+
isGitRepo && gseStatus.stdout ? 'Review and intentionally stage/commit or document project-local GSE changes.' : '',
|
|
199
326
|
),
|
|
200
327
|
)
|
|
201
328
|
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
329
|
+
const evidenceLevelStatus = evidenceLevelAnalysis.invalidLevel.length > 0
|
|
330
|
+
? 'failed'
|
|
331
|
+
: evidenceLevelAnalysis.downgraded.length > 0 || evidenceLevelAnalysis.missingLevel.length > 0
|
|
332
|
+
? 'warning'
|
|
333
|
+
: 'passed'
|
|
206
334
|
checks.push(
|
|
207
335
|
check(
|
|
208
|
-
'
|
|
209
|
-
'
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
?
|
|
213
|
-
:
|
|
214
|
-
|
|
336
|
+
'CG09',
|
|
337
|
+
'evidence level validity and downgrade labels are visible',
|
|
338
|
+
evidenceLevelStatus,
|
|
339
|
+
evidenceLevelAnalysis.invalidLevel.length
|
|
340
|
+
? `invalid evidence level(s): ${evidenceLevelAnalysis.invalidLevel.map((item) => `${item.summary}:${item.evidenceLevel}`).join('; ')}`
|
|
341
|
+
: `${evidenceLevelAnalysis.recordsWithLevel}/${evidenceLevelAnalysis.records} record(s) with evidenceLevel; ${evidenceLevelAnalysis.downgraded.length} downgrade(s); ${evidenceLevelAnalysis.missingLevel.length} historical missing`,
|
|
342
|
+
evidenceLevelAnalysis.invalidLevel.length
|
|
343
|
+
? 'Use one of the evidence levels from references/evidence-taxonomy.md.'
|
|
344
|
+
: evidenceLevelAnalysis.downgraded.length
|
|
345
|
+
? 'Record whether the downgrade is acceptable for this slice before claiming browser, CI, owner, or release proof.'
|
|
346
|
+
: '',
|
|
215
347
|
),
|
|
216
348
|
)
|
|
217
349
|
|
|
218
|
-
const
|
|
219
|
-
const
|
|
350
|
+
const roleFallback = readRoleDispatchFallback(resolvedTarget)
|
|
351
|
+
const roleFallbackStatus = roleFallback.status === 'failed' ? 'failed' : roleFallback.status === 'warning' ? 'warning' : 'passed'
|
|
220
352
|
checks.push(
|
|
221
353
|
check(
|
|
222
|
-
'
|
|
223
|
-
'
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
354
|
+
'CG10',
|
|
355
|
+
'role dispatch and subagent claims are honest',
|
|
356
|
+
roleFallbackStatus,
|
|
357
|
+
roleFallback.exists
|
|
358
|
+
? roleFallback.summary.fakeDelegationRisk.length
|
|
359
|
+
? `fake delegation risk: ${roleFallback.summary.fakeDelegationRisk.join(', ')}`
|
|
360
|
+
: `${roleFallback.summary.total} role packet(s); ${roleFallback.summary.sequentialFallbackRoles.length} sequential fallback role(s)`
|
|
361
|
+
: 'role fallback packet missing',
|
|
362
|
+
roleFallbackStatus === 'failed'
|
|
363
|
+
? 'Do not claim real subagent dispatch unless the current host/tool status is verified.'
|
|
364
|
+
: roleFallbackStatus === 'warning'
|
|
365
|
+
? 'Adopt role fallback packets or record why role dispatch evidence is unavailable.'
|
|
366
|
+
: '',
|
|
227
367
|
),
|
|
228
368
|
)
|
|
229
369
|
|
|
230
|
-
const
|
|
370
|
+
const fullGitStatus = isGitRepo ? runGit(resolvedTarget, ['status', '--porcelain=v1']) : { status: 1, stdout: '', stderr: 'not a git repository' }
|
|
371
|
+
const gitEntries = isGitRepo && fullGitStatus.status === 0 ? parseGitPorcelain(fullGitStatus.stdout) : []
|
|
372
|
+
const gitSummary = summarizeGitEntries(gitEntries)
|
|
373
|
+
const ownershipStatus = !isGitRepo
|
|
374
|
+
? 'warning'
|
|
375
|
+
: gitSummary.conflicts.length > 0 || gitSummary.mixed.length > 0
|
|
376
|
+
? 'failed'
|
|
377
|
+
: gitEntries.length > 0
|
|
378
|
+
? 'warning'
|
|
379
|
+
: 'passed'
|
|
231
380
|
checks.push(
|
|
232
381
|
check(
|
|
233
|
-
'
|
|
234
|
-
'
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
382
|
+
'CG11',
|
|
383
|
+
'worktree change ownership is bounded before close',
|
|
384
|
+
ownershipStatus,
|
|
385
|
+
isGitRepo
|
|
386
|
+
? gitEntries.length
|
|
387
|
+
? `${gitSummary.staged.length} staged, ${gitSummary.unstaged.length} unstaged, ${gitSummary.untracked.length} untracked, ${gitSummary.mixed.length} mixed, ${gitSummary.conflicts.length} conflict(s)`
|
|
388
|
+
: 'worktree clean'
|
|
389
|
+
: 'not a git repository',
|
|
390
|
+
ownershipStatus === 'failed'
|
|
391
|
+
? 'Resolve merge conflicts or mixed staged/unstaged edits before closing so ownership and evidence are unambiguous.'
|
|
392
|
+
: ownershipStatus === 'warning'
|
|
393
|
+
? 'Review changed files, exclude unrelated or generated artifacts, and stage/commit only the current slice.'
|
|
394
|
+
: '',
|
|
238
395
|
),
|
|
239
396
|
)
|
|
240
397
|
|
|
241
|
-
const
|
|
242
|
-
const isGitRepo = gitRoot.status === 0
|
|
243
|
-
const gseStatus = isGitRepo ? runGit(resolvedTarget, ['status', '--short', '.gse']) : { status: 1, stdout: '', stderr: 'not a git repository' }
|
|
398
|
+
const artifactStatus = gitSummary.stagedGenerated.length > 0 ? 'failed' : gitSummary.dirtyGenerated.length > 0 ? 'warning' : 'passed'
|
|
244
399
|
checks.push(
|
|
245
400
|
check(
|
|
246
|
-
'
|
|
247
|
-
'
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
401
|
+
'CG12',
|
|
402
|
+
'generated test artifacts are not staged as slice evidence',
|
|
403
|
+
artifactStatus,
|
|
404
|
+
gitSummary.stagedGenerated.length
|
|
405
|
+
? `staged generated artifact(s): ${gitSummary.stagedGenerated.map((entry) => entry.path).join(', ')}`
|
|
406
|
+
: gitSummary.dirtyGenerated.length
|
|
407
|
+
? `dirty generated artifact(s): ${gitSummary.dirtyGenerated.map((entry) => entry.path).join(', ')}`
|
|
408
|
+
: 'no generated/test output artifacts staged',
|
|
409
|
+
artifactStatus === 'failed'
|
|
410
|
+
? 'Unstage generated test/browser/build artifacts unless the project explicitly requires them as source.'
|
|
411
|
+
: artifactStatus === 'warning'
|
|
412
|
+
? 'Keep generated artifacts out of the commit or explain why they are required.'
|
|
413
|
+
: '',
|
|
251
414
|
),
|
|
252
415
|
)
|
|
253
|
-
|
|
254
|
-
const failed = checks.filter((item) => item.status === 'failed').length
|
|
255
|
-
const warnings = checks.filter((item) => item.status === 'warning').length
|
|
256
|
-
const passed = checks.filter((item) => item.status === 'passed').length
|
|
257
|
-
|
|
258
|
-
return {
|
|
259
|
-
target: resolvedTarget,
|
|
260
|
-
generatedAt: new Date().toISOString(),
|
|
261
|
-
summary: {
|
|
262
|
-
status: failed > 0 ? 'not-ready' : warnings > 0 ? 'ready-with-warnings' : 'ready',
|
|
263
|
-
passed,
|
|
264
|
-
warnings,
|
|
265
|
-
failed,
|
|
266
|
-
total: checks.length,
|
|
267
|
-
},
|
|
268
|
-
workflows: {
|
|
269
|
-
closeGate: failed > 0 ? 'not-ready' : warnings > 0 ? 'ready-with-warnings' : 'ready',
|
|
270
|
-
},
|
|
271
|
-
state: {
|
|
272
|
-
exists: state.exists,
|
|
273
|
-
valid: stateValid,
|
|
274
|
-
phase: state.data?.phase ?? null,
|
|
275
|
-
currentSliceStatus: state.data?.currentSlice?.status ?? null,
|
|
276
|
-
nextAction: state.data?.currentSlice?.nextAction ?? null,
|
|
277
|
-
},
|
|
416
|
+
|
|
417
|
+
const failed = checks.filter((item) => item.status === 'failed').length
|
|
418
|
+
const warnings = checks.filter((item) => item.status === 'warning').length
|
|
419
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
target: resolvedTarget,
|
|
423
|
+
generatedAt: new Date().toISOString(),
|
|
424
|
+
summary: {
|
|
425
|
+
status: failed > 0 ? 'not-ready' : warnings > 0 ? 'ready-with-warnings' : 'ready',
|
|
426
|
+
passed,
|
|
427
|
+
warnings,
|
|
428
|
+
failed,
|
|
429
|
+
total: checks.length,
|
|
430
|
+
},
|
|
431
|
+
workflows: {
|
|
432
|
+
closeGate: failed > 0 ? 'not-ready' : warnings > 0 ? 'ready-with-warnings' : 'ready',
|
|
433
|
+
},
|
|
434
|
+
state: {
|
|
435
|
+
exists: state.exists,
|
|
436
|
+
valid: stateValid,
|
|
437
|
+
phase: state.data?.phase ?? null,
|
|
438
|
+
currentSliceStatus: state.data?.currentSlice?.status ?? null,
|
|
439
|
+
nextAction: state.data?.currentSlice?.nextAction ?? null,
|
|
440
|
+
},
|
|
278
441
|
evidenceIndex: {
|
|
279
442
|
exists: evidenceIndex.exists,
|
|
280
443
|
valid: indexValid,
|
|
281
444
|
records: evidenceIndex.records.length,
|
|
282
445
|
closeableRecords: closeableEvidenceRecords.length,
|
|
446
|
+
evidenceLevels: {
|
|
447
|
+
recordsWithLevel: evidenceLevelAnalysis.recordsWithLevel,
|
|
448
|
+
missingLevel: evidenceLevelAnalysis.missingLevel.length,
|
|
449
|
+
invalidLevel: evidenceLevelAnalysis.invalidLevel,
|
|
450
|
+
downgraded: evidenceLevelAnalysis.downgraded,
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
roleFallback: {
|
|
454
|
+
exists: roleFallback.exists,
|
|
455
|
+
status: roleFallback.status,
|
|
456
|
+
total: roleFallback.summary.total,
|
|
457
|
+
fakeDelegationRisk: roleFallback.summary.fakeDelegationRisk,
|
|
458
|
+
},
|
|
459
|
+
git: {
|
|
460
|
+
isGitRepo,
|
|
461
|
+
changedFiles: gitEntries.length,
|
|
462
|
+
staged: gitSummary.staged.length,
|
|
463
|
+
unstaged: gitSummary.unstaged.length,
|
|
464
|
+
untracked: gitSummary.untracked.length,
|
|
465
|
+
mixed: gitSummary.mixed.length,
|
|
466
|
+
conflicts: gitSummary.conflicts.length,
|
|
467
|
+
stagedGenerated: gitSummary.stagedGenerated.map((entry) => entry.path),
|
|
468
|
+
dirtyGenerated: gitSummary.dirtyGenerated.map((entry) => entry.path),
|
|
283
469
|
},
|
|
284
470
|
checks,
|
|
285
|
-
limits: [
|
|
286
|
-
'Close gate is diagnostic. It reports ready/not-ready and does not modify files.',
|
|
287
|
-
'A ready close gate does not replace user, reviewer, release, or owner acceptance when the project requires it.',
|
|
288
|
-
'Project tests, browser smokes, CI, MCP, LSP, subagents, and release checks must still be run according to project quality gates.',
|
|
289
|
-
],
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function renderMarkdown(report) {
|
|
294
|
-
const lines = []
|
|
295
|
-
lines.push('# GSE Close Gate')
|
|
296
|
-
lines.push('')
|
|
297
|
-
lines.push('Generated: ' + report.generatedAt)
|
|
298
|
-
lines.push('Target: ' + report.target)
|
|
299
|
-
lines.push('')
|
|
300
|
-
lines.push('## Summary')
|
|
301
|
-
lines.push('')
|
|
302
|
-
lines.push('- Status: ' + report.summary.status)
|
|
303
|
-
lines.push('- Checks: ' + report.summary.passed + ' passed, ' + report.summary.warnings + ' warnings, ' + report.summary.failed + ' failed, ' + report.summary.total + ' total')
|
|
304
|
-
lines.push('')
|
|
305
|
-
lines.push('## Checks')
|
|
306
|
-
lines.push('')
|
|
307
|
-
for (const item of report.checks) {
|
|
308
|
-
const marker = item.status === 'passed' ? '[x]' : item.status === 'warning' ? '[!]' : '[ ]'
|
|
309
|
-
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
310
|
-
if (item.recommendation) lines.push(' - Recommendation: ' + item.recommendation)
|
|
311
|
-
}
|
|
312
|
-
lines.push('')
|
|
313
|
-
lines.push('## Limits')
|
|
314
|
-
lines.push('')
|
|
315
|
-
for (const item of report.limits) lines.push('- ' + item)
|
|
316
|
-
return lines.join('\n') + '\n'
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const target = selfTest ? createFixture() : targetArg
|
|
320
|
-
const report = auditCloseGate(target)
|
|
321
|
-
|
|
322
|
-
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
323
|
-
else console.log(renderMarkdown(report))
|
|
471
|
+
limits: [
|
|
472
|
+
'Close gate is diagnostic. It reports ready/not-ready and does not modify files.',
|
|
473
|
+
'A ready close gate does not replace user, reviewer, release, or owner acceptance when the project requires it.',
|
|
474
|
+
'Project tests, browser smokes, CI, MCP, LSP, subagents, and release checks must still be run according to project quality gates.',
|
|
475
|
+
],
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function renderMarkdown(report) {
|
|
480
|
+
const lines = []
|
|
481
|
+
lines.push('# GSE Close Gate')
|
|
482
|
+
lines.push('')
|
|
483
|
+
lines.push('Generated: ' + report.generatedAt)
|
|
484
|
+
lines.push('Target: ' + report.target)
|
|
485
|
+
lines.push('')
|
|
486
|
+
lines.push('## Summary')
|
|
487
|
+
lines.push('')
|
|
488
|
+
lines.push('- Status: ' + report.summary.status)
|
|
489
|
+
lines.push('- Checks: ' + report.summary.passed + ' passed, ' + report.summary.warnings + ' warnings, ' + report.summary.failed + ' failed, ' + report.summary.total + ' total')
|
|
490
|
+
lines.push('')
|
|
491
|
+
lines.push('## Checks')
|
|
492
|
+
lines.push('')
|
|
493
|
+
for (const item of report.checks) {
|
|
494
|
+
const marker = item.status === 'passed' ? '[x]' : item.status === 'warning' ? '[!]' : '[ ]'
|
|
495
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
496
|
+
if (item.recommendation) lines.push(' - Recommendation: ' + item.recommendation)
|
|
497
|
+
}
|
|
498
|
+
lines.push('')
|
|
499
|
+
lines.push('## Limits')
|
|
500
|
+
lines.push('')
|
|
501
|
+
for (const item of report.limits) lines.push('- ' + item)
|
|
502
|
+
return lines.join('\n') + '\n'
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const target = selfTest ? createFixture() : targetArg
|
|
506
|
+
const report = auditCloseGate(target)
|
|
507
|
+
|
|
508
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
509
|
+
else console.log(renderMarkdown(report))
|