Tom Boucher 1f6822ccba test(#2722): emitted-artifact provenance table with a totality guard (#2735)
* test(#2722): emitted-artifact provenance table with a totality guard

Adds the declarative emitted-path -> source-path table that ADR-2719 §2
specifies, plus the totality guard that keeps it honest. Phase 2 of #2719.

Every emitted path across all 19 committed golden-parity manifests (8,524
paths) must match exactly one rule. Zero matches, two matches, and a rule
matching nothing are all hard failures, so a new emitted family fails the
build loudly instead of passing through unattributed.

The measured surface is larger than #2722 estimated from claude.json alone
(26 top-level families across 19 runtimes, not 13), which is itself what the
totality guard exists to surface. It resolves to 19 rules.

Building the table caught three false attributions that were total but
resolved to repo files that do not exist -- Copilot's `<name>.agent.md`
rename, Kimi's code-literal `agents/gsd.{yaml,md}` root agent, and Copilot's
`hooks/gsd-session.json` registration. The "every attributed source exists"
test is therefore a first-class gate, not a nicety.

Notable correctness decisions:
- Emitted shapes are hard-coded; deriving them from the installer would make
  the guard tautological (it would follow any installer change silently).
  Only source paths read a first-party descriptor, and only where the
  descriptor is the sole declaration (hostBehaviors.nativePlugin.source).
- Emitted skills attribute to commands/gsd/*.md, NOT the repo skills/ dir --
  that directory is generated from commands/gsd by gen-plugin-skills.cjs, so
  attributing to it would be false attribution that still passes totality.
- Attribution is keyed on (rel, runtime): plugins/gsd-core.js has different
  sources for opencode and kilo.
- Rule order carries no semantics (property-tested), since exactly-one
  matching is enforced rather than first-match-wins.

Nothing here reads a git diff, builds a live manifest, or touches a fixture;
the differential check, drift-ack file and size ratchet are #2723.

Refs #2719

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W5kQs6ZufZDySC6zDJfYP6

* docs(#2722): record the delivered provenance table in the CONTEXT.md glossary

The `### Emitted Artifact Provenance` entry landed in #2721 describing the
table as future work. Phase 2 delivers it, so the glossary now records what
actually exists and the invariants #2723 must preserve:

- where the table lives, its rule count, and that it is total over all 8,524
  emitted paths across the 19 manifests
- dead-rule detection, so table rot is loud in both directions
- the corrected surface measurement (26 families, not the 13 estimated from
  claude.json alone)
- the two invariants #2723 inherits: shapes hard-coded (deriving them would
  make the guard tautological), and attribution keyed on (rel, runtime)
- the skills/ false-attribution trap, and that totality does NOT catch a
  wrong-source rule — the source-existence assertion is what does

Refs #2719

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W5kQs6ZufZDySC6zDJfYP6

* test(#2722): close five review findings on the provenance table

Two orthogonal review passes plus an isolated adversarial reviewer returned
findings at minor..major. All fixed; no blockers were raised.

Standards axis (CONTEXT.md:456, RULESET.TESTS.guard-toplevel-readFileSync):
- module-level loadManifests() threw at require time before any test()
  registered, turning a missing fixture dir into an opaque crash instead of
  one named failure. Now a memoized lazy accessor.
- matchRules and assertTotality each carried their own copy of the matching
  loop; assertTotality now calls matchRules. That is the #2266 divergence
  class, and two copies could let the guard and the attributor disagree.
- named the corpus stride constant; dropped an inline require.

Spec axis:
- the CONTEXT.md glossary carried a "26 families" figure that is not
  reproducible from the code and that no test pinned -- a hand-maintained
  number in permanent canon, i.e. exactly the silent drift this epic exists
  to end. All volatile counts are now removed from the glossary, with the
  reason stated inline: the guard recomputes them every run, so they belong
  in a failure message, not in prose. No test was added to pin the count,
  because that would rebuild the brittle committed number we are deleting.

Isolated adversarial review:
- `.+` tail captures let a `..` segment reach a constructed source path that
  resolves outside the repo. Not live-exploitable (fixtures are committed and
  the only consumer is an existsSync probe) but Phase 3 feeds these strings
  into a diff-consuming check, so assertSafeRelPath now fails closed once, in
  matchRules, rather than per-rule.
- attributeEmittedPath's ambiguous-match branch was never exercised; only
  assertTotality's parallel path was. Now tested directly.
- sampleLimit's truncation branch had no limit-1/limit/limit+1 coverage.
- the fast-check property could not fail for the reason it was named for.

That last one took two attempts and is the one worth reading. The property
hand-rolled its shuffled side from the per-rule matchOne primitive, which is
order-independent by construction, so it held for reasons unrelated to the
shipped matchRules. Routing it through the real matchRules was still not
enough: on an unambiguous table, first-match-wins and collect-all return
identical results for every path (measured: 0 of 190 corpus paths differ).
Order can only matter where more than one rule matches, so the property now
also asserts that an intentionally ambiguous table reports BOTH hits as a set
under every permutation. Verified by mutation -- injecting a `break` into
matchRules makes it fail, and restoring makes it pass.

Enabling all of the above: matchRules and attributeEmittedPath now take an
injectable rules table, so tests can drive the real code path instead of
re-implementing it by hand.

Refs #2719

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W5kQs6ZufZDySC6zDJfYP6

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 21:51:51 -04:00

GSD Core

Git. Ship. Done.

English · Português · 简体中文 · 日本語 · 한국어

A light-weight meta-prompting, context engineering, and spec-driven development system for Claude Code, OpenCode, Antigravity CLI, Kimi CLI, Kilo, Codex, Copilot, Cursor, Windsurf, and more.

npm version npm downloads Tests Discord GitHub stars License


What is GSD Core

GSD Core is a context-engineering and spec-driven development framework that drives AI coding agents (Claude Code, Codex, Antigravity CLI, Kimi CLI, Copilot, Cursor, and more) through a disciplined phase loop. It solves context rot — the quality degradation that accumulates as an AI fills its context window — by running all heavy research, planning, and execution work in fresh-context subagents while keeping your main session lean.


How it works

Each milestone repeats the same five-step loop, one phase at a time:

  1. Discuss — capture implementation decisions before anything is planned
  2. Plan — research, decompose, and verify the plan fits a fresh context window
  3. Execute — run plans in parallel waves; each executor starts with a clean 200k-token context
  4. Verify — walk through what was built; diagnose and fix before declaring done
  5. Ship — create the PR, archive the phase, repeat for the next one

Quickstart

npx @opengsd/gsd-core@latest

The installer prompts for your runtime (Claude Code, OpenCode, Antigravity CLI, Kimi CLI, Kilo, Codex, Copilot, Cursor, Windsurf, and more) and whether to install globally or locally. The installer is required for cross-runtime compatibility — do not copy files from agents/ or commands/ directly.

On another runtime or without Node.js? See Install on your runtime.

Once installed, start a new project or onboard an existing repo:

/gsd-new-project   # greenfield project
/gsd-onboard       # existing codebase

New here? Follow Your first project for a guided walkthrough from install to first shipped phase, or Onboarding an existing codebase for brownfield setup.


Documentation

What's new in 1.7.0 → docs/whats-new-1.7.0.md

Tutorials — learning by doing:

How-to guides — task-focused recipes:

Reference — authoritative facts:

Explanation — concepts and design decisions:

Full index: docs/README.md. Other languages: 日本語 · 한국어 · Português · 简体中文.


Why it works

Most AI-coding setups fail at scale because context bloat silently degrades output quality, there is no shared memory between sessions, and nothing verifies that code actually works. GSD Core solves all three: heavy work runs in fresh subagents, structured artifacts like STATE.md and CONTEXT.md survive session boundaries, and the verify step walks through what was built and generates fix plans before a phase is declared done. See docs/explanation/context-engineering.md for the full reasoning.

Troubleshooting? See docs/how-to/recover-and-troubleshoot.md.


Community

Project Platform
gsd-opencode Original OpenCode port
Discord Community support

Star History

Star History Chart

License

MIT License. See LICENSE for details.


Claude Code is powerful. GSD Core makes it reliable.

Description
No description provided
Readme MIT 77 MiB
Languages
JavaScript 82.3%
TypeScript 17.4%
Shell 0.3%