* enhance(#3915): stryker on the official tap runner, per-test coverage The 'command' runner is the one runner Stryker excludes from coverage analysis, which forced coverageAnalysis:'off' and made mutation cost strictly linear in (mutants x whole-shard test time). The frontmatter shard measured 1751s against 212s for the next slowest. Swap to @stryker-mutator/tap-runner (official plugin, peer-pinned to the @stryker-mutator/core@9.6.1 already installed) and turn coverage analysis on, so Stryker re-runs only the test files that cover each mutated line. Per-shard injection moves from a MUTATION_TEST_CMD command string to MUTATION_TEST_FILES, read by a new fail-closed resolveMutationTestFiles() that mirrors resolveMutationBreak. It stays derived from scripts/mutation-matrix.cjs and now has a single owner: the union moves behind allCoveredTests() and stryker.config.mjs no longer imports COVERED. The resolver existence-checks every entry, because the tap runner resolves tap.testFiles with glob() and a non-matching pattern yields an empty list silently - a fast, confident, meaningless run. tap.forceBail is off by measurement, not preference: a structural AST audit found 3 of 26 shard test files spawn subprocesses, and bail fires on every killed mutant, so leaving it on would kill processes mid-spawnSync and orphan their children. The matrix 'isolation' field is removed - per-file process isolation is inherent to the tap runner, so the field had no consumer left. Score arithmetic is unchanged and now pinned: mutationScore counts NoCoverage in the same denominator as Survived, which both Stryker's thresholds.break and check-mutation-score-ratchet.cjs read. A new non-vacuity test proves it diverges from mutationScoreBasedOnCoveredCode, so the gate cannot be quietly swapped to the field that would make every floor trivially satisfiable. Refs #3915 * fix(#3915): enforce the resolver's documented containment contract Review findings, all fixed in place. resolveMutationTestFiles claimed to verify each entry exists 'relative to the repo root' but used a bare fs.existsSync(path.join(...)), which accepts an existing DIRECTORY and lets ../ segments escape the root (path.join('/repo/root','../../etc/passwd') resolves to /etc/passwd). Not reachable from PR content - the value only ever comes from the static COVERED registry via CI env - but a fail-closed contract that overstates its own guarantee is a defect in the contract. Each entry is now resolved, rejected if path.relative puts it outside the root, and required to be a regular file. Three hostile-input tests added; the original missing-file wording is preserved so the existing assertion still binds. Also: removed a stale buildResult comment still naming the isolation field this branch deleted; hoisted one top-level path require in place of three inline ones; de-duplicated the derived-test-list expression in the tests to a single const, deliberately still re-derived from COVERED rather than calling allCoveredTests() so the assertion cannot become a tautology; tightened the workflow-parity assertion to exact equality; changed the tap-runner range from an exact 9.6.1 to ^9.6.1 so it tracks the caret-ranged core its peerDependency pins exactly. Regenerated examples/dynamic-context-management/CONTEXT-INDEX.json, which the earlier CONTEXT.md edit left stale - lint:ci was red on lint-example-parser-parity until it was refreshed. Refs #3915 * test(#3915): kill model-catalog survivors, set frontmatter budget from measurement From mutation run 33026833181 (all 13 shards, dispatched on this branch before any PR). WALL TIME: frontmatter measured 713s (11m53s) vs 1751s (29m11s) on the command runner, a 59% cut. timeoutMinutes 60 -> 20 (1.68x measured). Not deleted outright: the shared 15-minute default would leave only 21% headroom, and this module's mutant count grew 1.8x in one change. MODEL-CATALOG: came back 57.91 against its floor of 58. Diagnosed from the report JSON, not assumed - all 24 of its new RuntimeError mutants are in the load-time catalog bootstrap, so mutating them makes the module throw at require. Under node --test that is a failed test file (Killed); under the tap runner the process dies before emitting TAP, which Stryker classifies RuntimeError and excludes from the denominator. Add them back as killed and the shard is 248/416 = 59.62, the pre-change number exactly. Detection did not regress, classification changed. The floor is NOT lowered to absorb that. 11 new behavioural tests target ~42 genuinely surviving mutants: exact Set equality on the EFFORT_RENDERING/EFFORT_ARGV supported sets, an exact-string table render that makes the column-width arithmetic observable (padEnd never truncates, so the old substring assertion could not see a too-small width), clampEffortForHost's full null matrix plus a spoofed-toString host, and a prototype-pollution guard driven through Object.fromEntries. Mutants judged equivalent were skipped rather than papered over; reasoning is in the phase artifacts. All 15 new assertions verified against unmutated code. lint:ci exit 0. Refs #3915 * test(#3915): ratchet model-catalog's floor to 74 on measured 75.26% CI run 33029755081 measured model-catalog at 75.26% (295 killed / 49 survived / 48 no-coverage / 24 runtime-error, totalValid 392), so check-mutation-score-ratchet.cjs correctly failed the shard for unclaimed headroom: 17.26 points above the declared floor of 58, well past the 5-point slack. Floor raised 58 -> 74 (floor(75.26)-1, this file's documented convention), with RATCHET_BASELINE updated in the same diff as the equality assertion requires. Worth recording why the number moved this far. The shard first came back at 57.91 under the tap runner and the temptation was to lower the floor to match. The drop was not a regression: all 24 of its RuntimeError mutants sit in the load-time catalog bootstrap, and adding them back as killed reproduces 248/416 = 59.62, the pre-swap figure exactly. Rather than absorb a reporting artifact by weakening the gate, 11 behavioural tests went after the genuinely surviving mutants and killed 68 of them - carrying the module from 59.62 past its old ceiling to 75.26, within reach of the ADR-456 target of 80. The #3007 measurement is kept as clearly-labelled prior context rather than deleted, so the entry does not read as carrying two current numbers. Refs #3915 --------- Co-authored-by: sim <sim@local>
164 lines
10 KiB
JSON
164 lines
10 KiB
JSON
{
|
|
"name": "@opengsd/gsd-core",
|
|
"version": "1.11.0",
|
|
"description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
|
"main": ".opencode/plugins/gsd-core.js",
|
|
"bin": {
|
|
"gsd-core": "bin/install.js",
|
|
"gsd-tools": "gsd-core/bin/gsd-tools.cjs",
|
|
"gsd_run": "gsd-core/bin/gsd_run",
|
|
"gsd-mcp-server": "bin/gsd-mcp-server.js"
|
|
},
|
|
"files": [
|
|
"bin",
|
|
"commands",
|
|
"skills",
|
|
"gsd-core",
|
|
"assets",
|
|
"agents",
|
|
".claude-plugin",
|
|
".opencode",
|
|
"GEMINI.md",
|
|
"hooks",
|
|
"scripts",
|
|
"!scripts/gen-emitted-baseline.cjs",
|
|
"!scripts/qa-smell-ratchet.cjs",
|
|
"!scripts/live-config-guard.cjs",
|
|
"!scripts/run-tests.cjs",
|
|
"!scripts/affected-tests-lib.cjs",
|
|
"!scripts/run-affected-tests.cjs",
|
|
"!scripts/lint-no-adhoc-regex-escape.cjs",
|
|
"!scripts/lint-allow-test-rule-refs.cjs",
|
|
"pi",
|
|
"vscode"
|
|
],
|
|
"keywords": [
|
|
"claude",
|
|
"claude-code",
|
|
"ai",
|
|
"meta-prompting",
|
|
"context-engineering",
|
|
"spec-driven-development",
|
|
"codex",
|
|
"codex-cli"
|
|
],
|
|
"author": "OpenGSD",
|
|
"license": "MIT",
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "git+https://github.com/open-gsd/gsd-core.git"
|
|
},
|
|
"homepage": "https://github.com/open-gsd/gsd-core",
|
|
"bugs": {
|
|
"url": "https://github.com/open-gsd/gsd-core/issues"
|
|
},
|
|
"publishConfig": {
|
|
"access": "public"
|
|
},
|
|
"engines": {
|
|
"node": ">=24.0.0",
|
|
"npm": ">=10.0.0"
|
|
},
|
|
"dependencies": {
|
|
"@anthropic-ai/claude-agent-sdk": "^0.2.84",
|
|
"ws": "^8.21.0"
|
|
},
|
|
"devDependencies": {
|
|
"@eslint/js": "^9.39.4",
|
|
"@stryker-mutator/core": "^9.6.1",
|
|
"@stryker-mutator/tap-runner": "^9.6.1",
|
|
"@types/node": "^22.19.19",
|
|
"c8": "^11.0.0",
|
|
"eslint": "^9.39.4",
|
|
"eslint-plugin-n": "^17.24.0",
|
|
"eslint-plugin-no-only-tests": "^3.4.0",
|
|
"espree": "^10.4.0",
|
|
"fast-check": "^4.8.0",
|
|
"globals": "^16.5.0",
|
|
"js-yaml": "^4.3.1",
|
|
"mutation-testing-metrics": "^3.7.3",
|
|
"re2js": "^2.8.6",
|
|
"typescript": "^6.0.3",
|
|
"typescript-eslint": "^8.60.0"
|
|
},
|
|
"overrides": {
|
|
"qs": ">=6.15.2",
|
|
"body-parser": ">=2.3.0",
|
|
"@hono/node-server": ">=2.0.5"
|
|
},
|
|
"optionalDependencies": {
|
|
"fallow": "^2.70.0"
|
|
},
|
|
"scripts": {
|
|
"sync:launcher": "node scripts/sync-runtime-launcher.cjs",
|
|
"check:contract-drift": "node scripts/check-contract-drift.cjs",
|
|
"check:env": "node scripts/check-env.cjs",
|
|
"check:alias-drift": "node scripts/check-alias-drift.cjs",
|
|
"check:identity-drift": "node scripts/lint-package-identity-drift.cjs",
|
|
"check:phase-id-drift": "node scripts/lint-phase-id-drift.cjs",
|
|
"check:integrity": "node scripts/check-npm-integrity.cjs",
|
|
"build": "npm run generate:identity && npm run build:lib && npm run gen:section-manifest && npm run gen:context-index && npm run gen:plugin-skills && npm run gen:loop-host-contract && npm run gen:capability-registry && npm run build:hooks",
|
|
"build:hooks": "node scripts/build-hooks.js",
|
|
"build:lib": "tsc -p tsconfig.build.json",
|
|
"generate:identity": "node scripts/generate-package-identity.cjs",
|
|
"gen:context-index": "node scripts/gen-context-index.cjs --write",
|
|
"gen:loop-host-contract": "node scripts/gen-loop-host-contract.cjs --write",
|
|
"gen:plugin-skills": "node scripts/gen-plugin-skills.cjs --write",
|
|
"gen:capability-registry": "node scripts/gen-capability-registry.cjs --write",
|
|
"gen:registry": "node scripts/gen-registry.cjs --write",
|
|
"gen:install-tree": "node scripts/gen-install-tree-fixtures.cjs",
|
|
"gen:section-manifest": "node scripts/gen-section-manifest.cjs --write",
|
|
"regen:derived": "npm run build && npm run gen:registry && node scripts/gen-adr-index.cjs --write && node scripts/gen-features.cjs --write && node scripts/gen-capability-matrix.cjs --write && node scripts/gen-inventory-manifest.cjs --write && node scripts/gen-context-index.cjs --write && node scripts/gen-state-md-docs.cjs --write && npm run gen:section-manifest && node scripts/sync-manifest-versions.cjs && npm run gen:install-tree && node scripts/gen-scripts-cli-exit.cjs --write",
|
|
"validate:registry": "node scripts/validate-registry.cjs",
|
|
"prepack": "npm run build:lib",
|
|
"prepare": "npm run build:lib",
|
|
"version": "node scripts/sync-manifest-versions.cjs --stage && node scripts/gen-capability-registry.cjs --write && git add gsd-core/bin/lib/capability-registry.cjs",
|
|
"prepublishOnly": "npm run build:lib && npm run build:hooks",
|
|
"pretest": "npm run build:lib && npm run lint:skill-deps",
|
|
"pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
|
|
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings 0",
|
|
"lint:fix": "eslint . --fix",
|
|
"lint:table-schema-drift": "node scripts/lint-table-schema-drift.cjs",
|
|
"lint:frontmatter-scalar-broad-grep": "node scripts/lint-frontmatter-scalar-broad-grep.cjs",
|
|
"lint:removed-but-needed": "node scripts/lint-removed-but-needed.cjs",
|
|
"lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-emitted-drift-ack.cjs && node scripts/lint-portable-timeout.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-fix-has-regression-tests.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs && node scripts/lint-plan-count-drift.cjs && node scripts/lint-milestone-window-drift.cjs && node scripts/lint-phase-enumeration-drift.cjs && node scripts/lint-planning-prompt-drift.cjs && node scripts/lint-unreachable-guard-drift.cjs && node scripts/lint-completion-ratio-drift.cjs && node scripts/lint-state-field-drift.cjs && node scripts/lint-state-write-path-drift.cjs && node scripts/lint-completion-predicate-drift.cjs && node scripts/lint-planning-snapshot-bypass-drift.cjs && node scripts/lint-health-diagnostic-rule-table.cjs && node scripts/lint-planning-artifact-writer-drift.cjs && node scripts/lint-frontmatter-scalar-broad-grep.cjs && node scripts/lint-removed-but-needed.cjs && node scripts/lint-no-adhoc-regex-escape.cjs && node scripts/lint-vendored-deps.cjs && node scripts/lint-docs-guard-registration.cjs && node scripts/lint-source-test-name-collision.cjs && npm run lint:hooks-runtime-build-seam && node scripts/check-contract-drift.cjs && node scripts/lint-mutation-test-derivation-drift.cjs",
|
|
"lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
|
|
"lint:regression-names": "node scripts/lint-regression-test-names.cjs",
|
|
"lint:descriptions": "node scripts/lint-descriptions.cjs",
|
|
"lint:skill-deps": "node scripts/lint-skill-deps.cjs",
|
|
"lint:test-file-count": "node scripts/lint-test-file-count.cjs",
|
|
"lint:pr-checks": "node scripts/lint-pr-check-project-dir.cjs",
|
|
"lint:changeset": "node scripts/changeset/lint.cjs",
|
|
"lint:generated-sync": "node scripts/gen-capability-registry.cjs --check && node scripts/gen-loop-host-contract.cjs --check && node scripts/gen-capability-matrix.cjs --check && node scripts/sync-manifest-versions.cjs --check && node scripts/gen-inventory-manifest.cjs --check && node scripts/generate-package-identity.cjs --check && node scripts/gen-plugin-skills.cjs --check && node scripts/gen-registry.cjs --check && node scripts/gen-adr-index.cjs --check && node scripts/gen-features.cjs --check && node scripts/check-glossary-refs.cjs --check && node scripts/lint-compiled-artifact-sync.cjs --check && node scripts/gen-context-index.cjs --check && node scripts/gen-section-manifest.cjs --check && node scripts/gen-health-docs.cjs --check && node scripts/gen-state-md-docs.cjs --check && node scripts/gen-scripts-cli-exit.cjs --check",
|
|
"lint:docs": "node scripts/lint-docs-required.cjs",
|
|
"lint:qa-smells": "node scripts/qa-smell-ratchet.cjs",
|
|
"lint:legacy-name": "node scripts/lint-legacy-dir-name.cjs",
|
|
"lint:docs-command-form": "node scripts/lint-docs-command-form.cjs",
|
|
"lint:hooks-runtime-build-seam": "node scripts/lint-hooks-runtime-build-seam.cjs",
|
|
"ci:test-scope": "node scripts/ci-test-scope.cjs",
|
|
"changeset": "node scripts/changeset/new.cjs",
|
|
"changelog:render": "node scripts/changeset/cli.cjs render",
|
|
"test": "node scripts/run-tests.cjs",
|
|
"test:unit": "node scripts/run-tests.cjs --suite unit",
|
|
"test:integration": "node scripts/run-tests.cjs --suite integration",
|
|
"test:install": "node scripts/run-tests.cjs --suite install",
|
|
"test:security": "node scripts/run-tests.cjs --suite security",
|
|
"test:slow": "node scripts/run-tests.cjs --suite slow",
|
|
"test:qa": "node scripts/run-tests.cjs --suite qa",
|
|
"test:affected": "node scripts/run-affected-tests.cjs",
|
|
"test:coverage": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
|
|
"test:coverage:scripts-floor": "c8 check-coverage --lines 55 --include 'scripts/**/*.cjs' --exclude 'tests/**' --all",
|
|
"test:coverage:unit": "c8 --reporter text --reporter json-summary --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && node scripts/check-coverage-gate.cjs",
|
|
"test:coverage:unit:raw": "c8 --reporter none node scripts/run-tests.cjs --suite unit",
|
|
"test:coverage:report": "c8 report --reporter text --reporter json-summary --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all && node scripts/check-coverage-gate.cjs",
|
|
"test:coverage:all": "npm run test:coverage",
|
|
"test:mutation": "stryker run",
|
|
"test:mutation:since": "stryker run --incremental --since origin/next",
|
|
"gen:features": "node scripts/gen-features.cjs",
|
|
"gen:state-md-docs": "node scripts/gen-state-md-docs.cjs"
|
|
},
|
|
"allowScripts": {
|
|
"fallow@2.70.0": true
|
|
}
|
|
}
|