@typedstandards/civic-typed-harness 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,57 @@
3
3
  Factual record of what changed per published version. Section references are
4
4
  to the Typed Standards specification unless noted otherwise.
5
5
 
6
+ ## 0.2.0 — 2026-08-17
7
+
8
+ **Breaking: identity-bearing config is now required**
9
+ ([civic-ai-tools#153](https://github.com/npstorey/civic-ai-tools/issues/153) —
10
+ the [ADR-0024](../../docs/adr/0024-evidence-path-configuration.md) posture at
11
+ the domain layer: configuration that reaches signed output is absent-or-error,
12
+ never defaulted). 0.1.0 applied the civicaitools.org reference deployment's
13
+ identity via silently-applied default parameters; 0.2.0 removes every such
14
+ default, so a bare call fails typecheck instead of attributing output to the
15
+ reference deployment.
16
+
17
+ - **Breaking — the config parameter is required in five API families:**
18
+ - `buildProvenanceGraph(trace, input, config)` — `ProvenanceConfig`
19
+ required (was defaulted to `CIVICAITOOLS_PROVENANCE_CONFIG`).
20
+ - `buildDatHereEnvironment(model, skillMcpServerUrl, config)` and
21
+ `deriveDatHereEnvelopeFields(input, config)` —
22
+ `DatHereEnvironmentConfig` required (was defaulted to
23
+ `CIVICAITOOLS_ENVIRONMENT_CONFIG`; the `host` field lands under the
24
+ envelope hash, so this default was the sharpest instance).
25
+ - `new TraceBuilder(config)` — `TraceBuilderConfig` required (was
26
+ defaulted to `CIVICAITOOLS_TRACE_CONFIG`). The intra-config
27
+ `now`/`randomBytes` operational fallbacks are unchanged — they are not
28
+ identity.
29
+ - `isDatasetKeyedSource(sourceId, registry)`,
30
+ `displayNameForSource(sourceId, registry)`,
31
+ `formatDataSourcesSummary(entries, registry)` — `CivicSourceRegistry`
32
+ required in all three (was defaulted to `CIVIC_SOURCE_REGISTRY`).
33
+ - **Breaking — the model-agent description is omitted when unset.** The
34
+ module-private fallback description is deleted.
35
+ `ProvenanceConfig.modelAgentDescription` stays optional, but when unset the
36
+ PROV model agent now carries **no** `dcterms:description` field at all
37
+ (honest absence, not an empty string — ADR-0024 §B) instead of the fallback
38
+ text. `CIVICAITOOLS_PROVENANCE_CONFIG` now carries
39
+ `modelAgentDescription: 'Large language model via OpenRouter'`, so
40
+ reference-config output is byte-identical to 0.1.0.
41
+ - **The reference-value exports remain.** `CIVICAITOOLS_PROVENANCE_CONFIG`,
42
+ `CIVICAITOOLS_ENVIRONMENT_CONFIG`, `CIVICAITOOLS_TRACE_CONFIG`, and
43
+ `CIVIC_SOURCE_REGISTRY` are still exported — they are the reference
44
+ deployment's values, which the reference app passes explicitly; they are no
45
+ longer applied on any caller's behalf.
46
+ - **Migration:** pass the exported reference configs to reproduce 0.1.x
47
+ behavior byte-for-byte (see README §"Migrating from 0.1.x"). Golden
48
+ fixtures are unchanged; byte parity now comes from tests passing the
49
+ reference config explicitly, never from restored defaults.
50
+ - **Enforcement:** `src/required-config.assert.ts` encodes the acceptance
51
+ condition — one `@ts-expect-error` bare call per changed signature —
52
+ so reintroducing a default parameter fails `npm run typecheck` and
53
+ `npm run build`.
54
+ - Dependencies unchanged (`@typedstandards/produce-core` `^0.2.0` remains the
55
+ single runtime dependency).
56
+
6
57
  ## 0.1.0 — 2026-08-02
7
58
 
8
59
  Initial release: the civic **domain harness** for Typed Standards evidence
package/README.md CHANGED
@@ -14,18 +14,36 @@ The civic **domain harness** for [Typed Standards](../../docs/architecture/typed
14
14
 
15
15
  **The internal boundary is load-bearing:** no capture module defines vocabulary, and no format-extension module walks a trace — this sentence reserves a future split of the format-extension group into its own package (a civic extension *of Typed Standards*, distinct from the civic *harness* proper) as a mechanical move rather than a re-partition. The boundary is enforced by `src/purity.test.ts`.
16
16
 
17
- ## Config, not constants
17
+ ## Config, not constants — and required, never defaulted
18
18
 
19
- Every value that names a deployment is a **typed config input**, with the civicaitools.org demo values exported as overridable defaults:
19
+ Every value that names a deployment is a **required typed config input**. As of 0.2.0 the harness never applies a deployment identity on a caller's behalf: a call that omits the config **fails typecheck** ([ADR-0024](../../docs/adr/0024-evidence-path-configuration.md)'s posture at the domain layer — configuration that reaches signed output is absent-or-error, never defaulted; the removal of the 0.1.x defaults is [civic-ai-tools#153](https://github.com/npstorey/civic-ai-tools/issues/153)). The `CIVICAITOOLS_*` exports are the civicaitools.org **reference deployment's values** — the reference app passes them explicitly; any other instance supplies its own.
20
20
 
21
- | Value | Config type | Demo default export |
21
+ | Identity-bearing input | Config type | Reference-value export |
22
22
  |---|---|---|
23
- | Platform-agent identity/URL | `PlatformAgentConfig` | `CIVICAITOOLS_PLATFORM_AGENT` |
23
+ | Platform-agent identity/URL | `PlatformAgentConfig` (`ProvenanceConfig.platformAgent`) | `CIVICAITOOLS_PLATFORM_AGENT` |
24
24
  | MCP source registry (server URLs, catalog types, display names) | `CivicSourceRegistry` | `CIVIC_SOURCE_REGISTRY` |
25
- | Tool-name → source-id resolver | `ToolSourceResolver` | `civicToolSourceResolver` |
26
- | Environment-extension `host` | `DatHereEnvironmentConfig` | `CIVICAITOOLS_ENVIRONMENT_CONFIG` |
25
+ | Tool-name → source-id resolver (a caller-supplied input, not a silent default) | `ToolSourceResolver` | `civicToolSourceResolver` |
26
+ | Environment-extension `host` (lands under the envelope hash) | `DatHereEnvironmentConfig` | `CIVICAITOOLS_ENVIRONMENT_CONFIG` |
27
27
  | Trace `service.name` / scope identity | `TraceBuilderConfig` | `CIVICAITOOLS_TRACE_CONFIG` |
28
- | Provenance build (all of the above + model-agent description) | `ProvenanceConfig` | `CIVICAITOOLS_PROVENANCE_CONFIG` |
28
+ | Model-agent `dcterms:description` | `ProvenanceConfig.modelAgentDescription` (optional field) | carried in `CIVICAITOOLS_PROVENANCE_CONFIG` |
29
+ | Provenance build (platform agent + source registry + model-agent description) | `ProvenanceConfig` | `CIVICAITOOLS_PROVENANCE_CONFIG` |
30
+
31
+ `modelAgentDescription` is the one **optional** field among these: when unset, the PROV model agent carries no `dcterms:description` at all — the field is omitted from the graph (honest absence), never filled with a fallback. The `now`/`randomBytes` fields on `TraceBuilderConfig` are operational fallbacks (runtime clock/CSPRNG), not identity, and keep their intra-config defaults.
32
+
33
+ ### Migrating from 0.1.x
34
+
35
+ 0.1.x applied the reference deployment's identity via silent default parameters; 0.2.0 removes every such default — the breaking change is the point: a bare call that would have embedded civicaitools.org's identity in the output now fails to compile. To reproduce 0.1.x behavior byte-for-byte, pass the exported reference configs explicitly:
36
+
37
+ ```ts
38
+ // 0.1.x — compiled, and silently attributed output to the reference deployment:
39
+ const graph = buildProvenanceGraph(trace, input);
40
+
41
+ // 0.2.0 — the same output, byte-identical, with the identity stated:
42
+ import { CIVICAITOOLS_PROVENANCE_CONFIG } from '@typedstandards/civic-typed-harness';
43
+ const graph = buildProvenanceGraph(trace, input, CIVICAITOOLS_PROVENANCE_CONFIG);
44
+ ```
45
+
46
+ Likewise: `buildDatHereEnvironment` / `deriveDatHereEnvelopeFields` take `CIVICAITOOLS_ENVIRONMENT_CONFIG`, `new TraceBuilder(...)` takes `CIVICAITOOLS_TRACE_CONFIG`, and `isDatasetKeyedSource` / `displayNameForSource` / `formatDataSourcesSummary` take `CIVIC_SOURCE_REGISTRY`. The acceptance condition is encoded in `src/required-config.assert.ts`: reintroducing any of the removed defaults fails `npm run typecheck`.
29
47
 
30
48
  ## Purity contract (harness-grade)
31
49
 
@@ -37,7 +55,7 @@ Runtime dependency: **`@typedstandards/produce-core` (`^0.2.0`) only.** The veri
37
55
 
38
56
  ## Byte-compatibility
39
57
 
40
- The port is tested for **byte parity** against golden outputs captured from the reference implementation (`src/__fixtures__/website-golden.json`): with the demo default config, `buildProvenanceGraph` and `buildDataSources` reproduce the app's output byte-for-byte, and `RUBRIC_VERSION_SHA256` is asserted against the exact reference digest (moving the rubric changes no hashes). Fixture-level byte-compat against produce-core's `reference-golden.json` (`src/golden-reproduction.test.ts`) and the produce→verify composition round-trip (`src/composition-roundtrip.test.ts`) landed in S2 P2 and run with the suite.
58
+ The port is tested for **byte parity** against golden outputs captured from the reference implementation (`src/__fixtures__/website-golden.json`): with the reference config passed explicitly, `buildProvenanceGraph` and `buildDataSources` reproduce the app's output byte-for-byte, and `RUBRIC_VERSION_SHA256` is asserted against the exact reference digest (moving the rubric changes no hashes). Fixture-level byte-compat against produce-core's `reference-golden.json` (`src/golden-reproduction.test.ts`) and the produce→verify composition round-trip (`src/composition-roundtrip.test.ts`) landed in S2 P2 and run with the suite.
41
59
 
42
60
  ## Develop
43
61
 
@@ -30,11 +30,13 @@ export interface ProvenanceConfig {
30
30
  * overrides when present (the skill is fetched from that source's MCP
31
31
  * server). Default `socrata`. */
32
32
  skillSourceId?: string;
33
- /** `dcterms:description` of the model agent. Default names the demo
34
- * deployment's model gateway. */
33
+ /** `dcterms:description` of the model agent. When unset, the model agent
34
+ * carries no `dcterms:description` at all — the field is omitted from the
35
+ * graph (honest omission), never filled with a fallback. */
35
36
  modelAgentDescription?: string;
36
37
  }
37
- /** Demo default: the civicaitools.org reference deployment. */
38
+ /** The civicaitools.org reference deployment's values. Passed explicitly by
39
+ * the reference app — never applied as a default. */
38
40
  export declare const CIVICAITOOLS_PROVENANCE_CONFIG: ProvenanceConfig;
39
41
  /**
40
42
  * Build a W3C PROV-O JSON-LD graph from an OTel trace and package metadata.
@@ -45,4 +47,4 @@ export declare const CIVICAITOOLS_PROVENANCE_CONFIG: ProvenanceConfig;
45
47
  * - Prompt, skill guidance, data responses, output → prov:Entity
46
48
  * - LLM model, MCP server, platform → prov:Agent
47
49
  */
48
- export declare function buildProvenanceGraph(trace: Record<string, unknown>, input: ProvenanceInput, config?: ProvenanceConfig): ProvGraph;
50
+ export declare function buildProvenanceGraph(trace: Record<string, unknown>, input: ProvenanceInput, config: ProvenanceConfig): ProvGraph;
@@ -9,20 +9,23 @@
9
9
  //
10
10
  // Config-not-constants: the platform-agent identity, the source-agent
11
11
  // registry (server URLs), and the model-agent description are typed config
12
- // inputs; `CIVICAITOOLS_PROVENANCE_CONFIG` is the demo default and
13
- // reproduces the reference implementation's output byte-for-byte (property
14
- // insertion order is preserved throughout — the legacy hash chain's byte
15
- // contract).
12
+ // inputs, and the config is REQUIRED — no deployment identity is ever
13
+ // applied silently (ADR-0024 posture at the domain layer).
14
+ // `CIVICAITOOLS_PROVENANCE_CONFIG` is the reference deployment's values,
15
+ // which the reference app passes explicitly; with it, the builder reproduces
16
+ // the reference implementation's output byte-for-byte (property insertion
17
+ // order is preserved throughout — the legacy hash chain's byte contract).
16
18
  import { makeProvGraph, makeEntityNode, makeActivityNode, makeAgentNode, provRef, provUsed, provWasGeneratedBy, provWasDerivedFrom, provWasAssociatedWith, xsdDateTime, } from '@typedstandards/produce-core';
17
19
  import { hash } from "./trace.js";
18
20
  import { makeCivicProvContext, civicUrn, civicModelUrn, civicSourceAgentUrn, civicPlatformUrn, CIVICAITOOLS_PLATFORM_AGENT, } from "../format/vocabulary.js";
19
21
  import { CIVIC_SOURCE_REGISTRY, FALLBACK_SOURCE_ID, isDatasetKeyedSource, } from "../format/sources.js";
20
- /** Demo default: the civicaitools.org reference deployment. */
22
+ /** The civicaitools.org reference deployment's values. Passed explicitly by
23
+ * the reference app — never applied as a default. */
21
24
  export const CIVICAITOOLS_PROVENANCE_CONFIG = {
22
25
  platformAgent: CIVICAITOOLS_PLATFORM_AGENT,
23
26
  sourceRegistry: CIVIC_SOURCE_REGISTRY,
27
+ modelAgentDescription: 'Large language model via OpenRouter',
24
28
  };
25
- const DEFAULT_MODEL_AGENT_DESCRIPTION = 'Large language model via OpenRouter';
26
29
  // --- Helpers ---
27
30
  function getAttr(attrs, key) {
28
31
  const attr = attrs.find(a => a.key === key);
@@ -42,7 +45,7 @@ function nanoToIso(nano) {
42
45
  * - Prompt, skill guidance, data responses, output → prov:Entity
43
46
  * - LLM model, MCP server, platform → prov:Agent
44
47
  */
45
- export function buildProvenanceGraph(trace, input, config = CIVICAITOOLS_PROVENANCE_CONFIG) {
48
+ export function buildProvenanceGraph(trace, input, config) {
46
49
  const otel = trace;
47
50
  const spans = otel?.resourceSpans?.[0]?.scopeSpans?.[0]?.spans || [];
48
51
  const { packageId, promptHash, promptText, outputText, model, portal } = input;
@@ -50,7 +53,6 @@ export function buildProvenanceGraph(trace, input, config = CIVICAITOOLS_PROVENA
50
53
  const registry = config.sourceRegistry;
51
54
  const fallbackSourceId = config.fallbackSourceId ?? FALLBACK_SOURCE_ID;
52
55
  const skillSourceId = config.skillSourceId ?? FALLBACK_SOURCE_ID;
53
- const modelDescription = config.modelAgentDescription ?? DEFAULT_MODEL_AGENT_DESCRIPTION;
54
56
  const graph = [];
55
57
  // --- Entities ---
56
58
  // User prompt
@@ -78,11 +80,15 @@ export function buildProvenanceGraph(trace, input, config = CIVICAITOOLS_PROVENA
78
80
  'dcterms:description': 'AI-generated analysis output',
79
81
  }));
80
82
  // --- Agents ---
81
- // LLM model
83
+ // LLM model. The description is emitted only when the config supplies one —
84
+ // absent otherwise (honest omission, same idiom as deriveProducerProfile /
85
+ // deriveSummaryEmission in ../format/dathere.ts).
82
86
  const modelUrn = civicModelUrn(model);
83
87
  graph.push(makeAgentNode(modelUrn, {
84
88
  'dcterms:title': model,
85
- 'dcterms:description': modelDescription,
89
+ ...(config.modelAgentDescription
90
+ ? { 'dcterms:description': config.modelAgentDescription }
91
+ : {}),
86
92
  }, ['prov:SoftwareAgent']));
87
93
  // MCP server agents — one per distinct data source that appears in the
88
94
  // trace. Tool spans carry `mcp.source`; evidence records captured before
@@ -50,7 +50,9 @@ export type TraceRandomBytes = (byteLength: number) => Uint8Array;
50
50
  /**
51
51
  * TraceBuilder identity + determinism inputs. The identity strings name the
52
52
  * capturing service, so they are per-instance config (config-not-constants);
53
- * the demo values are `CIVICAITOOLS_TRACE_CONFIG` below.
53
+ * the reference deployment's values are `CIVICAITOOLS_TRACE_CONFIG` below.
54
+ * The identity fields are required; `now`/`randomBytes` are operational
55
+ * fallbacks, not identity, and default to the runtime's clock and CSPRNG.
54
56
  */
55
57
  export interface TraceBuilderConfig {
56
58
  /** OTel resource `service.name`. */
@@ -67,8 +69,8 @@ export interface TraceBuilderConfig {
67
69
  * `crypto.getRandomValues` (Web Crypto — Node 18+ and every browser). */
68
70
  randomBytes?: TraceRandomBytes;
69
71
  }
70
- /** Demo default: the civicaitools.org reference deployment's capture
71
- * identity. */
72
+ /** The civicaitools.org reference deployment's capture identity. Passed
73
+ * explicitly by the reference app — never applied as a default. */
72
74
  export declare const CIVICAITOOLS_TRACE_CONFIG: TraceBuilderConfig;
73
75
  export declare class TraceBuilder {
74
76
  readonly traceId: string;
@@ -77,7 +79,7 @@ export declare class TraceBuilder {
77
79
  private readonly config;
78
80
  private readonly now;
79
81
  private readonly randomBytes;
80
- constructor(config?: TraceBuilderConfig);
82
+ constructor(config: TraceBuilderConfig);
81
83
  private randomHex;
82
84
  private nowNano;
83
85
  /**
@@ -5,8 +5,10 @@
5
5
  // implements and @typedstandards/produce-core re-exports (0.2.0), removing
6
6
  // the module's only `node:crypto` use — the harness is browser-safe.
7
7
  // - The resource/scope identity constants (`service.name`, scope
8
- // name/version, semconv version) are typed config inputs with the demo
9
- // values as the exported default (config-not-constants, S2 brief §2).
8
+ // name/version, semconv version) are REQUIRED typed config inputs
9
+ // (config-not-constants, S2 brief §2); the reference deployment's values
10
+ // are exported as `CIVICAITOOLS_TRACE_CONFIG` for explicit use, never
11
+ // applied as a default.
10
12
  //
11
13
  // Clock + RNG are INHERENT to capture (span timestamps and ids are what
12
14
  // capture *is*): this module is the sanctioned exception to the package's
@@ -32,8 +34,8 @@ function attrsFromRecord(attrs) {
32
34
  export function hash(content) {
33
35
  return sha256Hex(content);
34
36
  }
35
- /** Demo default: the civicaitools.org reference deployment's capture
36
- * identity. */
37
+ /** The civicaitools.org reference deployment's capture identity. Passed
38
+ * explicitly by the reference app — never applied as a default. */
37
39
  export const CIVICAITOOLS_TRACE_CONFIG = {
38
40
  serviceName: 'civic-ai-tools-website',
39
41
  scopeName: 'civic-ai-tools-evidence',
@@ -53,7 +55,7 @@ export class TraceBuilder {
53
55
  config;
54
56
  now;
55
57
  randomBytes;
56
- constructor(config = CIVICAITOOLS_TRACE_CONFIG) {
58
+ constructor(config) {
57
59
  this.config = config;
58
60
  this.now = config.now ?? Date.now;
59
61
  this.randomBytes = config.randomBytes ?? defaultRandomBytes;
@@ -5,16 +5,18 @@ export declare const DATHERE_CONTENT_PROFILE = "datHere";
5
5
  export declare const DATHERE_PRODUCER_PROFILE = "ai-assisted-analysis/datHere";
6
6
  /** Reverse-DNS key of the auto-emitted environment extension. */
7
7
  export declare const ENVIRONMENT_EXTENSION_KEY = "org.civicaitools.environment";
8
- /** Demo default for the environment extension's `host` field: the
9
- * civicaitools.org reference deployment. Config-not-constants — every other
10
- * instance supplies its own via `DatHereEnvironmentConfig`. */
8
+ /** The civicaitools.org reference deployment's value for the environment
9
+ * extension's `host` field. Config-not-constants — every instance supplies
10
+ * its own via `DatHereEnvironmentConfig`; the `host` lands under the
11
+ * envelope hash, so it is never applied silently. */
11
12
  export declare const CIVICAITOOLS_ENVIRONMENT_HOST = "civicaitools.org";
12
13
  /** Per-instance configuration for the environment extension. */
13
14
  export interface DatHereEnvironmentConfig {
14
15
  /** Publishing host recorded in `org.civicaitools.environment.host`. */
15
16
  host: string;
16
17
  }
17
- /** The civicaitools.org demo default. */
18
+ /** The civicaitools.org reference deployment's values. Passed explicitly by
19
+ * the reference app — never applied as a default. */
18
20
  export declare const CIVICAITOOLS_ENVIRONMENT_CONFIG: DatHereEnvironmentConfig;
19
21
  /**
20
22
  * Derive the envelope's `producerProfile` (ADR-0006): the explicit value when
@@ -48,7 +50,7 @@ export declare function deriveSummaryEmission(contentProfile?: string, summary?:
48
50
  * skill-fetch span URL (the analysis's primary MCP server). Fields captured
49
51
  * honestly: `modelVersion` and `host`.
50
52
  */
51
- export declare function buildDatHereEnvironment(model: string, skillMcpServerUrl: string | undefined, config?: DatHereEnvironmentConfig): Record<string, unknown>;
53
+ export declare function buildDatHereEnvironment(model: string, skillMcpServerUrl: string | undefined, config: DatHereEnvironmentConfig): Record<string, unknown>;
52
54
  /** Input to the composite datHere-policy derivation. */
53
55
  export interface DatHerePolicyInput {
54
56
  /** Model identifier (becomes `environment.modelVersion`). */
@@ -80,4 +82,4 @@ export interface DatHereEnvelopeFields {
80
82
  * the legacy canonicalization rule and any caller-supplied extensions —
81
83
  * byte-identical envelopes via the core's conditional spreads.
82
84
  */
83
- export declare function deriveDatHereEnvelopeFields(input: DatHerePolicyInput, config?: DatHereEnvironmentConfig): DatHereEnvelopeFields;
85
+ export declare function deriveDatHereEnvelopeFields(input: DatHerePolicyInput, config: DatHereEnvironmentConfig): DatHereEnvelopeFields;
@@ -25,11 +25,13 @@ export const DATHERE_CONTENT_PROFILE = 'datHere';
25
25
  export const DATHERE_PRODUCER_PROFILE = 'ai-assisted-analysis/datHere';
26
26
  /** Reverse-DNS key of the auto-emitted environment extension. */
27
27
  export const ENVIRONMENT_EXTENSION_KEY = 'org.civicaitools.environment';
28
- /** Demo default for the environment extension's `host` field: the
29
- * civicaitools.org reference deployment. Config-not-constants — every other
30
- * instance supplies its own via `DatHereEnvironmentConfig`. */
28
+ /** The civicaitools.org reference deployment's value for the environment
29
+ * extension's `host` field. Config-not-constants — every instance supplies
30
+ * its own via `DatHereEnvironmentConfig`; the `host` lands under the
31
+ * envelope hash, so it is never applied silently. */
31
32
  export const CIVICAITOOLS_ENVIRONMENT_HOST = 'civicaitools.org';
32
- /** The civicaitools.org demo default. */
33
+ /** The civicaitools.org reference deployment's values. Passed explicitly by
34
+ * the reference app — never applied as a default. */
33
35
  export const CIVICAITOOLS_ENVIRONMENT_CONFIG = {
34
36
  host: CIVICAITOOLS_ENVIRONMENT_HOST,
35
37
  };
@@ -78,7 +80,7 @@ export function deriveSummaryEmission(contentProfile, summary) {
78
80
  * skill-fetch span URL (the analysis's primary MCP server). Fields captured
79
81
  * honestly: `modelVersion` and `host`.
80
82
  */
81
- export function buildDatHereEnvironment(model, skillMcpServerUrl, config = CIVICAITOOLS_ENVIRONMENT_CONFIG) {
83
+ export function buildDatHereEnvironment(model, skillMcpServerUrl, config) {
82
84
  const mcpServers = [];
83
85
  if (skillMcpServerUrl) {
84
86
  mcpServers.push({ url: skillMcpServerUrl });
@@ -97,7 +99,7 @@ export function buildDatHereEnvironment(model, skillMcpServerUrl, config = CIVIC
97
99
  * the legacy canonicalization rule and any caller-supplied extensions —
98
100
  * byte-identical envelopes via the core's conditional spreads.
99
101
  */
100
- export function deriveDatHereEnvelopeFields(input, config = CIVICAITOOLS_ENVIRONMENT_CONFIG) {
102
+ export function deriveDatHereEnvelopeFields(input, config) {
101
103
  const extensions = { ...(input.extensions ?? {}) };
102
104
  if (input.contentProfile === DATHERE_CONTENT_PROFILE) {
103
105
  extensions[ENVIRONMENT_EXTENSION_KEY] = buildDatHereEnvironment(input.model, input.skillMcpServerUrl, config);
@@ -21,14 +21,15 @@ export interface CivicSourceInfo {
21
21
  /** A source registry: source id → coordinates. Insertion order is emission
22
22
  * order for aggregate `dataSources` entries. */
23
23
  export type CivicSourceRegistry = Record<string, CivicSourceInfo>;
24
- /** The civic default registry — the three demo sources. */
24
+ /** The civic reference registry — the three demo sources. Passed explicitly
25
+ * by the reference app — never applied as a default. */
25
26
  export declare const CIVIC_SOURCE_REGISTRY: CivicSourceRegistry;
26
27
  /** The source id untagged/pre-M9.1 captures fall back to. Socrata was the
27
28
  * only source when those packages were written. */
28
29
  export declare const FALLBACK_SOURCE_ID = "socrata";
29
30
  /** Is this source dataset-keyed (one `dataSources` entry per dataset) rather
30
31
  * than aggregate? Unknown ids are neither — they contribute no entry. */
31
- export declare function isDatasetKeyedSource(sourceId: string, registry?: CivicSourceRegistry): boolean;
32
+ export declare function isDatasetKeyedSource(sourceId: string, registry: CivicSourceRegistry): boolean;
32
33
  /**
33
34
  * Resolve an MCP tool name to a source id, or `undefined` when unknown.
34
35
  * The data-source population function (capture group) takes one of these as
@@ -47,8 +48,8 @@ export declare const civicToolSourceResolver: ToolSourceResolver;
47
48
  * capitalised form of the raw id so new sources render sensibly before the
48
49
  * registry is updated. Missing ids coerce to the fallback source (pre-M9.3
49
50
  * packages have no `sourceId` on dataSources entries). */
50
- export declare function displayNameForSource(sourceId: string | undefined | null, registry?: CivicSourceRegistry): string;
51
+ export declare function displayNameForSource(sourceId: string | undefined | null, registry: CivicSourceRegistry): string;
51
52
  /** Format a `dataSources` array as a compact, de-duplicated summary string
52
53
  * (middle-dot separated). Returns `null` when the array is empty or missing,
53
54
  * letting callers render a fallback. */
54
- export declare function formatDataSourcesSummary(entries: DataSourceEntry[] | undefined, registry?: CivicSourceRegistry): string | null;
55
+ export declare function formatDataSourcesSummary(entries: DataSourceEntry[] | undefined, registry: CivicSourceRegistry): string | null;
@@ -8,10 +8,12 @@
8
8
  // app's MCP registry itself stays app-side; this is the harness's civic
9
9
  // DEFAULT — callers supply their own resolver to add or replace sources).
10
10
  //
11
- // Endpoint URLs name the demo deployment's data plane, so the registry is a
12
- // typed config input (config-not-constants, S2 brief §2) with the civic
13
- // values as the exported default map.
14
- /** The civic default registry — the three demo sources. */
11
+ // Endpoint URLs name a deployment's data plane, so the registry is a
12
+ // REQUIRED typed config input (config-not-constants, S2 brief §2); the civic
13
+ // demo map is exported as `CIVIC_SOURCE_REGISTRY` for explicit use, never
14
+ // applied as a default.
15
+ /** The civic reference registry — the three demo sources. Passed explicitly
16
+ * by the reference app — never applied as a default. */
15
17
  export const CIVIC_SOURCE_REGISTRY = {
16
18
  socrata: {
17
19
  displayName: 'Socrata',
@@ -39,7 +41,7 @@ export const CIVIC_SOURCE_REGISTRY = {
39
41
  export const FALLBACK_SOURCE_ID = 'socrata';
40
42
  /** Is this source dataset-keyed (one `dataSources` entry per dataset) rather
41
43
  * than aggregate? Unknown ids are neither — they contribute no entry. */
42
- export function isDatasetKeyedSource(sourceId, registry = CIVIC_SOURCE_REGISTRY) {
44
+ export function isDatasetKeyedSource(sourceId, registry) {
43
45
  const info = registry[sourceId];
44
46
  return info !== undefined && info.aggregatePortalUrl === undefined;
45
47
  }
@@ -65,7 +67,7 @@ export const civicToolSourceResolver = (toolName) => CIVIC_TOOL_SOURCE_MAP[toolN
65
67
  * capitalised form of the raw id so new sources render sensibly before the
66
68
  * registry is updated. Missing ids coerce to the fallback source (pre-M9.3
67
69
  * packages have no `sourceId` on dataSources entries). */
68
- export function displayNameForSource(sourceId, registry = CIVIC_SOURCE_REGISTRY) {
70
+ export function displayNameForSource(sourceId, registry) {
69
71
  const id = sourceId || FALLBACK_SOURCE_ID;
70
72
  return (registry[id]?.displayName
71
73
  ?? id
@@ -77,7 +79,7 @@ export function displayNameForSource(sourceId, registry = CIVIC_SOURCE_REGISTRY)
77
79
  /** Format a `dataSources` array as a compact, de-duplicated summary string
78
80
  * (middle-dot separated). Returns `null` when the array is empty or missing,
79
81
  * letting callers render a fallback. */
80
- export function formatDataSourcesSummary(entries, registry = CIVIC_SOURCE_REGISTRY) {
82
+ export function formatDataSourcesSummary(entries, registry) {
81
83
  if (!entries || entries.length === 0)
82
84
  return null;
83
85
  const seen = new Set();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ // Type-level acceptance gate for the 0.2.0 breaking change (civic-ai-tools#153,
2
+ // findings A3–A7): identity-bearing config is a REQUIRED parameter — a bare
3
+ // call that omits it must FAIL typecheck. Each `@ts-expect-error` below
4
+ // asserts exactly that: if a silently-applied default parameter is ever
5
+ // reintroduced, the bare call becomes legal, the directive turns unused, and
6
+ // `npm run typecheck` / `npm run build` fail.
7
+ //
8
+ // Compile-time only: the guard function is never exported and never invoked,
9
+ // and the `declare`d values have no runtime existence.
10
+ import { buildProvenanceGraph, buildDatHereEnvironment, deriveDatHereEnvelopeFields, TraceBuilder, isDatasetKeyedSource, displayNameForSource, formatDataSourcesSummary, } from "./index.js";
11
+ function rejectsBareCalls() {
12
+ // @ts-expect-error A3 — buildProvenanceGraph: the ProvenanceConfig is required
13
+ buildProvenanceGraph(trace, provenanceInput);
14
+ // @ts-expect-error A4 — buildDatHereEnvironment: the DatHereEnvironmentConfig is required
15
+ buildDatHereEnvironment('model/slug', undefined);
16
+ // @ts-expect-error A4 — deriveDatHereEnvelopeFields: the DatHereEnvironmentConfig is required
17
+ deriveDatHereEnvelopeFields(policyInput);
18
+ // @ts-expect-error A6 — TraceBuilder: the TraceBuilderConfig is required
19
+ new TraceBuilder();
20
+ // @ts-expect-error A7 — isDatasetKeyedSource: the CivicSourceRegistry is required
21
+ isDatasetKeyedSource('socrata');
22
+ // @ts-expect-error A7 — displayNameForSource: the CivicSourceRegistry is required
23
+ displayNameForSource('socrata');
24
+ // @ts-expect-error A7 — formatDataSourcesSummary: the CivicSourceRegistry is required
25
+ formatDataSourcesSummary(entries);
26
+ }
27
+ void rejectsBareCalls;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typedstandards/civic-typed-harness",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Civic-domain harness for Typed Standards evidence packages — the DOMAIN layer of the ADR-0021 format/domain line: civic PROV-O vocabulary and provenance builder, datHere envelope-policy derivations, and the capture machinery (trace builder, skill-metadata extraction, data-source population, adversarial rubric core). Derives; @typedstandards/produce-core assembles.",
5
5
  "license": "MIT",
6
6
  "author": "Nathan Storey",
@@ -36,6 +36,7 @@
36
36
  "@typedstandards/produce-core": "^0.2.0"
37
37
  },
38
38
  "devDependencies": {
39
+ "@typedstandards/verify-core": "^0.8.0",
39
40
  "@typescript-eslint/parser": "^8",
40
41
  "eslint": "^9",
41
42
  "typescript": "^5.9.3"