@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
|
@@ -1,8 +1,10 @@
|
|
|
1
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 { spawnSync } from 'node:child_process'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
import { analyzeEvidenceLevels } from './audit-evidence-levels.mjs'
|
|
7
|
+
import { readRoleDispatchFallback } from './audit-role-dispatch-fallback.mjs'
|
|
6
8
|
|
|
7
9
|
const args = process.argv.slice(2)
|
|
8
10
|
|
|
@@ -50,7 +52,7 @@ function exists(target, relativePath) {
|
|
|
50
52
|
return fs.existsSync(path.join(target, relativePath))
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
function runGit(target, commandArgs) {
|
|
55
|
+
function runGit(target, commandArgs) {
|
|
54
56
|
const result = spawnSync('git', commandArgs, {
|
|
55
57
|
cwd: target,
|
|
56
58
|
encoding: 'utf8',
|
|
@@ -61,7 +63,58 @@ function runGit(target, commandArgs) {
|
|
|
61
63
|
stdout: (result.stdout ?? '').trim(),
|
|
62
64
|
stderr: (result.stderr ?? '').trim(),
|
|
63
65
|
}
|
|
64
|
-
}
|
|
66
|
+
}
|
|
67
|
+
|
|
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
|
|
73
|
+
}
|
|
74
|
+
|
|
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 })
|
|
87
|
+
}
|
|
88
|
+
return entries
|
|
89
|
+
}
|
|
90
|
+
|
|
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
|
+
]
|
|
102
|
+
|
|
103
|
+
function isGeneratedArtifact(relativePath) {
|
|
104
|
+
const normalized = relativePath.replace(/\\/g, '/')
|
|
105
|
+
return generatedArtifactPatterns.some((pattern) => pattern.test(normalized))
|
|
106
|
+
}
|
|
107
|
+
|
|
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 }
|
|
117
|
+
}
|
|
65
118
|
|
|
66
119
|
function statusFrom(ok, warn = false) {
|
|
67
120
|
if (ok) return 'passed'
|
|
@@ -73,9 +126,10 @@ function check(id, label, status, evidence, recommendation = '') {
|
|
|
73
126
|
return { id, label, status, evidence, recommendation }
|
|
74
127
|
}
|
|
75
128
|
|
|
76
|
-
function createFixture() {
|
|
77
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-close-gate-'))
|
|
78
|
-
fs.mkdirSync(path.join(dir, '.gse', 'evidence'), { recursive: true })
|
|
129
|
+
function createFixture() {
|
|
130
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-close-gate-'))
|
|
131
|
+
fs.mkdirSync(path.join(dir, '.gse', 'evidence'), { recursive: true })
|
|
132
|
+
fs.mkdirSync(path.join(dir, '.gse', 'agents'), { recursive: true })
|
|
79
133
|
fs.writeFileSync(path.join(dir, '.gse', 'README.md'), '# GSE\n', 'utf8')
|
|
80
134
|
fs.writeFileSync(path.join(dir, '.gse', 'project-profile.md'), '# Project Profile\n', 'utf8')
|
|
81
135
|
fs.writeFileSync(path.join(dir, '.gse', 'goal-map.md'), '# Goal Map\n\nNext action: archive slice.\n', 'utf8')
|
|
@@ -111,20 +165,40 @@ function createFixture() {
|
|
|
111
165
|
) + '\n',
|
|
112
166
|
'utf8',
|
|
113
167
|
)
|
|
114
|
-
fs.writeFileSync(
|
|
115
|
-
path.join(dir, '.gse', 'evidence', 'index.jsonl'),
|
|
168
|
+
fs.writeFileSync(
|
|
169
|
+
path.join(dir, '.gse', 'evidence', 'index.jsonl'),
|
|
116
170
|
JSON.stringify({
|
|
117
171
|
date: '2026-07-06',
|
|
118
|
-
recordType: 'slice',
|
|
119
|
-
status: 'verified',
|
|
120
|
-
|
|
121
|
-
|
|
172
|
+
recordType: 'slice',
|
|
173
|
+
status: 'verified',
|
|
174
|
+
evidenceLevel: 'verified-unit',
|
|
175
|
+
requiredEvidenceLevel: 'verified-unit',
|
|
176
|
+
summary: 'Fixture close gate evidence.',
|
|
177
|
+
evidenceFile: '.gse/evidence/2026-07-06.md',
|
|
122
178
|
commands: ['node scripts/audit-close-gate.mjs --self-test'],
|
|
123
179
|
nextAction: 'Archive slice.',
|
|
124
180
|
}) + '\n',
|
|
125
|
-
'utf8',
|
|
126
|
-
)
|
|
127
|
-
|
|
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'),
|
|
199
|
+
'utf8',
|
|
200
|
+
)
|
|
201
|
+
runGit(dir, ['init'])
|
|
128
202
|
runGit(dir, ['config', 'user.email', 'gse-fixture@example.local'])
|
|
129
203
|
runGit(dir, ['config', 'user.name', 'GSE Fixture'])
|
|
130
204
|
runGit(dir, ['add', '.'])
|
|
@@ -135,9 +209,10 @@ function createFixture() {
|
|
|
135
209
|
function auditCloseGate(target) {
|
|
136
210
|
const resolvedTarget = path.resolve(target)
|
|
137
211
|
const gseDir = path.join(resolvedTarget, '.gse')
|
|
138
|
-
const state = readJson(path.join(gseDir, 'state.json'))
|
|
139
|
-
const evidenceIndex = readJsonl(path.join(gseDir, 'evidence', 'index.jsonl'))
|
|
140
|
-
const
|
|
212
|
+
const state = readJson(path.join(gseDir, 'state.json'))
|
|
213
|
+
const evidenceIndex = readJsonl(path.join(gseDir, 'evidence', 'index.jsonl'))
|
|
214
|
+
const evidenceLevelAnalysis = analyzeEvidenceLevels(evidenceIndex.records)
|
|
215
|
+
const checks = []
|
|
141
216
|
|
|
142
217
|
checks.push(
|
|
143
218
|
check(
|
|
@@ -241,15 +316,103 @@ function auditCloseGate(target) {
|
|
|
241
316
|
const gitRoot = runGit(resolvedTarget, ['rev-parse', '--show-toplevel'])
|
|
242
317
|
const isGitRepo = gitRoot.status === 0
|
|
243
318
|
const gseStatus = isGitRepo ? runGit(resolvedTarget, ['status', '--short', '.gse']) : { status: 1, stdout: '', stderr: 'not a git repository' }
|
|
244
|
-
checks.push(
|
|
245
|
-
check(
|
|
246
|
-
'CG08',
|
|
319
|
+
checks.push(
|
|
320
|
+
check(
|
|
321
|
+
'CG08',
|
|
247
322
|
'.gse git state is known',
|
|
248
323
|
isGitRepo ? (gseStatus.stdout ? 'warning' : 'passed') : 'warning',
|
|
249
324
|
isGitRepo ? gseStatus.stdout || 'clean' : 'not a git repository',
|
|
250
325
|
isGitRepo && gseStatus.stdout ? 'Review and intentionally stage/commit or document project-local GSE changes.' : '',
|
|
251
|
-
),
|
|
252
|
-
)
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
const evidenceLevelStatus = evidenceLevelAnalysis.invalidLevel.length > 0
|
|
330
|
+
? 'failed'
|
|
331
|
+
: evidenceLevelAnalysis.downgraded.length > 0 || evidenceLevelAnalysis.missingLevel.length > 0
|
|
332
|
+
? 'warning'
|
|
333
|
+
: 'passed'
|
|
334
|
+
checks.push(
|
|
335
|
+
check(
|
|
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
|
+
: '',
|
|
347
|
+
),
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
const roleFallback = readRoleDispatchFallback(resolvedTarget)
|
|
351
|
+
const roleFallbackStatus = roleFallback.status === 'failed' ? 'failed' : roleFallback.status === 'warning' ? 'warning' : 'passed'
|
|
352
|
+
checks.push(
|
|
353
|
+
check(
|
|
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
|
+
: '',
|
|
367
|
+
),
|
|
368
|
+
)
|
|
369
|
+
|
|
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'
|
|
380
|
+
checks.push(
|
|
381
|
+
check(
|
|
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
|
+
: '',
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
const artifactStatus = gitSummary.stagedGenerated.length > 0 ? 'failed' : gitSummary.dirtyGenerated.length > 0 ? 'warning' : 'passed'
|
|
399
|
+
checks.push(
|
|
400
|
+
check(
|
|
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
|
+
: '',
|
|
414
|
+
),
|
|
415
|
+
)
|
|
253
416
|
|
|
254
417
|
const failed = checks.filter((item) => item.status === 'failed').length
|
|
255
418
|
const warnings = checks.filter((item) => item.status === 'warning').length
|
|
@@ -275,13 +438,36 @@ function auditCloseGate(target) {
|
|
|
275
438
|
currentSliceStatus: state.data?.currentSlice?.status ?? null,
|
|
276
439
|
nextAction: state.data?.currentSlice?.nextAction ?? null,
|
|
277
440
|
},
|
|
278
|
-
evidenceIndex: {
|
|
279
|
-
exists: evidenceIndex.exists,
|
|
280
|
-
valid: indexValid,
|
|
281
|
-
records: evidenceIndex.records.length,
|
|
282
|
-
closeableRecords: closeableEvidenceRecords.length,
|
|
283
|
-
|
|
284
|
-
|
|
441
|
+
evidenceIndex: {
|
|
442
|
+
exists: evidenceIndex.exists,
|
|
443
|
+
valid: indexValid,
|
|
444
|
+
records: evidenceIndex.records.length,
|
|
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),
|
|
469
|
+
},
|
|
470
|
+
checks,
|
|
285
471
|
limits: [
|
|
286
472
|
'Close gate is diagnostic. It reports ready/not-ready and does not modify files.',
|
|
287
473
|
'A ready close gate does not replace user, reviewer, release, or owner acceptance when the project requires it.',
|
|
@@ -64,9 +64,10 @@ fs.writeFileSync(path.join(target, 'docs', 'productization-architecture.md'), '#
|
|
|
64
64
|
fs.appendFileSync(path.join(target, '.gse', 'README.md'), '\nCanonical plan: `docs/productization-architecture.md`.\n', 'utf8')
|
|
65
65
|
|
|
66
66
|
const adapterRun = run('generate-command-adapter.mjs', ['--target', target, '--host', 'all', '--json'])
|
|
67
|
-
const helpRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse help', '--json'])
|
|
68
|
-
const continueRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse continue', '--json'])
|
|
69
|
-
const
|
|
67
|
+
const helpRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse help', '--json'])
|
|
68
|
+
const continueRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse continue', '--json'])
|
|
69
|
+
const repairRun = run('run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse repair', '--json'])
|
|
70
|
+
const shortCliRun = run('gse.mjs', ['status', '--target', target, '--json'])
|
|
70
71
|
|
|
71
72
|
const full = profile === 'full'
|
|
72
73
|
const statusRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse status', '--json'])
|
|
@@ -92,11 +93,19 @@ const publicReleaseExecuteRun = maybeRun(full, 'run-gse-command.mjs', ['--root',
|
|
|
92
93
|
const doctorTargetRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse doctor', '--json'])
|
|
93
94
|
const verifyRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', root, '--command', '/gse verify --profile lite', '--json'])
|
|
94
95
|
const auditRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse audit', '--json'])
|
|
95
|
-
const closeRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse close', '--json'])
|
|
96
|
-
const changeRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse change add-login --level lite', '--execute', '--json'])
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
96
|
+
const closeRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse close', '--json'])
|
|
97
|
+
const changeRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse change add-login --level lite', '--execute', '--json'])
|
|
98
|
+
if (full) {
|
|
99
|
+
const statePath = path.join(target, '.gse', 'state.json')
|
|
100
|
+
const stateForRepair = JSON.parse(fs.readFileSync(statePath, 'utf8'))
|
|
101
|
+
stateForRepair.residualRisks = Array.from({ length: 9 }, (_, index) => `Command repair fixture risk ${index + 1}.`)
|
|
102
|
+
fs.writeFileSync(statePath, JSON.stringify(stateForRepair, null, 2) + '\n', 'utf8')
|
|
103
|
+
}
|
|
104
|
+
const repairExecuteRun = maybeRun(full, 'run-gse-command.mjs', ['--root', root, '--target', target, '--command', '/gse repair --max-active-risks 3', '--execute', '--json'])
|
|
105
|
+
|
|
106
|
+
const help = parseJson(helpRun.stdout)
|
|
107
|
+
const cont = parseJson(continueRun.stdout)
|
|
108
|
+
const repair = parseJson(repairRun.stdout)
|
|
100
109
|
const status = statusRun ? parseJson(statusRun.stdout) : null
|
|
101
110
|
const doctor = doctorRun ? parseJson(doctorRun.stdout) : null
|
|
102
111
|
const acceptance = acceptanceRun ? parseJson(acceptanceRun.stdout) : null
|
|
@@ -110,7 +119,9 @@ const doctorTarget = doctorTargetRun ? parseJson(doctorTargetRun.stdout) : null
|
|
|
110
119
|
const verify = verifyRun ? parseJson(verifyRun.stdout) : null
|
|
111
120
|
const audit = auditRun ? parseJson(auditRun.stdout) : null
|
|
112
121
|
const close = closeRun ? parseJson(closeRun.stdout) : null
|
|
113
|
-
const change = changeRun ? parseJson(changeRun.stdout) : null
|
|
122
|
+
const change = changeRun ? parseJson(changeRun.stdout) : null
|
|
123
|
+
const repairExecute = repairExecuteRun ? parseJson(repairExecuteRun.stdout) : null
|
|
124
|
+
const repairExecuteData = repairExecute ? parseJson(repairExecute.execution?.stdout ?? '') : null
|
|
114
125
|
const doctorData = doctor ? parseJson(doctor.execution?.stdout ?? '') : null
|
|
115
126
|
const ownerActionsData = ownerActions ? parseJson(ownerActions.execution?.stdout ?? '') : null
|
|
116
127
|
const probeWaitingData = probeWaiting ? parseJson(probeWaiting.execution?.stdout ?? '') : null
|
|
@@ -148,17 +159,18 @@ const liteChecks = [
|
|
|
148
159
|
check('CMDX02', 'target project initializes for command smoke', initRun.status === 0, initRun.command),
|
|
149
160
|
check('CMDX03', 'host command adapters are generated', adapterRun.status === 0 && claudeCommand.includes('run-gse-command.mjs') && codexPointer.includes('run-gse-command.mjs') && copilotPointer.includes('GitHub Copilot GSE Adapter') && geminiPointer.includes('Gemini GSE Adapter'), 'generated supported host adapters'),
|
|
150
161
|
check('CMDX04', '/gse help resolves command reference', helpRun.status === 0 && help?.route?.route === 'references/commands.md', '/gse help'),
|
|
151
|
-
check('CMDX05', '/gse continue executes
|
|
152
|
-
check('
|
|
162
|
+
check('CMDX05', '/gse continue executes hard preflight and compact state generator', continueRun.status === 0 && cont?.execution?.status === 0 && cont?.execution?.command?.includes('generate-continue-packet.mjs') && cont?.execution?.stdout?.includes('"compactState"'), '/gse continue'),
|
|
163
|
+
check('CMDX05c', '/gse repair executes state/evidence repair audit in read-only mode', repairRun.status === 0 && repair?.execution?.status === 0 && repair?.execution?.command?.includes('audit-state-repair.mjs') && repair?.execution?.stdout?.includes('"repairActions"'), '/gse repair'),
|
|
164
|
+
check('CMDX05b', 'short CLI wrapper routes to portable command runner', shortCliRun.status === 0 && shortCliRun.stdout.includes('"/gse status"') && shortCliRun.stdout.includes('"stateValid": true'), 'scripts/gse.mjs status --target <target> --json'),
|
|
153
165
|
]
|
|
154
166
|
|
|
155
167
|
const fullChecks = full
|
|
156
168
|
? [
|
|
157
169
|
check('CMDX06', '/gse status exposes GSE final-form progress when target is GSE skill', statusRun.status === 0 && status?.execution?.status === 0 && status?.execution?.stdout?.includes('fullFinalFormReadiness') && status?.execution?.stdout?.includes('pendingGateCount'), '/gse status'),
|
|
158
|
-
check('CMDX07', '/gse doctor exposes GSE public acceptance
|
|
170
|
+
check('CMDX07', '/gse doctor exposes GSE public acceptance evidence state when target is GSE skill', doctorRun.status === 0 && doctor?.execution?.status === 0 && doctorData?.workflows?.publicAcceptanceDoctor === 'verified' && doctorData?.summary?.pendingGates > 0 && doctorData?.summary?.publicAccepted === 'not-accepted', '/gse doctor'),
|
|
159
171
|
check('CMDX08', '/gse acceptance aliases the public acceptance doctor', acceptanceRun.status === 0 && acceptance?.execution?.status === 0 && acceptance?.execution?.stdout?.includes('"publicAcceptanceDoctor": "verified"'), '/gse acceptance'),
|
|
160
|
-
check('CMDX08b', '/gse owner-actions exposes compact owner/external action commands without claiming acceptance', ownerActionsRun.status === 0 && ownerActions?.execution?.status === 0 && ownerActionsData?.pendingGateCount
|
|
161
|
-
check('CMDX08c', '/gse owner-actions --compact returns owner packet without wrapper path noise', ownerActionsCompactRun.status === 0 && ownerActionsCompact?.pendingGateCount
|
|
172
|
+
check('CMDX08b', '/gse owner-actions exposes compact owner/external action commands without claiming acceptance', ownerActionsRun.status === 0 && ownerActions?.execution?.status === 0 && ownerActionsData?.pendingGateCount > 0 && ownerActionsData?.publicAccepted === 'not-accepted' && ownerActionsData.actions?.every((item) => item.recordCommand && item.preflightCommand), '/gse owner-actions'),
|
|
173
|
+
check('CMDX08c', '/gse owner-actions --compact returns owner packet without wrapper path noise', ownerActionsCompactRun.status === 0 && ownerActionsCompact?.pendingGateCount > 0 && ownerActionsCompact?.publicAccepted === 'not-accepted' && !ownerActionsCompactRun.stdout.includes(root) && !ownerActionsCompactRun.stdout.includes(process.execPath), '/gse owner-actions --json --compact'),
|
|
162
174
|
check('CMDX08c2', '/gse owner-actions --compact routes probe verification through portable command runner', ownerActionsCompactRun.status === 0 && ownerActionsCompact?.verificationCommands?.some((command) => command.includes('run-gse-command.mjs') && command.includes('/gse probe')) && !ownerActionsCompact?.verificationCommands?.some((command) => command.startsWith('node scripts/probe-public-external-gates.mjs')), '/gse owner-actions compact verificationCommands'),
|
|
163
175
|
check('CMDX08d', '/gse probe runs as a waiting diagnostic without evidence inputs', probeWaitingRun.status === 0 && probeWaiting?.execution?.status === 0 && probeWaitingData?.status === 'waiting-for-input' && probeWaitingData?.summary?.checked === 0, '/gse probe'),
|
|
164
176
|
check('CMDX08e', '/gse probe rejects placeholder public evidence through portable command runner', probeRejectRun.status !== 0 && probeReject?.execution?.status !== 0 && probeRejectData?.status === 'failed' && probeRejectData?.probes?.some((item) => item.errors?.some((error) => error.includes('not a placeholder'))), '/gse probe --public-repo-url https://github.com/example/gse'),
|
|
@@ -174,14 +186,15 @@ const fullChecks = full
|
|
|
174
186
|
check('CMDX10', '/gse verify executes validation profile runner', verifyRun.status === 0 && verify?.execution?.status === 0 && verify?.execution?.stdout?.includes('"profile": "lite"') && verify?.execution?.stdout?.includes('"validationProfile": "verified"'), '/gse verify --profile lite'),
|
|
175
187
|
check('CMDX11', '/gse audit executes target project doctor', diagnosticOk(auditRun, audit), '/gse audit'),
|
|
176
188
|
check('CMDX12', '/gse close executes close gate', diagnosticOk(closeRun, close), '/gse close'),
|
|
177
|
-
check('CMDX13', '/gse change executes change pack creation only with --execute', changeRun.status === 0 && change?.execution?.status === 0 && fs.existsSync(path.join(target, '.gse', 'changes', 'add-login', 'brief.md')), '/gse change --execute'),
|
|
178
|
-
|
|
189
|
+
check('CMDX13', '/gse change executes change pack creation only with --execute', changeRun.status === 0 && change?.execution?.status === 0 && fs.existsSync(path.join(target, '.gse', 'changes', 'add-login', 'brief.md')), '/gse change --execute'),
|
|
190
|
+
check('CMDX14', '/gse repair --execute performs reversible residual risk compaction only when requested', repairExecuteRun.status === 0 && repairExecute?.execution?.status === 0 && repairExecuteData?.summary?.writes === 1 && repairExecuteData?.writes?.some((item) => item.action === 'compact-residual-risks') && fs.existsSync(path.join(target, '.gse', 'backups')), '/gse repair --execute'),
|
|
191
|
+
]
|
|
179
192
|
: []
|
|
180
193
|
|
|
181
194
|
const checks = [...liteChecks, ...fullChecks]
|
|
182
195
|
const passed = checks.filter((item) => item.status === 'passed').length
|
|
183
196
|
const failed = checks.length - passed
|
|
184
|
-
const commandRuns = [initRun, adapterRun, helpRun, continueRun, shortCliRun, statusRun, doctorRun, acceptanceRun, ownerActionsRun, ownerActionsCompactRun, probeWaitingRun, probeRejectRun, releaseDryRun, releaseExecuteRun, packageDryRun, packageExecuteRun, installDryRun, installExecuteRun, publicReleaseDryRun, publicReleaseExecuteRun, doctorTargetRun, verifyRun, auditRun, closeRun, changeRun].filter(Boolean)
|
|
197
|
+
const commandRuns = [initRun, adapterRun, helpRun, continueRun, repairRun, shortCliRun, statusRun, doctorRun, acceptanceRun, ownerActionsRun, ownerActionsCompactRun, probeWaitingRun, probeRejectRun, releaseDryRun, releaseExecuteRun, packageDryRun, packageExecuteRun, installDryRun, installExecuteRun, publicReleaseDryRun, publicReleaseExecuteRun, doctorTargetRun, verifyRun, auditRun, closeRun, changeRun, repairExecuteRun].filter(Boolean)
|
|
185
198
|
const report = {
|
|
186
199
|
root,
|
|
187
200
|
generatedAt: new Date().toISOString(),
|
|
@@ -36,9 +36,10 @@ const requiredCommands = [
|
|
|
36
36
|
'/gse init',
|
|
37
37
|
'/gse adopt',
|
|
38
38
|
'/gse continue',
|
|
39
|
-
'/gse status',
|
|
40
|
-
'/gse doctor',
|
|
41
|
-
'/gse
|
|
39
|
+
'/gse status',
|
|
40
|
+
'/gse doctor',
|
|
41
|
+
'/gse repair',
|
|
42
|
+
'/gse acceptance',
|
|
42
43
|
'/gse owner-actions',
|
|
43
44
|
'/gse probe',
|
|
44
45
|
'/gse release',
|
|
@@ -68,8 +69,9 @@ const checks = [
|
|
|
68
69
|
check('CMD12', 'public-release command is documented as checklist/runway and not acceptance', skill.includes('/gse public-release') && commands.includes('/gse public-release') && commands.includes('ordered public release checklist') && commands.includes('does not publish, approve, configure, or accept'), 'SKILL.md, references/commands.md'),
|
|
69
70
|
check('CMD13', 'package/install commands expose installability without claiming publication', skill.includes('/gse package') && skill.includes('/gse install') && commands.includes('/gse package') && commands.includes('/gse install') && commands.includes('Only write a package when the command is run with `--execute`') && commands.includes('Only write the install target when the command is run with `--execute`') && commands.includes('does not publish to a registry'), 'SKILL.md, references/commands.md'),
|
|
70
71
|
check('CMD14', 'close command is documented as read-only readiness check', commands.includes('| `/gse close` | Check whether the current slice is ready to close') && commands.includes('/gse close` is read-only in the portable command runner') && commands.includes('close-change.mjs --target <project-root> --change-id <change-id>'), 'references/commands.md'),
|
|
71
|
-
check('CMD15', 'learn command is documented as execute-gated learning capture', commands.includes('| `/gse learn` | Record a reusable lesson') && commands.includes('/gse learn --summary') && commands.includes('Append the entry only when `--execute` is supplied') && skill.includes('scripts/record-learning.mjs'), 'SKILL.md, references/commands.md'),
|
|
72
|
-
|
|
72
|
+
check('CMD15', 'learn command is documented as execute-gated learning capture', commands.includes('| `/gse learn` | Record a reusable lesson') && commands.includes('/gse learn --summary') && commands.includes('Append the entry only when `--execute` is supplied') && skill.includes('scripts/record-learning.mjs'), 'SKILL.md, references/commands.md'),
|
|
73
|
+
check('CMD16', 'repair command is documented as diagnostic by default and execute-gated for safe repair', commands.includes('| `/gse repair` | Diagnose or repair stale state') && commands.includes('/gse repair') && commands.includes('Automatic writes are limited to reversible residual-risk compaction') && skill.includes('audit-state-repair.mjs'), 'SKILL.md, references/commands.md'),
|
|
74
|
+
]
|
|
73
75
|
|
|
74
76
|
const passed = checks.filter((item) => item.status === 'passed').length
|
|
75
77
|
const failed = checks.length - passed
|