Spec Studio

File-level imports show where curation is missing

spec:consumers.impact-graph.curation-assistUse Case / Behavior · featureready floor ready

Packs: pack:design-iteration-v1, pack:self-hosting-v1

Design: 7 design entries · 4 pinned declarations · 1 decision

Findings: no errors, no warnings

specs/consumers/impact-graph.curation-assist.sdp.md

No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.

Gen 1 of this tool, @libar-dev/architect, derived a mechanical import graph beside its curated one and used it to show authors where curation was missing: load-bearing modules no anchor covered, coverage by package, and designed modules no code realized yet. The idea held; the build did not. It hard-coded the repository's layout into the engine, read TypeScript only, and mixed both graphs in one query handle. A review of gen 1 found that the file-level layer gave most of its curation value and that only symbol queries need a symbol identity, which the impact graph's symbol-reach child holds open, so the file-level layer stands on its own.

Intent
actor
An author curating anchors across a codebase, or a design pass over a large redesign.
problem
Nothing tells an author which load-bearing files no anchor covers, where anchored uses and the code's imports disagree, or which component designs no code realizes yet, so curation gaps surface only when someone reads the code.
outcome
Report from file-level imports where anchors and component designs are missing or drifting, as advice that never authors intent.
Behavior
rule line 25 · specs/consumers/impact-graph.curation-assist.sdp.md:25
The layer reads file-level import edges from a per-language adapter and identifies each file by its repository-relative path, so it needs no symbol identity.
rule line 26 · specs/consumers/impact-graph.curation-assist.sdp.md:26
Every import relationship it derives is inferred; the imports file's schema and the recipe's external-inferred-input label carry that claim for all of them at once, so no relationship carries its own. The relationships stay apart from the curated graph: no uses, memberOf, satisfies or delivery fact derives from them, and a query of the curated graph never reads them unless the caller asks.
rule line 27 · specs/consumers/impact-graph.curation-assist.sdp.md:27
It reports the files with the highest import fan-in that no anchor covers, the anchored uses edges between two components whose files share no import, the imports between two anchored components that no uses states, and the component designs no component: anchor realizes yet.
rule line 28 · specs/consumers/impact-graph.curation-assist.sdp.md:28
Every report is advice: it refuses nothing, fails no validation and authors no anchor, and an author who agrees edits an anchor or a Spec as usual.
rule line 29 · specs/consumers/impact-graph.curation-assist.sdp.md:29
The engine reads no repository layout convention: source roots and module resolution come from the adapter's configuration, and a file belongs to a component only when it holds that component: anchor or a code anchor memberOf it, never through a path pattern in the engine.
rule line 30 · specs/consumers/impact-graph.curation-assist.sdp.md:30
The TypeScript adapter reads imports through the compiler library extraction already depends on; another language arrives as another adapter.
rule line 31 · specs/consumers/impact-graph.curation-assist.sdp.md:31
The adapter runs outside extraction and outside sdp q: sdp build, given the adapter's configuration, writes the import edges to generated/imports.json, sorted and without a timestamp, and the curation recipe reads that file through --params, so no query derives imports and no validator sees an inferred edge.
rule line 32 · specs/consumers/impact-graph.curation-assist.sdp.md:32
The imports configuration accepts optional root-relative exclude paths matching a file or directory subtree, refuses unknown keys, and records exclusions in its output so curation distinguishes deliberate omissions from missing input.
rule line 33 · specs/consumers/impact-graph.curation-assist.sdp.md:33
The recipe labels the file as external inferred input and reports a file present on one side only; it states nothing in the graph's name.
rule line 34 · specs/consumers/impact-graph.curation-assist.sdp.md:34
The adapter follows re-exports through barrel files, so a uses that reaches a component through an index file counts as backed by an import.
rule line 35 · specs/consumers/impact-graph.curation-assist.sdp.md:35
Load-bearing is a ranked list, not a threshold: the recipe reports each uncovered file's import fan-in and fan-out, takes a limit, and leaves the cut to the caller.

11 unkeyed rules.

Design
importsFlag line 39 · specs/consumers/impact-graph.curation-assist.sdp.md:39
sdp build --imports PATH names the adapter configuration, a JSON object { "adapter": "typescript", "tsconfig": "tsconfig.json", "roots": ["src"], "exclude": ["src/generated"] } with root-relative paths, where exclude is optional and each of its paths names a file or a directory subtree, and a key outside these four is refused; without the flag the build writes no imports file and leaves an existing one untouched.

no citation recorded

importsFile line 40 · specs/consumers/impact-graph.curation-assist.sdp.md:40
{ "schema": "sdp-imports/1", "adapter": "typescript", "exclude": ["src/generated"], "files": [{ "file": "src/a.ts", "imports": ["src/b.ts"] }] } in generated/imports.json, files and imports sorted in code-unit order, paths root-relative with POSIX separators, exclude recording the configuration's exclusions in that form and sorted, every file the adapter reads under the configured roots and outside the exclusions listed even when it imports nothing, and imports outside the roots or under an exclusion left out. The schema and the recipe's external inferred input label give every listed relationship the inferred claim.

no citation recorded

barrelImports line 41 · specs/consumers/impact-graph.curation-assist.sdp.md:41
when a file imports a barrel that re-exports another file, its imports lists the barrel and every file the barrel's re-exports reach, so the list is already the backing a uses check reads; a barrel under an exclusion is left out of the list while the files reached through it stay.
importForms line 42 · specs/consumers/impact-graph.curation-assist.sdp.md:42
the TypeScript adapter reads the .ts, .cts, .mts and .tsx files under the configured roots and the module references the compiler resolves in them: import and export-from declarations, type-only and side-effect imports included, import x = require(...), and import(...) calls and import types with a literal specifier; a computed specifier and a plain require(...) call are not read.
curationRecipe line 43 · specs/consumers/impact-graph.curation-assist.sdp.md:43
recipe 40, the curation report, takes params.imports, the imports file's object, and params.limit, 20 by default, and returns { input, totals, uncovered, usesWithoutImport, importsWithoutUses, unrealizedComponents, oneSided }.
curationRows line 44 · specs/consumers/impact-graph.curation-assist.sdp.md:44
uncovered rows are { file, fanIn, fanOut } for files no anchor sits in, ranked by fan-in then path and cut at limit; usesWithoutImport rows are { from, to, fromComponent, toComponent }; importsWithoutUses rows are { fromComponent, toComponent, imports, sample: { from, to } }; unrealizedComponents rows are { spec, componentId } for component designs with no resolving anchored satisfies edge from the planned component: unit to the design, so an existing id without that binding stays unrealized.

no citation recorded

curationInput line 45 · specs/consumers/impact-graph.curation-assist.sdp.md:45
input is { label: "external inferred input", schema, adapter, exclude, files }, with exclude echoing the imports file's exclusions, and oneSided lists anchored source files the imports file does not list and imports-file entries outside every anchored component, so a stale or partial file shows.

no citation recorded

Verification

Verifier bindings

  • test:protocol.curation-imports · anchored · test anchor binding present · test/curation-imports.test.ts:17

    External run evidence from test/curation-imports.test.ts

    Test anchors: test:protocol.curation-imports. Specs verified by those bindings: spec:consumers.impact-graph, spec:consumers.impact-graph.curation-assist.

    Run 1: external run evidence from vitest 4.1.10

    Build: CI 391 · Branch: cursor/media-plan-and-articles-09b1 · Commit: 076cd4f1f85640d8236e5cca1bffffa68ab79a33 · Start: 2026-10-31T15:32:20.471Z · Stop: 2026-10-31T15:34:02.073Z

    NameSuiteResultDuration
    compares Windows source paths in the form the compiler returns themTypeScript curation importspassed1.95 ms
    resolves aliases, JS specifiers, types, side effects, import equals and cyclic barrels within configured rootsTypeScript curation importspassed611.38 ms
    sorts paths by code unit, includes empty files, and deduplicates overlapping rootsTypeScript curation importspassed623.27 ms
    follows re-exports through files outside the roots but never follows ordinary transitive importsTypeScript curation importspassed250.5 ms
    reads literal dynamic imports and import types, and skips computed specifiersTypeScript curation importspassed706.19 ms
    excludes exact files and subtrees with segment boundaries and normalized metadataTypeScript curation importspassed490.89 ms
    resolves barrel reach through excluded intermediates without emitting themTypeScript curation importspassed239.24 ms
    accepts empty exclusions and normalizes root-relative exclusion spellingsTypeScript curation importspassed773.99 ms
    refuses invalid exclusion configuration {"extra":true}TypeScript curation importspassed2.41 ms
    refuses invalid exclusion configuration {"exclude":null}TypeScript curation importspassed1.45 ms
    refuses invalid exclusion configuration {"exclude":"code"}TypeScript curation importspassed1.36 ms
    refuses invalid exclusion configuration {"exclude":[1]}TypeScript curation importspassed1.27 ms
    refuses invalid exclusion configuration {"exclude":[""]}TypeScript curation importspassed1.24 ms
    refuses invalid exclusion configuration {"exclude":[" "]}TypeScript curation importspassed1.41 ms
    refuses invalid exclusion configuration {"exclude":["."]}TypeScript curation importspassed1.39 ms
    refuses invalid exclusion configuration {"exclude":["./"]}TypeScript curation importspassed1.27 ms
    refuses invalid exclusion configuration {"exclude":["../other"]}TypeScript curation importspassed3.83 ms
    refuses invalid exclusion configuration {"exclude":["code/../../other"]}TypeScript curation importspassed1.26 ms
    refuses invalid exclusion configuration {"exclude":["/code"]}TypeScript curation importspassed1.31 ms
    refuses invalid exclusion configuration {"exclude":["C:/code"]}TypeScript curation importspassed1.25 ms
    refuses invalid exclusion configuration {"exclude":["C:code"]}TypeScript curation importspassed2.18 ms
    refuses invalid exclusion configuration {"exclude":["code\\leaf.ts"]}TypeScript curation importspassed3.76 ms
    refuses invalid configuration {}TypeScript curation importspassed3.56 ms
    refuses invalid configuration {"adapter":"other","tsconfig":"tsconfig.json","roots":["code"]}TypeScript curation importspassed2.13 ms
    refuses invalid configuration {"adapter":"typescript","tsconfig":"tsconfig.json","roots":[]}TypeScript curation importspassed1.27 ms
    refuses invalid configuration {"adapter":"typescript","tsconfig":"tsconfig.json","roots":[1]}TypeScript curation importspassed1.22 ms
    refuses invalid configuration {"adapter":"typescript","tsconfig":"../tsconfig.json","roots":["code"]}TypeScript curation importspassed1.27 ms
    refuses invalid configuration {"adapter":"typescript","tsconfig":"tsconfig.json","roots":["../"]}TypeScript curation importspassed1.16 ms
    refuses invalid configuration {"adapter":"typescript","tsconfig":"tsconfig.json","roots":["/src"]}TypeScript curation importspassed3.27 ms
    refuses the source root missing by its configured pathTypeScript curation importspassed1.56 ms
    refuses the source root code/leaf.ts by its configured pathTypeScript curation importspassed1.88 ms
    builds the imports file atomically and leaves the curated graph byte-identicalTypeScript curation importspassed942.63 ms
    writes no imports file without the flag and preserves an existing file even on build failureTypeScript curation importspassed25.59 ms
    removes requested stale imports after a configuration or extraction failureTypeScript curation importspassed181.56 ms
    refuses invalid build flag argv "build"TypeScript curation importspassed0.19 ms
    refuses invalid build flag argv "build"TypeScript curation importspassed0.09 ms
    refuses invalid build flag argv "build"TypeScript curation importspassed0.05 ms
    refuses invalid build flag argv "build"TypeScript curation importspassed0.04 ms
    refuses invalid build flag argv "validate"TypeScript curation importspassed0.04 ms
    refuses invalid build flag argv "view"TypeScript curation importspassed0.03 ms
    refuses invalid build flag argv "census"TypeScript curation importspassed0.03 ms
    refuses invalid build flag argv "mermaid"TypeScript curation importspassed0.03 ms
    refuses invalid build flag argv "gherkin"TypeScript curation importspassed0.12 ms
    completes over the repository src and lists a known build-command importTypeScript curation importspassed2250.37 ms
  • test:protocol.curation-recipe · anchored · test anchor binding present · test/curation-recipes.test.ts:44

    External run evidence from test/curation-recipes.test.ts

    Test anchors: test:protocol.curation-recipe, test:protocol.slimming-recipe. Specs verified by those bindings: spec:consumers.impact-graph.curation-assist, spec:model.enrichment-lifecycle.

    Run 1: external run evidence from vitest 4.1.10

    Build: CI 391 · Branch: cursor/media-plan-and-articles-09b1 · Commit: 076cd4f1f85640d8236e5cca1bffffa68ab79a33 · Start: 2026-10-31T15:32:20.471Z · Stop: 2026-10-31T15:34:02.073Z

    NameSuiteResultDuration
    requires both facts and uses recipe 24's opening span rule, with lines and bindingsslimming candidates recipepassed8.7 ms
    selects only Pack members and returns no rows for a clean Packslimming candidates recipepassed2.5 ms
    distinguishes an unknown Pack from a clean existing Packslimming candidates recipepassed1.99 ms
    includes enabled example verifier bindings without claiming they realize an entryslimming candidates recipepassed1.59 ms
    returns diagnostics and no rows for invalid imports input undefinedcuration report recipepassed5.5 ms
    returns diagnostics and no rows for invalid imports input nullcuration report recipepassed0.96 ms
    returns diagnostics and no rows for invalid imports input []curation report recipepassed0.61 ms
    returns diagnostics and no rows for invalid imports input 'imports'curation report recipepassed0.67 ms
    returns diagnostics and no rows for invalid imports input {}curation report recipepassed0.8 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/2', …(2) }curation report recipepassed0.56 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', files: [] }curation report recipepassed0.55 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', …(2) }curation report recipepassed0.54 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', …(3) }curation report recipepassed0.6 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', …(3) }curation report recipepassed0.6 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', …(2) }curation report recipepassed0.59 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', …(2) }curation report recipepassed0.52 ms
    returns diagnostics and no rows for invalid imports input { schema: 'sdp-imports/1', …(2) }curation report recipepassed0.48 ms
    returns diagnostics and no rows for invalid limit 0curation report recipepassed0.51 ms
    returns diagnostics and no rows for invalid limit -1curation report recipepassed0.43 ms
    returns diagnostics and no rows for invalid limit 1.5curation report recipepassed0.53 ms
    returns diagnostics and no rows for invalid limit "1"curation report recipepassed0.41 ms
    returns diagnostics and no rows for invalid limit nullcuration report recipepassed0.41 ms
    returns diagnostics and no rows for invalid limit truecuration report recipepassed0.47 ms
    recognizes every lawful component-id segment and keeps invalid convention values outcuration report recipepassed0.73 ms
    echoes import exclusions without changing the supplied graph or inferring omissionscuration report recipepassed2.31 ms
    joins directed component pairs, ranks uncovered files and reports incomplete input and unrealized designscuration report recipepassed1.11 ms
    applies the limit only to uncovered rows and counts distinct file pairscuration report recipepassed0.92 ms
    aggregates file pairs for a component pair and picks the first sample in path ordercuration report recipepassed0.8 ms
    uses code-unit order for tied ranks and samples, and defaults to twenty uncovered rowscuration report recipepassed2.17 ms
    keeps several component bindings in one file and ignores inferred structural edgescuration report recipepassed1.28 ms
    builds a small fixture imports file and supplies its object to the recipe, backing uses through a barrelcuration report recipepassed520.53 ms
    reports missing or malformed parameter data {}curation report recipepassed0.62 ms
    reports missing or malformed parameter data {"imports":{}}curation report recipepassed0.36 ms
    reports missing or malformed parameter data {"imports":{"schema":"sdp-imports/1","adapter":"typescript","files":[{"file":"code/idle.ts","imports":[]},{"file":"code/a.ts","imports":["code/index.ts","code/leaf.ts"]},{"file":"code/index.ts","imports":["code/leaf.ts"]},{"file":"code/leaf.ts","imports":["code/a.ts"]},{"file":"code/loose.ts","imports":[]}]},"limit":-1}curation report recipepassed0.32 ms
    reports missing or malformed parameter data {"imports":{"schema":"sdp-imports/1","adapter":"typescript","files":[{"file":"code/idle.ts","imports":[]},{"file":"code/a.ts","imports":["code/index.ts","code/leaf.ts"]},{"file":"code/index.ts","imports":["code/leaf.ts"]},{"file":"code/leaf.ts","imports":["code/a.ts"]},{"file":"code/loose.ts","imports":[]}]},"limit":1.5}curation report recipepassed0.28 ms
Design view

Requirement drawing

  • Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.impact-graph.curation-assist
The diagram as text
  • spec:consumers.impact-graph.curation-assist: File-level imports show where curation is missing · declared Spec
  • spec:consumers.impact-graph: Mechanical code structure stays inferred and apart from curated intent · declared Spec
  • impl:protocol.build-imports: opt-in imports publication in the build command · anchored code · src/cli/build-command.ts:243
  • impl:protocol.curation-recipe: asserts the curation report over external inferred imports · anchored code · test/curation-recipes.test.ts:32
  • impl:protocol.typescript-imports: TypeScript file imports and barrel reach for external curation input · anchored code · src/adapters/typescript-imports.ts:7
  • test:protocol.curation-imports: test:protocol.curation-imports · anchored test binding · binding present · test/curation-imports.test.ts:17
  • test:protocol.curation-recipe: test:protocol.curation-recipe · anchored test binding · binding present · test/curation-recipes.test.ts:44
  • spec:consumers.impact-graph.curation-assist refines spec:consumers.impact-graph · declared
  • impl:protocol.build-imports satisfies spec:consumers.impact-graph.curation-assist · anchored
  • impl:protocol.curation-recipe satisfies spec:consumers.impact-graph.curation-assist · anchored
  • impl:protocol.typescript-imports satisfies spec:consumers.impact-graph.curation-assist · anchored
  • test:protocol.curation-imports verifies spec:consumers.impact-graph.curation-assist · anchored
  • test:protocol.curation-recipe verifies spec:consumers.impact-graph.curation-assist · anchored
Mermaid source

Copyable source; the Studio draws static SVG.

Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.

Decisions

  • Architectural significance is annotated where it is realized

    Architectural significance is annotated on the anchor of the unit that realizes it. A code anchor may carry role, the architectural pattern the unit plays; a component: anchor may additionally carry layer, one of edge, application, domain, adapter, or infrastructure, and context, its bounded context. The component: anchor is anchored architecture: it is the declared component, and there is no separate architecture file, because the anchor sits where the component is realized. It is not the original design's declared Component that could exist before code; an unrealized component lives in Specs and never as an invented CodeNode. A role is a free, corpus-owned vocabulary whose taxonomy the census renders with counts from the graph; service, decider, projection, read-model, codec, contract, barrel, and utility are the lineage set, not a closed list. layer is a closed set, and a value outside it is an envelope error; layer or context on a non-component anchor is an envelope error. All three attributes are optional, and omission is lawful.

Runtime
  • component:protocol.adapters · external runtime and source adapters · src/adapters/vitest.ts:23 · layer adapter · context protocol

    Uses

    • component:protocol.runner · provider-neutral example execution · src/runner/index.ts:99 · layer application · context protocol
  • component:protocol.cli · entry points, shared build and publication · src/cli/build-command.ts:32 · layer edge · context protocol

    Uses

    • component:protocol.adapters · external runtime and source adapters · src/adapters/vitest.ts:23 · layer adapter · context protocol
    • component:protocol.codegen · contracts and registrar output · src/codegen/contracts.ts:633 · layer application · context protocol
    • component:protocol.extract · the carrier and source pipeline · src/extract/index.ts:192 · layer application · context protocol
    • component:protocol.graph · the one graph and its semantic decisions · src/graph/schema.ts:34 · layer domain · context protocol
    • component:protocol.import · canonical conversion with a fidelity boundary · src/import/import.ts:45 · layer application · context protocol
    • component:protocol.model · the authored contracts and stable ids · src/model/anchors.ts:100 · layer domain · context protocol
    • component:protocol.projections · read-only output, layout and owned publication · src/projections/design-review.ts:29 · layer edge · context protocol
    • component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
    • component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
  • impl:protocol.build-imports · opt-in imports publication in the build command · src/cli/build-command.ts:243

    Component: component:protocol.cli · entry points, shared build and publication · src/cli/build-command.ts:32 · layer edge · context protocol

    Uses

    None.

  • impl:protocol.curation-recipe · asserts the curation report over external inferred imports · test/curation-recipes.test.ts:32

    Uses

    None.

  • impl:protocol.typescript-imports · TypeScript file imports and barrel reach for external curation input · src/adapters/typescript-imports.ts:7

    Component: component:protocol.adapters · external runtime and source adapters · src/adapters/vitest.ts:23 · layer adapter · context protocol

    Uses

    None.

Runtime observation: not tracked.

Evidence

Runtime observation: not tracked.

Build attestations: not tracked.

Deployments: not tracked.

Bills of materials: not tracked.

Impact
Relations of spec:consumers.impact-graph.curation-assist
The diagram as text
  • spec:consumers.impact-graph: Mechanical code structure stays inferred and apart from curated intent
  • spec:consumers.impact-graph.curation-assist: File-level imports show where curation is missing
  • spec:decisions.architectural-annotation: Architectural significance is annotated where it is realized
  • spec:model.planned-architecture: Components are designed ahead of their code
  • spec:consumers.impact-graph.curation-assist decidedBy spec:decisions.architectural-annotation · declared
  • spec:consumers.impact-graph.curation-assist dependsOn spec:model.planned-architecture · declared — the report uses the component-design convention to identify unrealized planned components
  • spec:consumers.impact-graph.curation-assist refines spec:consumers.impact-graph · declared
Mermaid source

Copyable source; the Studio draws static SVG.

Preferred syntax: flowchart. Chosen syntax: labelled flowchart, preserving exact relations, claims and folds.

Rests on

Rested on by

No Spec rests on this Spec.

Relations

Relation and directionOther endClaimReasonExercised keys
decidedBy · outgoingArchitectural significance is annotated where it is realized
spec:decisions.architectural-annotation · resolves
declaredNoneNone
dependsOn · outgoingComponents are designed ahead of their code
spec:model.planned-architecture · resolves
declaredthe report uses the component-design convention to identify unrealized planned componentsNone
refines · outgoingMechanical code structure stays inferred and apart from curated intent
spec:consumers.impact-graph · resolves
declaredNoneNone

Bindings

Implementation binding: present

  • impl:protocol.build-imports · opt-in imports publication in the build command · src/cli/build-command.ts:243 · role publisher · component component:protocol.cli · layer edge · context protocol
  • impl:protocol.curation-recipe · asserts the curation report over external inferred imports · test/curation-recipes.test.ts:32
  • impl:protocol.typescript-imports · TypeScript file imports and barrel reach for external curation input · src/adapters/typescript-imports.ts:7 · role adapter · component component:protocol.adapters · layer adapter · context protocol

Design reference: none

Verifier binding: present

  • test:protocol.curation-imports · anchored · test/curation-imports.test.ts:17 · test anchor
  • test:protocol.curation-recipe · anchored · test/curation-recipes.test.ts:44 · test anchor

Expected-outcome oracle: none

Runtime observation: not tracked.

Run results: not recorded in the graph.

Findings

None.

Composing (0)

Composing needs the script.