Tom Boucher 4bd6fb066b chore(#2880): close ADR-2143 deployment misses — table-regex fingerprint + state-document seam migration (#2889)
* chore(#2880): close ADR-2143 seam misses — widen table-regex fingerprint, migrate state-document onto the seam

The no-adhoc-markdown-parsing rule matched only a negated class whose sole
member was a pipe ([^|]), so the stricter and more common [^|\n] spelling
evaded it entirely -- src/state-document.cts hand-rolled exactly that shape
and linted clean. Widen the fingerprint to any negated class excluding a
pipe, which is the ADR-2143 section 7 prohibition as written.

With the rule fixed, state-document.cts goes red. Replace tableRowPattern
with locateFieldRow: a line scan using the markdown-table seam's
splitTableRow for cell semantics, returning the value cell's byte range, and
splice that range instead of running a whole-document content.replace. An
edit now physically cannot cross a row boundary (section 4).

Behavior is frozen -- stateReplaceField has 79 dependents across 5 command
processes. Characterization tests lock all 14 table-branch rows plus CRLF,
extract round-trip and the withFallback caller shape; a fast-check property
asserts every non-target line stays byte-identical.

Refs #2880, epic #2143

* fix(#2880): address adversarial review — lone-CR rows, field-name padding, quadratic scan, over-broad fingerprint

Isolated adversarial review found four defects in the first commit.

1. locateFieldRow split lines on \n only. JS treats a lone \r as a line
   terminator, so the regex it replaced matched rows separated by bare CR.
   "| Phase | 3 |\r| Other | 9 |" returned 3 before and null after. Now
   CR, LF and CRLF are all terminators, byte offsets unchanged.

2. The field name was normalised with trim().toLowerCase(). The old regex
   embedded it verbatim, so its whitespace had to be absorbed by the row's
   own padding -- and because the group is a literal-character match rather
   than a whitespace class, a tab-padded cell does not accept a
   space-padded name. Replaced with an offset-aligned search reproducing
   the original backtracking exactly.

3. The widened fingerprint regex had two unbounded [^\]]* around an
   optional and ran quadratically over every regex source in every linted
   file: 256000 chars took 23 seconds. Replaced with a single-pass scanner
   that never rescans; the same input is now ~1ms.

4. The fingerprint also matched non-table idioms such as [^\s|] and [^"|].
   Narrowed to a class excluding the pipe plus only \n, \r or \t.

Differential fuzz against origin/next: 20000 cases, 0 mismatches.

Refs #2880, epic #2143

* test(#2880): drop wall-clock assertion from the ReDoS regression guard

local/no-elapsed-assertion flagged the elapsed-time check, and CLAUDE.md
bans timing assertions outright as flaky. The 256000-char input stays as
the regression guard for the quadratic scan; correctness of the verdict is
what is asserted. If the quadratic path returns, the test stops completing
and surfaces as a suite timeout rather than a silent pass.

Also adds the changeset fragment for #2880.

Refs #2880

* fix(#2880): spec-correct case folding, property tests, naming

Code-review findings.

The field-name comparison used toLowerCase(). The regex it replaced used
/i WITHOUT /u, and ECMAScript Canonicalize deliberately does not fold a
non-ASCII character onto an ASCII one -- KELVIN SIGN U+212A matched ASCII
K where the old code returned null. Replaced with spec-correct
Canonicalize, including the multi-character uppercase case (eszett -> SS),
which a naive uppercase comparison also gets wrong.

Added the fast-check property tests CLAUDE.md requires for parsers: one
for the negated-class scanner, one for the field-name fold semantics, each
against an independent reference implementation. Both reference impls
failed on first run against real bugs, so neither property is vacuous.

Renamed p2/p3 to name the exactly-three-pipes invariant, and reduced a
duplicated comment to a cross-reference.

Differential fuzz vs origin/next: 20000 runs, 0 mismatches, with the
harness proven to discriminate the KELVIN case.

Refs #2880

* chore(#2880): backfill changeset PR number (#2889)

* docs(#2890): correct the local ESLint plugin path in CONTEXT.md

CONTEXT.md named the local AST-rule plugin directory as
scripts/eslint-rules/, which does not exist. The real location is
eslint-rules/ at the repo root -- what eslint.config.mjs actually
imports -- and CONTEXT.md's own later entry already says so
explicitly, so the file disagreed with itself.

Found by a line-by-line audit of all 1036 lines against the live
graph; this was the only confirmed inaccuracy.

Closes #2890

---------

Co-authored-by: Test <test@example.com>
2026-07-30 19:55:03 -04:00
2026-07-21 23:54:43 +00:00
2026-07-21 23:54:43 +00: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 79 MiB
Languages
JavaScript 82.2%
TypeScript 17.4%
Shell 0.4%