freshcontext-mcp 0.3.22 → 0.4.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.
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  const HA_PRI_V2_VERSION = "FRESHCONTEXT_HA_PRI_V2";
3
+ const HA_PRI_V3_VERSION = "FRESHCONTEXT_HA_PRI_V3";
3
4
  const NULL_SENTINEL = "null";
4
5
  function fieldValue(value) {
5
6
  return value ?? NULL_SENTINEL;
@@ -46,6 +47,52 @@ export function calculateHaPriV2(input) {
46
47
  haPriSigV2: sha256Hex(signingPayload),
47
48
  };
48
49
  }
50
+ // Returns the canonical signing payload string only — no hash, no HMAC.
51
+ // The Worker reads this and signs it with Web Crypto. calculateHaPriV2
52
+ // additionally SHA-256-hashes the same string for the existing provenance path.
53
+ export function buildHaPriPayload(input) {
54
+ const canonicalContentSha256 = sha256Hex(canonicalizeHaPriContent(input.rawContent));
55
+ const semanticFingerprintSha256 = sha256Hex(fieldValue(input.semanticFingerprint));
56
+ const resultId = fieldValue(input.resultId);
57
+ const adapter = fieldValue(input.adapter);
58
+ const publishedAt = fieldValue(input.publishedAt);
59
+ const retrievedAt = fieldValue(input.retrievedAt);
60
+ const engineVersion = fieldValue(input.engineVersion);
61
+ return [
62
+ HA_PRI_V2_VERSION,
63
+ `result_id=${resultId}`,
64
+ `canonical_content_sha256=${canonicalContentSha256}`,
65
+ `semantic_fingerprint_sha256=${semanticFingerprintSha256}`,
66
+ `adapter=${adapter}`,
67
+ `published_at=${publishedAt}`,
68
+ `retrieved_at=${retrievedAt}`,
69
+ `engine_version=${engineVersion}`,
70
+ ].join("\n");
71
+ }
72
+ // v3 payload = same 8 v2 fields + verdict_id + decision, under the V3 header.
73
+ // This signs the apple, not just the tree: the HMAC covers what content was seen
74
+ // AND what verdict was reached. Alongside v2 — does NOT replace buildHaPriPayload.
75
+ export function buildHaPriPayloadV3(input) {
76
+ const canonicalContentSha256 = sha256Hex(canonicalizeHaPriContent(input.rawContent));
77
+ const semanticFingerprintSha256 = sha256Hex(fieldValue(input.semanticFingerprint));
78
+ const resultId = fieldValue(input.resultId);
79
+ const adapter = fieldValue(input.adapter);
80
+ const publishedAt = fieldValue(input.publishedAt);
81
+ const retrievedAt = fieldValue(input.retrievedAt);
82
+ const engineVersion = fieldValue(input.engineVersion);
83
+ return [
84
+ HA_PRI_V3_VERSION,
85
+ `result_id=${resultId}`,
86
+ `canonical_content_sha256=${canonicalContentSha256}`,
87
+ `semantic_fingerprint_sha256=${semanticFingerprintSha256}`,
88
+ `adapter=${adapter}`,
89
+ `published_at=${publishedAt}`,
90
+ `retrieved_at=${retrievedAt}`,
91
+ `engine_version=${engineVersion}`,
92
+ `verdict_id=${input.verdictId}`,
93
+ `decision=${input.decision}`,
94
+ ].join("\n");
95
+ }
49
96
  export function verifyHaPriV2(input, actualSig) {
50
97
  if (actualSig === null || actualSig === undefined || actualSig.trim() === "") {
51
98
  return {
@@ -1,3 +1,4 @@
1
+ import type { StalenessVerdict } from "./decay.js";
1
2
  export interface FreshContext {
2
3
  content: string;
3
4
  source_url: string;
@@ -6,6 +7,8 @@ export interface FreshContext {
6
7
  freshness_confidence: "high" | "medium" | "low";
7
8
  freshness_score: number | null;
8
9
  adapter: string;
10
+ staleness: StalenessVerdict;
11
+ revalidate_after: string | null;
9
12
  }
10
13
  export interface ExtractOptions {
11
14
  url: string;
@@ -54,9 +57,39 @@ export interface SourceProfile {
54
57
  export interface ContextDecisionOptions {
55
58
  sourceProfile?: SourceProfile | SourceProfileId;
56
59
  intentProfile?: IntentProfileId;
60
+ /**
61
+ * Optional decision-time clock override. Controls the evaluated_at field
62
+ * on the returned ContextDecisionResult. Defaults to new Date() when
63
+ * omitted. Pass a deterministic value in tests or any caller that needs
64
+ * reproducible verdicts.
65
+ */
66
+ now?: string | Date;
57
67
  }
58
68
  export interface ContextDecisionResult {
59
69
  decision: ContextDecision;
70
+ /**
71
+ * Deterministic fingerprint of this verdict (signal identity + decision +
72
+ * profile selection). Stable across repeated evaluations of the same
73
+ * input; intentionally NOT derived from utility or provenance_readiness.
74
+ * This is the id a future verification event would reference when
75
+ * resolving a needs_verification (or similar) decision.
76
+ */
77
+ verdict_id?: string;
78
+ /**
79
+ * ISO timestamp recording when this decision was computed. Always
80
+ * populated at runtime by the decision factory; optional in the type for
81
+ * backward compatibility with existing consumers that construct results
82
+ * manually — same convention as verdict_id. This is the stored decision-
83
+ * time clock — it is NOT recomputed at read time.
84
+ */
85
+ evaluated_at?: string;
86
+ /**
87
+ * Advisory hint for when this verdict is worth re-checking, derived from
88
+ * the source profile's half_life_hours (evaluated_at + 1.0 × half-life).
89
+ * Explicit null when no source profile basis is available — never a
90
+ * fabricated timestamp. NOT enforcement; consumers decide what to do.
91
+ */
92
+ revalidate_after?: string | null;
60
93
  label: string;
61
94
  meaning: string;
62
95
  action: string;
@@ -159,6 +192,21 @@ export interface HaPriV2Input {
159
192
  retrievedAt?: string | null;
160
193
  engineVersion: string;
161
194
  }
195
+ export interface HaPriV3Input extends HaPriV2Input {
196
+ /**
197
+ * Deterministic verdict fingerprint (SHA-256 of decision basis fields).
198
+ * Computed by computeVerdictId in decision.ts at evaluation time.
199
+ */
200
+ verdictId: string;
201
+ /**
202
+ * The ContextDecision enum value (e.g., "use_first", "exclude").
203
+ * Typed as string so the signing layer stays free of decision-module imports.
204
+ * Including both verdictId and decision in the payload is intentional: the pair
205
+ * forms a mutual cross-check — either field tampered independently breaks the HMAC,
206
+ * and a verifier can read the decision without recomputing verdictId.
207
+ */
208
+ decision: string;
209
+ }
162
210
  export interface HaPriV2Material {
163
211
  version: "FRESHCONTEXT_HA_PRI_V2";
164
212
  resultId: string;
@@ -1 +1 @@
1
- export declare function handleRestRequest(request: Request): Promise<Response>;
1
+ export declare function handleRestRequest(request: Request, hmacSecret?: string): Promise<Response>;
@@ -1,5 +1,5 @@
1
1
  import { evaluateSignal, evaluateSignals } from "../core/index.js";
2
- const SERVICE_VERSION = "0.1.0";
2
+ const SERVICE_VERSION = "0.4.0";
3
3
  const JSON_CONTENT_TYPE = "application/json";
4
4
  const MAX_BODY_BYTES = 256 * 1024;
5
5
  function jsonResponse(body, status = 200) {
@@ -109,7 +109,56 @@ function handleHealth(request) {
109
109
  core_available: true,
110
110
  });
111
111
  }
112
- export async function handleRestRequest(request) {
112
+ async function hmacHex(key, payload) {
113
+ const cryptoKey = await crypto.subtle.importKey("raw", new TextEncoder().encode(key), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
114
+ const buf = await crypto.subtle.sign("HMAC", cryptoKey, new TextEncoder().encode(payload));
115
+ return Array.from(new Uint8Array(buf))
116
+ .map((b) => b.toString(16).padStart(2, "0"))
117
+ .join("");
118
+ }
119
+ async function handleVerify(request, hmacSecret) {
120
+ if (request.method !== "POST")
121
+ return methodNotAllowed("POST");
122
+ if (!hmacSecret) {
123
+ return jsonResponse({
124
+ status: "unknown",
125
+ reasons: ["signing secret not configured on this host; cannot verify"],
126
+ });
127
+ }
128
+ const parsed = await readJsonBody(request);
129
+ if (!parsed.ok)
130
+ return parsed.response;
131
+ const { signing_payload, signature } = parsed.body;
132
+ if (typeof signing_payload !== "string" || signing_payload.trim() === "") {
133
+ return errorResponse("invalid_request", "signing_payload must be a non-empty string.", 400);
134
+ }
135
+ // Unknown (not invalid): caller has no signature to present.
136
+ // Mirrors verifyHaPriV2's three-state contract: missing/empty → unknown, not invalid.
137
+ if (signature === undefined || signature === null) {
138
+ return jsonResponse({
139
+ status: "unknown",
140
+ reasons: ["signature missing or empty; verification status unknown"],
141
+ });
142
+ }
143
+ if (typeof signature !== "string") {
144
+ return errorResponse("invalid_request", "signature must be a string.", 400);
145
+ }
146
+ if (signature.trim() === "") {
147
+ return jsonResponse({
148
+ status: "unknown",
149
+ reasons: ["signature missing or empty; verification status unknown"],
150
+ });
151
+ }
152
+ const expected = await hmacHex(hmacSecret, signing_payload);
153
+ if (signature === expected) {
154
+ return jsonResponse({ status: "valid", reasons: [] });
155
+ }
156
+ return jsonResponse({ status: "invalid", reasons: ["HMAC does not match recomputed signature"] });
157
+ }
158
+ // hmacSecret is injected by the Worker from env.FC_HMAC_SECRET when mounted.
159
+ // handler.ts never imports or holds the secret — it arrives as a call-scoped
160
+ // parameter. Existing callers that omit it continue to work; other routes ignore it.
161
+ export async function handleRestRequest(request, hmacSecret) {
113
162
  const url = new URL(request.url);
114
163
  try {
115
164
  if (url.pathname === "/v1/health")
@@ -118,6 +167,8 @@ export async function handleRestRequest(request) {
118
167
  return handleEvaluate(request);
119
168
  if (url.pathname === "/v1/evaluate-batch")
120
169
  return handleEvaluateBatch(request);
170
+ if (url.pathname === "/v1/verify")
171
+ return handleVerify(request, hmacSecret);
121
172
  return errorResponse("not_found", `Not found: ${url.pathname}.`, 404);
122
173
  }
123
174
  catch {
package/dist/server.js CHANGED
@@ -23,7 +23,7 @@ import { EvaluateContextInputError, evaluateContextInput, formatEvaluateContextR
23
23
  import { formatSecurityError } from "./security.js";
24
24
  const server = new McpServer({
25
25
  name: "freshcontext-mcp",
26
- version: "0.3.22",
26
+ version: "0.4.0",
27
27
  });
28
28
  const signalInputSchema = z.object({
29
29
  id: z.string().optional(),
@@ -6,7 +6,7 @@ Use this guide when connecting Claude Desktop, Codex, or another MCP-compatible
6
6
 
7
7
  ## What You Should See
8
8
 
9
- FreshContext `0.3.22` exposes:
9
+ FreshContext `0.4.0` exposes:
10
10
 
11
11
  ```text
12
12
  22 tools = evaluate_context + 21 read-only reference adapters
@@ -105,8 +105,8 @@ Expected smoke result:
105
105
  ```json
106
106
  {
107
107
  "ok": true,
108
- "package_version": "0.3.22",
109
- "server_version": "0.3.22",
108
+ "package_version": "0.4.0",
109
+ "server_version": "0.4.0",
110
110
  "tool_count": 22
111
111
  }
112
112
  ```
@@ -132,7 +132,7 @@ Some clients can use `mcp-remote`:
132
132
  }
133
133
  ```
134
134
 
135
- The npm/local stdio package remains the safest default client path. The hosted Worker endpoint was last verified on 2026-06-14 at `0.3.21 / 22 tools` with `evaluate_context` present and returning decision-first output, including `provenance_readiness`, `readable`, and `readable.handoff`. Because the Worker is a separate deployment surface, re-run remote verification before claiming future package interfaces are live there.
135
+ The npm/local stdio package remains the safest default client path. The hosted Worker endpoint was last verified on 2026-06-19 at `0.4.0 / 22 tools` with `evaluate_context` present and returning decision-first output, including `provenance_readiness`, `readable`, and `readable.handoff`. Because the Worker is a separate deployment surface, re-run remote verification before claiming future package interfaces are live there.
136
136
 
137
137
  ## ChatGPT / OpenAI Connector Boundary
138
138
 
@@ -67,7 +67,7 @@ command = "npx"
67
67
  args = ["-y", "mcp-remote", "https://freshcontext-mcp.gimmanuel73.workers.dev/mcp"]
68
68
  ```
69
69
 
70
- This remote path was last verified on 2026-06-14 as a live Worker MCP endpoint exposing `0.3.21 / 22 tools`, including `evaluate_context`, `provenance_readiness`, `readable`, and `readable.handoff`. That confirms Worker availability and MCP tool discovery. It does not by itself claim Codex Cloud support or guarantee every MCP client can use the remote bridge without its own client-specific setup check.
70
+ This remote path was last verified on 2026-06-19 as a live Worker MCP endpoint exposing `0.4.0 / 22 tools`, including `evaluate_context`, `provenance_readiness`, `readable`, and `readable.handoff`. That confirms Worker availability and MCP tool discovery. It does not by itself claim Codex Cloud support or guarantee every MCP client can use the remote bridge without its own client-specific setup check.
71
71
 
72
72
  ## Verification steps
73
73
 
@@ -83,8 +83,8 @@ Expected result:
83
83
  ```json
84
84
  {
85
85
  "ok": true,
86
- "package_version": "0.3.22",
87
- "server_version": "0.3.22",
86
+ "package_version": "0.4.0",
87
+ "server_version": "0.4.0",
88
88
  "tool_count": 22
89
89
  }
90
90
  ```
@@ -102,7 +102,7 @@ Expected result: no output and exit code 0.
102
102
  - Do not place secrets, credentials, registry tokens, npm tokens, GitHub tokens, or Cloudflare tokens in Codex MCP config.
103
103
  - Do not read, edit, print, or commit local token files, local environment files, registry credentials, Cloudflare local state, or Wrangler state.
104
104
  - Do not commit local Codex config or machine-specific paths.
105
- - Prefer the local stdio path for source-checkout compatibility checks because it is verified by `npm run smoke:stdio`.
105
+ - Prefer the local stdio path for source-checkout compatibility checks because it is verified by `npm run smoke:stdio`.
106
106
  - Do not claim Codex Cloud support unless it is separately tested and documented.
107
107
 
108
108
  ## Troubleshooting
@@ -50,17 +50,17 @@ Worker/site surfaces own deployment concerns:
50
50
 
51
51
  Live today:
52
52
 
53
- - npm package: `freshcontext-mcp@0.3.21`
53
+ - npm package: `freshcontext-mcp@0.4.0`
54
54
  - MCP stdio server and published binary: `freshcontext-mcp`
55
55
  - Core subpath export: `freshcontext-mcp/core`
56
56
  - `evaluate_context` MCP tool for caller-provided candidate context
57
57
  - 21 named read-only reference adapters
58
58
  - Core signal evaluation
59
59
  - Source Profiles
60
- - Decision Helper
61
- - human-readable `readable` output on structured `evaluate_context` results
62
- - provenance readiness and readable handoff safety
63
- - adapter registry metadata
60
+ - Decision Helper
61
+ - human-readable `readable` output on structured `evaluate_context` results
62
+ - provenance readiness and readable handoff safety
63
+ - adapter registry metadata
64
64
  - arXiv signal-to-decision proof
65
65
  - bring-your-own-context local demos
66
66
  - Trust Scanner release gate
@@ -10,7 +10,7 @@ The current package boundary is documented in [Core / MCP Boundary](./CORE_MCP_B
10
10
 
11
11
  Live today:
12
12
 
13
- - npm package: `freshcontext-mcp@0.3.21`
13
+ - npm package: `freshcontext-mcp@0.4.0`
14
14
  - MCP stdio server
15
15
  - `evaluate_context` MCP tool for caller-provided candidate context
16
16
  - Signal Contract v1 as the stable candidate-context input shape
@@ -1,5 +1,84 @@
1
1
  # FreshContext Release Notes
2
2
 
3
+ ## 0.4.0
4
+
5
+ FreshContext 0.4.0 ships the signed-verdict integrity loop and the staleness envelope live in
6
+ production, closing the near-term arc toward context-integrity infrastructure: a judgment that
7
+ is not just scored, but signed, stored, verifiable, and legible as a staleness signal.
8
+
9
+ ### Ha-Pri v2 / v3 Signed-Verdict Loop (live in production)
10
+
11
+ - Adds HMAC-SHA256 signing of the `evaluate_context` verdict path (v2): canonical content
12
+ hash, semantic fingerprint, adapter, timestamps, and version-scoped engine version, signed
13
+ under a server-held secret never present in Core, never logged.
14
+ - Adds Ha-Pri v3: extends the signed payload with `verdict_id` and the `decision` itself, so
15
+ the signature is tamper-evident at the verdict level. v3 runs additively alongside v2.
16
+ - Adds an append-only `evaluation_snapshots` ledger. Every signed verdict is stored; rows are
17
+ never updated or deleted. Ledger writes are non-fatal and non-blocking — a storage failure
18
+ can never break the caller's evaluation response.
19
+ - Adds a stateless `/v1/verify` endpoint: recompute-and-compare HMAC verification returning
20
+ `valid` / `invalid` / `unknown`, callable by any third party without holding the signing
21
+ secret. Verification reads the stored, version-scoped engine version, never a live constant.
22
+ - Live-verified in production 2026-06-30: first signed row confirmed byte-correct end to end
23
+ (content hash, signature, verdict_id, decision, all fields consistent across independent
24
+ computation paths).
25
+
26
+ ### The Staleness Envelope ("the eyes")
27
+
28
+ - Adds an explicit `staleness` verdict (`fresh` / `aging` / `stale` / `unknown`) and a
29
+ `revalidate_after` timestamp to the FreshContext envelope (`stampFreshness` /
30
+ `toStructuredJSON` / `formatForLLM`), derived from the existing per-source freshness score —
31
+ no second decay computation, no new tunable.
32
+ - `revalidate_after` solves the existing exponential decay function at its "verify before
33
+ acting" threshold (one half-life from the content date); null when the content date is
34
+ unknown, in lockstep with `freshness_score`.
35
+ - Surfaces both the human-readable line (`Staleness: fresh (revalidate by ...)`) and the
36
+ structured JSON fields, so a consuming model sees staleness directly rather than having to
37
+ interpret a bare score.
38
+ - Available via the adapter/extract tools' FreshContext envelope path. Not present in
39
+ `evaluate_context` output, which uses a separate evaluation-result format by design.
40
+ - Live-verified in production 2026-07-01 via a real adapter call against the deployed Worker.
41
+
42
+ ### Decay Model Validation
43
+
44
+ - Validated the per-source exponential decay model against 1,219 rows of real production data
45
+ across 6 active source types. Confirmed the pure freshness function is clean and correctly
46
+ calibrated (measured half-lives match design intent). Documented the honest scope boundary:
47
+ age predicts source-level decay rate, not per-item validity; per-item variance is driven by
48
+ content, not age alone. Full audit: `docs/FRESHCONTEXT_FLAG_A_THESIS_2026-06-30.md`.
49
+
50
+ ### Methodology and Defensibility
51
+
52
+ - `METHODOLOGY.md` updated to v1.3, documenting the live signed-verdict integrity layer and
53
+ the decay validation, so the authored specification matches the shipped engine.
54
+
55
+ ### Release Gate
56
+
57
+ - Full test suite: 344 pass / 0 fail.
58
+ - MCP smoke confirmed at 22 tools / 0.4.0.
59
+ - Trust Scanner gate: effective fail 0.
60
+ - Package and server metadata aligned at 0.4.0.
61
+
62
+ ## 0.3.23
63
+
64
+ FreshContext 0.3.23 adds deterministic verdict identity for evaluated context results.
65
+
66
+ ### Deterministic Verdict ID
67
+
68
+ - Adds `verdict_id` to structured `evaluate_context` output.
69
+ - `verdict_id` is deterministic: the same input signal and evaluation context always
70
+ produce the same identifier, enabling audit trails, caching, and downstream
71
+ deduplication.
72
+ - Keeps `verdict_id` additive: it does not change ranking, decision labels, utility
73
+ scoring, or existing structured output fields.
74
+ - Preserves full backward compatibility with 0.3.22 evaluate_context output shapes.
75
+
76
+ ### Release Gate
77
+
78
+ - MCP smoke confirmed at 22 tools / 0.3.23.
79
+ - Trust Scanner gate: effective fail 0.
80
+ - Package and server metadata aligned at 0.3.23.
81
+
3
82
  ## 0.3.22
4
83
 
5
84
  FreshContext 0.3.22 expands Source Profiles as judgment policies without adding adapters or retrieval behavior.
@@ -47,53 +126,53 @@ FreshContext 0.3.21 adds provenance readiness and readable handoff safety for ju
47
126
  ## 0.3.19
48
127
 
49
128
  FreshContext 0.3.19 syncs the public MCP package with the new generic `evaluate_context` interface.
50
-
51
- ### Context Evaluation Front Door
52
-
53
- - Adds `evaluate_context` as the primary MCP tool for caller-provided candidate context.
54
- - Returns decision-first output for agents and users: decision, meaning, action, warnings, source, freshness, rank score, utility, confidence, and explanation.
55
- - Keeps the boundary explicit: `evaluate_context` does not fetch, crawl, scrape, browse, read folders, or call adapters.
56
- - Updates stdio smoke and Trust Scanner claim checks to expect 22 MCP tools: `evaluate_context` plus 21 read-only reference adapters.
57
-
58
- ### Public Framing
59
-
60
- - Reframes the MCP package around FreshContext as context integrity infrastructure, not a 21-tool toolbox.
61
- - Keeps the 21 adapter tools as read-only reference adapters and proof surfaces.
62
- - Updates package-facing docs/spec language to point first at `candidate context -> FreshContext Core -> decision-ready context`.
63
-
64
- ## 0.3.18
65
-
66
- FreshContext 0.3.18 made the MCP/Core package easier to install, validate, and explain without changing the deployed Worker runtime.
67
-
68
- ### Core and Context Evaluation
69
-
70
- - Added the Core signal evaluation pipeline for normalized, freshness-ranked context results.
71
- - Added Source Profiles as Core metadata for source-aware policy vocabulary.
72
- - Added the Context Decision Helper so evaluated context can be interpreted as use, cite, verify, refresh, watch, background, or exclude.
73
- - Preserved the ranking boundary: `ranked.final_score` controls default ordering, while `utility.score` remains sidecar intelligence.
74
-
75
- ### Bring Your Own Context
76
-
77
- - Added decision-first local demos for user-provided JSON source lists.
78
- - Added academic citation and jobs/opportunity sample inputs.
79
- - Added `npm run demo:evaluate:file` for local source-list evaluation from a cloned source checkout.
80
-
81
- ### Adapter Path
82
-
83
- - Added adapter registry metadata for the 21 existing MCP tools.
84
- - Added additive arXiv signal extraction without changing the existing MCP `extract_arxiv` behavior.
85
- - Added an arXiv signal-to-decision proof using a static fixture, Core evaluation, and decision output.
86
-
87
- ### Package and Release Hygiene
88
-
89
- - Hardened the npm package file allowlist.
90
- - Added script guards so repo-only scripts show a source-checkout notice in packed installs.
91
- - Isolated Apify/Crawlee from the normal MCP npm runtime package while preserving source-checkout Apify Actor support.
92
- - Confirmed fresh consumer installs no longer install Apify/Crawlee/file-type through the default MCP package path.
93
-
94
- ### Boundaries
95
-
96
- - No Worker deploy is part of the npm package release.
97
- - No hosted dashboard, billing system, Operator mode, browser crawling, or local file scanning is included.
98
- - No Worker, REST handler, MCP tool schema, or existing adapter behavior changes are included in the package release itself.
99
- - Future work is tracked in [`FUTURE_LANES.md`](./FUTURE_LANES.md).
129
+
130
+ ### Context Evaluation Front Door
131
+
132
+ - Adds `evaluate_context` as the primary MCP tool for caller-provided candidate context.
133
+ - Returns decision-first output for agents and users: decision, meaning, action, warnings, source, freshness, rank score, utility, confidence, and explanation.
134
+ - Keeps the boundary explicit: `evaluate_context` does not fetch, crawl, scrape, browse, read folders, or call adapters.
135
+ - Updates stdio smoke and Trust Scanner claim checks to expect 22 MCP tools: `evaluate_context` plus 21 read-only reference adapters.
136
+
137
+ ### Public Framing
138
+
139
+ - Reframes the MCP package around FreshContext as context integrity infrastructure, not a 21-tool toolbox.
140
+ - Keeps the 21 adapter tools as read-only reference adapters and proof surfaces.
141
+ - Updates package-facing docs/spec language to point first at `candidate context -> FreshContext Core -> decision-ready context`.
142
+
143
+ ## 0.3.18
144
+
145
+ FreshContext 0.3.18 made the MCP/Core package easier to install, validate, and explain without changing the deployed Worker runtime.
146
+
147
+ ### Core and Context Evaluation
148
+
149
+ - Added the Core signal evaluation pipeline for normalized, freshness-ranked context results.
150
+ - Added Source Profiles as Core metadata for source-aware policy vocabulary.
151
+ - Added the Context Decision Helper so evaluated context can be interpreted as use, cite, verify, refresh, watch, background, or exclude.
152
+ - Preserved the ranking boundary: `ranked.final_score` controls default ordering, while `utility.score` remains sidecar intelligence.
153
+
154
+ ### Bring Your Own Context
155
+
156
+ - Added decision-first local demos for user-provided JSON source lists.
157
+ - Added academic citation and jobs/opportunity sample inputs.
158
+ - Added `npm run demo:evaluate:file` for local source-list evaluation from a cloned source checkout.
159
+
160
+ ### Adapter Path
161
+
162
+ - Added adapter registry metadata for the 21 existing MCP tools.
163
+ - Added additive arXiv signal extraction without changing the existing MCP `extract_arxiv` behavior.
164
+ - Added an arXiv signal-to-decision proof using a static fixture, Core evaluation, and decision output.
165
+
166
+ ### Package and Release Hygiene
167
+
168
+ - Hardened the npm package file allowlist.
169
+ - Added script guards so repo-only scripts show a source-checkout notice in packed installs.
170
+ - Isolated Apify/Crawlee from the normal MCP npm runtime package while preserving source-checkout Apify Actor support.
171
+ - Confirmed fresh consumer installs no longer install Apify/Crawlee/file-type through the default MCP package path.
172
+
173
+ ### Boundaries
174
+
175
+ - No Worker deploy is part of the npm package release.
176
+ - No hosted dashboard, billing system, Operator mode, browser crawling, or local file scanning is included.
177
+ - No Worker, REST handler, MCP tool schema, or existing adapter behavior changes are included in the package release itself.
178
+ - Future work is tracked in [`FUTURE_LANES.md`](./FUTURE_LANES.md).
@@ -106,6 +106,8 @@ const commands = {
106
106
  "tests/arxivDecisionIntegration.test.ts",
107
107
  "tests/core.test.ts",
108
108
  "tests/haPriV2GoldenVectors.test.ts",
109
+ "tests/haPriV3GoldenVectors.test.ts",
110
+ "tests/hmacSigning.test.ts",
109
111
  "tests/signalContractExamples.test.ts",
110
112
  "tests/batchValidationHarness.test.ts",
111
113
  "tests/rank.test.ts",
@@ -125,8 +127,15 @@ const commands = {
125
127
  "tests/decision.test.ts",
126
128
  "tests/evaluateContextTool.test.ts",
127
129
  "tests/restHandler.test.ts",
130
+ "tests/verifyEndpoint.test.ts",
131
+ "tests/evaluateContextSnapshot.test.ts",
132
+ "tests/evaluateVerifyLoop.test.ts",
133
+ "tests/stalenessEnvelope.test.ts",
128
134
  "tests/sourceProfiles.test.ts",
129
135
  "tests/adapterRegistry.test.ts",
136
+ "tests/coreEdgeBoundary.test.ts",
137
+ "tests/lambdaSingleSource.test.ts",
138
+ "tests/workerDarGoldenVectors.test.ts",
130
139
  "tests/trustScan.test.mjs",
131
140
  ],
132
141
  },