From 12d6285b4fdc0a8049fd2e491a05ece08110b6fb Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Thu, 11 Jun 2026 11:36:18 -0400 Subject: [PATCH] fix(#1000): align gsd-intel-updater output to canonical intel filenames (#1037) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(#1000): align gsd-intel-updater output to canonical intel filenames The intel-updater agent was instructed to write short names (files.json, apis.json, deps.json) and a markdown arch.md, but the intel library + gsd-tools intel CLI read only the canonical long names from INTEL_FILES (file-roles.json, api-map.json, dependency-graph.json, arch-decisions.json as JSON). After /gsd:map-codebase --query refresh the agent output was orphaned — intel status and validate reported the canonical files missing and intel query returned nothing. Renames every short reference to its INTEL_FILES canonical name and converts the arch output from markdown to queryable arch-decisions.json. Adds a drift-proof regression test (derived from the exported INTEL_FILES map) in the owning module's test file tests/intel.test.cjs, reviving the maintainer-approved approach from closed PR #608. Closes #1000 Co-Authored-By: Claude Opus 4.8 * chore(#1000): backfill changeset PR number to 1037 Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 --- .../1000-intel-updater-canonical-filenames.md | 5 ++ agents/gsd-intel-updater.md | 76 +++++++++---------- tests/intel.test.cjs | 40 ++++++++++ 3 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 .changeset/1000-intel-updater-canonical-filenames.md diff --git a/.changeset/1000-intel-updater-canonical-filenames.md b/.changeset/1000-intel-updater-canonical-filenames.md new file mode 100644 index 000000000..e3f6de178 --- /dev/null +++ b/.changeset/1000-intel-updater-canonical-filenames.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 1037 +--- +**`gsd-intel-updater` now writes the canonical intel filenames the `gsd-tools intel` CLI actually reads** — the agent was instructed to emit short names (`files.json`, `apis.json`, `deps.json`) and a markdown `arch.md`, but the intel library reads only `file-roles.json`, `api-map.json`, `dependency-graph.json`, and `arch-decisions.json` (JSON). After `/gsd:map-codebase --query refresh` the output was orphaned, so `intel status`/`validate` reported the files missing and `intel query` returned nothing. The agent now emits the canonical long names and structured `arch-decisions.json`. (#1000) diff --git a/agents/gsd-intel-updater.md b/agents/gsd-intel-updater.md index 549af4039..3e12f0cf7 100644 --- a/agents/gsd-intel-updater.md +++ b/agents/gsd-intel-updater.md @@ -88,7 +88,7 @@ EXCLUDE from counts and analysis: - `.planning/` -- Planning docs, not project code - `node_modules/`, `dist/`, `build/`, `.git/` -**Count accuracy:** When reporting component counts in stack.json or arch.md, always derive +**Count accuracy:** When reporting component counts in stack.json or arch-decisions.json, always derive counts by running Glob on the layout-resolved canonical locations above, not from memory or CLAUDE.md. Example (standard layout): `Glob("agents/*.md")`. Example (kilo): `Glob(".kilo/agents/*.md")`. @@ -108,7 +108,7 @@ If encountered, skip silently. Do NOT include contents. All JSON files include a `_meta` object with `updated_at` (ISO timestamp) and `version` (integer, start at 1, increment on update). -### files.json -- File Graph +### file-roles.json -- File Graph ```json { @@ -127,7 +127,7 @@ All JSON files include a `_meta` object with `updated_at` (ISO timestamp) and `v Types: `entry-point`, `module`, `config`, `test`, `script`, `type-def`, `style`, `template`, `data`. -### apis.json -- API Surfaces +### api-map.json -- API Surfaces ```json { @@ -144,7 +144,7 @@ Types: `entry-point`, `module`, `config`, `test`, `script`, `type-def`, `style`, } ``` -### deps.json -- Dependency Chains +### dependency-graph.json -- Dependency Chains ```json { @@ -180,31 +180,24 @@ Each dependency entry should also include `"invocation": " Identify non-code content formats that are structurally important to the project and include them in `content_formats`. -### arch.md -- Architecture Summary +### arch-decisions.json -- Architecture Summary -```markdown ---- -updated_at: "ISO-8601" ---- +arch-decisions.json is JSON (NOT markdown). The `gsd-tools intel` CLI reads, validates, and queries it as JSON. Capture the architecture as descriptive keyed entries: -## Architecture Overview - -{pattern name and description} - -## Key Components - -| Component | Path | Responsibility | -|-----------|------|---------------| - -## Data Flow - -{entry point} -> {processing} -> {output} - -## Conventions - -{naming, file organization, import patterns} +```json +{ + "_meta": { "updated_at": "ISO-8601", "version": 1 }, + "entries": { + "overview": { "pattern": "{architecture pattern name}", "description": "{what it is and why}" }, + "data-flow": { "flow": "{entry} -> {processing} -> {output}", "description": "{detail}" }, + "conventions": { "naming": "{...}", "file-organization": "{...}", "imports": "{...}" }, + "component:{Name}": { "path": "{path}", "responsibility": "{what it does}" } + } +} ``` +Add one `component:{Name}` entry per key component, plus any other descriptive keys that fit (e.g. `security`, `modes`, a domain engine). Keys and string values are what `intel query ` searches, so keep them descriptive. + ## Exploration Process @@ -226,9 +219,9 @@ gsd-tools intel patch-meta .planning/intel/stack.json Glob source files (`**/*.ts`, `**/*.js`, `**/*.py`, etc., excluding node_modules/dist/build). Read key files (entry points, configs, core modules) for imports/exports. -Write `files.json`. Then patch its timestamp: +Write `file-roles.json`. Then patch its timestamp: ```bash -gsd-tools intel patch-meta .planning/intel/files.json +gsd-tools intel patch-meta .planning/intel/file-roles.json ``` Focus on files that matter -- entry points, core modules, configs. Skip test files and generated code unless they reveal architecture. @@ -237,24 +230,27 @@ Focus on files that matter -- entry points, core modules, configs. Skip test fil Grep for route definitions, endpoint declarations, CLI command registrations. Patterns to search: `app.get(`, `router.post(`, `@GetMapping`, `def route`, express route patterns. -Write `apis.json`. If no API endpoints found, write an empty entries object. Then patch its timestamp: +Write `api-map.json`. If no API endpoints found, write an empty entries object. Then patch its timestamp: ```bash -gsd-tools intel patch-meta .planning/intel/apis.json +gsd-tools intel patch-meta .planning/intel/api-map.json ``` ### Step 5: Dependencies Read package.json (dependencies, devDependencies), requirements.txt, go.mod, Cargo.toml. Cross-reference with actual imports to populate `used_by`. -Write `deps.json`. Then patch its timestamp: +Write `dependency-graph.json`. Then patch its timestamp: ```bash -gsd-tools intel patch-meta .planning/intel/deps.json +gsd-tools intel patch-meta .planning/intel/dependency-graph.json ``` ### Step 6: Architecture -Synthesize patterns from steps 2-5 into a human-readable summary. -Write `arch.md`. +Synthesize patterns from steps 2-5 into structured JSON. +Write `arch-decisions.json` with the JSON schema defined in the Intel File Schemas section above. Then patch its timestamp: +```bash +gsd-tools intel patch-meta .planning/intel/arch-decisions.json +``` ### Step 6.5: Self-Check @@ -278,8 +274,8 @@ This writes `.last-refresh.json` with accurate timestamps and hashes. Do NOT wri ## Partial Updates When `focus: partial --files ` is specified: -1. Only update entries in files.json/apis.json/deps.json that reference the given paths -2. Do NOT rewrite stack.json or arch.md (these need full context) +1. Only update entries in file-roles.json/api-map.json/dependency-graph.json that reference the given paths +2. Do NOT rewrite stack.json or arch-decisions.json (these need full context) 3. Preserve existing entries not related to the specified paths 4. Read existing intel files first, merge updates, write back @@ -287,13 +283,13 @@ When `focus: partial --files ` is specified: | File | Target | Hard Limit | |------|--------|------------| -| files.json | <=2000 tokens | 3000 tokens | -| apis.json | <=1500 tokens | 2500 tokens | -| deps.json | <=1000 tokens | 1500 tokens | +| file-roles.json | <=2000 tokens | 3000 tokens | +| api-map.json | <=1500 tokens | 2500 tokens | +| dependency-graph.json | <=1000 tokens | 1500 tokens | | stack.json | <=500 tokens | 800 tokens | -| arch.md | <=1500 tokens | 2000 tokens | +| arch-decisions.json | <=1500 tokens | 2000 tokens | -For large codebases, prioritize coverage of key files over exhaustive listing. Include the most important 50-100 source files in files.json rather than attempting to list every file. +For large codebases, prioritize coverage of key files over exhaustive listing. Include the most important 50-100 source files in file-roles.json rather than attempting to list every file. - [ ] All 5 intel files written to .planning/intel/ diff --git a/tests/intel.test.cjs b/tests/intel.test.cjs index 1a388dd13..4cf54ebdb 100644 --- a/tests/intel.test.cjs +++ b/tests/intel.test.cjs @@ -25,6 +25,7 @@ const { intelApiSurface, ensureIntelDir, isIntelEnabled, + INTEL_FILES, } = require('../gsd-core/bin/lib/intel.cjs'); // ─── Helpers ──────────────────────────────────────────────────────────────── @@ -846,3 +847,42 @@ describe('intelApiSurface', () => { assert.ok('stale' in result, 'result must have stale field'); }); }); + +describe('#1000 regression: gsd-intel-updater emits canonical intel filenames', () => { + // allow-test-rule: source-text-is-the-product — agents/gsd-intel-updater.md IS the + // system prompt the intel-updater agent runs under; asserting its filename references + // verifies the deployed agent surface contract matches the INTEL_FILES the CLI reads. + const agentPromptPath = path.join(__dirname, '..', 'agents', 'gsd-intel-updater.md'); + const agentPrompt = fs.readFileSync(agentPromptPath, 'utf8'); + + test('references every canonical INTEL_FILES name', () => { + for (const filename of Object.values(INTEL_FILES)) { + assert.ok( + agentPrompt.includes(filename), + `gsd-intel-updater.md must instruct writing the canonical intel file "${filename}" (from INTEL_FILES) that the gsd-tools intel CLI reads; it was missing.`, + ); + } + }); + + test('does not reference orphaned short filenames the CLI never reads', () => { + // Short forms `${key}.json` that are NOT canonical INTEL_FILES values are orphaned — + // the agent must not emit them. Also forbid the markdown arch.md output. + const canonical = new Set(Object.values(INTEL_FILES)); + const forbidden = Object.keys(INTEL_FILES) + .map((k) => `${k}.json`) + .filter((short) => !canonical.has(short)); + forbidden.push('arch.md'); + for (const shortName of forbidden) { + // Guard against substring false-positives (e.g. 'files.json' inside 'file-roles.json'): + // canonical long names never contain these short tokens, verified by the canonical set. + const offendingLines = agentPrompt + .split('\n') + .filter((line) => line.includes(shortName)); + assert.strictEqual( + offendingLines.length, + 0, + `gsd-intel-updater.md must not reference orphaned short name "${shortName}" the intel CLI never reads. Offending line(s):\n${offendingLines.join('\n')}`, + ); + } + }); +});