pluribus-context 0.3.41 → 0.3.42

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +3 -2
  3. package/bin/pluribus.js +3 -1
  4. package/docs/agent-surface-proof-chain.md +176 -0
  5. package/docs/cursor-claude-context-handoff.md +68 -0
  6. package/docs/index.html +1 -1
  7. package/docs/receipt-playground.html +54 -0
  8. package/docs/session-preflight-receipts.md +77 -0
  9. package/examples/claude-md-read-receipts/README.md +70 -0
  10. package/examples/claude-md-read-receipts/check-read-receipt.mjs +119 -0
  11. package/examples/claude-md-read-receipts/sample-read-receipt.json +45 -0
  12. package/examples/claude-md-read-receipts/stale-read-receipt.json +18 -0
  13. package/examples/context-sufficiency-trace/README.md +22 -0
  14. package/examples/context-sufficiency-trace/check-context-sufficiency.mjs +40 -0
  15. package/examples/context-sufficiency-trace/context-trace-pass.json +28 -0
  16. package/examples/context-sufficiency-trace/context-trace.json +47 -0
  17. package/examples/context-sufficiency-trace/ground-truth.json +13 -0
  18. package/examples/provider-degradation-canaries/README.md +79 -0
  19. package/examples/provider-degradation-canaries/check-degradation-receipt.mjs +64 -0
  20. package/examples/provider-degradation-canaries/healthy-decision.json +27 -0
  21. package/examples/provider-degradation-canaries/unsafe-write-decision.json +26 -0
  22. package/examples/semantic-anchor-receipts/README.md +49 -0
  23. package/examples/semantic-anchor-receipts/check-semantic-anchors.mjs +153 -0
  24. package/examples/semantic-anchor-receipts/cleaned-paste.md +17 -0
  25. package/examples/semantic-anchor-receipts/original-paste.md +19 -0
  26. package/examples/semantic-anchor-receipts/sample-receipt.json +62 -0
  27. package/examples/session-preflight-receipts/README.md +25 -0
  28. package/examples/session-preflight-receipts/session-preflight-receipt.json +39 -0
  29. package/examples/session-preflight-receipts/session-preflight.mdc +18 -0
  30. package/examples/task-scoped-mcp-config/README.md +60 -0
  31. package/examples/task-scoped-mcp-config/mcp-catalog.json +46 -0
  32. package/examples/task-scoped-mcp-config/select-mcp-config.mjs +64 -0
  33. package/examples/task-scoped-mcp-config/tasks/browser-debug.json +7 -0
  34. package/package.json +1 -1
  35. package/src/commands/demo.js +81 -1
  36. package/src/utils/version.js +1 -1
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ const VALID_STATES = new Set(['fresh', 'compacted', 'topic_switched', 'resumed']);
6
+ const REGROUNDING_STATES = new Set(['compacted', 'topic_switched', 'resumed']);
7
+
8
+ function parseArgs(argv) {
9
+ const args = {};
10
+ for (let i = 0; i < argv.length; i += 1) {
11
+ const key = argv[i];
12
+ const value = argv[i + 1];
13
+ if (key === '--receipt') { args.receipt = value; i += 1; continue; }
14
+ if (key === '--help' || key === '-h') { args.help = true; continue; }
15
+ throw new Error(`Unknown argument: ${key}`);
16
+ }
17
+ return args;
18
+ }
19
+
20
+ function usage() {
21
+ return 'Usage: node check-read-receipt.mjs --receipt sample-read-receipt.json\n';
22
+ }
23
+
24
+ function hasText(value) {
25
+ return typeof value === 'string' && value.trim().length > 0;
26
+ }
27
+
28
+ function asArray(value) {
29
+ return Array.isArray(value) ? value : [];
30
+ }
31
+
32
+ function validate(receipt) {
33
+ const errors = [];
34
+ const warnings = [];
35
+
36
+ if (receipt.schema !== 'pluribus.claude_md_read_receipt.v1') {
37
+ errors.push('schema must be pluribus.claude_md_read_receipt.v1');
38
+ }
39
+ if (!VALID_STATES.has(receipt.session_state)) {
40
+ errors.push(`session_state must be one of: ${[...VALID_STATES].join(', ')}`);
41
+ }
42
+ if (!hasText(receipt.current_task)) {
43
+ errors.push('current_task is required');
44
+ }
45
+
46
+ const reloadedFiles = asArray(receipt.reloaded_files);
47
+ if (reloadedFiles.length === 0) {
48
+ errors.push('reloaded_files must name at least one file/source');
49
+ }
50
+ for (const [index, file] of reloadedFiles.entries()) {
51
+ if (!hasText(file.path)) errors.push(`reloaded_files[${index}].path is required`);
52
+ if (!hasText(file.why)) errors.push(`reloaded_files[${index}].why is required`);
53
+ }
54
+
55
+ const activeConstraints = asArray(receipt.active_constraints).filter(hasText);
56
+ if (activeConstraints.length < 3) {
57
+ errors.push('active_constraints must include at least 3 concrete constraints');
58
+ }
59
+
60
+ if (!Array.isArray(receipt.not_loaded_files)) {
61
+ errors.push('not_loaded_files must be present as an array; use [] only when nothing relevant was skipped');
62
+ } else {
63
+ for (const [index, file] of receipt.not_loaded_files.entries()) {
64
+ if (!hasText(file.path)) errors.push(`not_loaded_files[${index}].path is required`);
65
+ if (!hasText(file.why)) errors.push(`not_loaded_files[${index}].why is required`);
66
+ }
67
+ }
68
+
69
+ const routerLoaded = reloadedFiles.some((file) => /(^|\/)CLAUDE\.md$/i.test(file.path || '') || /router|index/i.test(file.role || ''));
70
+ if (!routerLoaded) warnings.push('no CLAUDE.md/router/index source named in reloaded_files');
71
+
72
+ const topicAuthorityLoaded = reloadedFiles.some((file) => /topic|authority|migration|spec|docs?\//i.test(`${file.role || ''} ${file.path || ''}`));
73
+ if (REGROUNDING_STATES.has(receipt.session_state) && !topicAuthorityLoaded) {
74
+ errors.push(`${receipt.session_state} receipts must name a topic authority/spec/doc reloaded after the boundary`);
75
+ }
76
+
77
+ if (receipt.safe_to_edit === true && errors.length > 0) {
78
+ warnings.push('safe_to_edit=true is ignored because the receipt failed validation');
79
+ }
80
+ if (typeof receipt.safe_to_edit !== 'boolean') {
81
+ errors.push('safe_to_edit must be a boolean');
82
+ }
83
+
84
+ const safeToEdit = errors.length === 0 && receipt.safe_to_edit === true;
85
+ return {
86
+ schema: 'pluribus.claude_md_read_receipt_check.v1',
87
+ source_receipt_schema: receipt.schema || null,
88
+ session_state: receipt.session_state || null,
89
+ current_task_present: hasText(receipt.current_task),
90
+ reloaded_files_count: reloadedFiles.length,
91
+ active_constraints_count: activeConstraints.length,
92
+ skipped_relevant_files_count: Array.isArray(receipt.not_loaded_files) ? receipt.not_loaded_files.length : null,
93
+ router_or_index_named: routerLoaded,
94
+ topic_authority_named: topicAuthorityLoaded,
95
+ stale_notes_named: asArray(receipt.stale_or_historical_notes).length,
96
+ errors,
97
+ warnings,
98
+ safe_to_edit: safeToEdit
99
+ };
100
+ }
101
+
102
+ function main() {
103
+ const args = parseArgs(process.argv.slice(2));
104
+ if (args.help) { process.stdout.write(usage()); return; }
105
+ if (!args.receipt) throw new Error(usage().trim());
106
+
107
+ const receiptPath = path.resolve(args.receipt);
108
+ const receipt = JSON.parse(fs.readFileSync(receiptPath, 'utf8'));
109
+ const result = validate(receipt);
110
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
111
+ if (!result.safe_to_edit) process.exitCode = 1;
112
+ }
113
+
114
+ try {
115
+ main();
116
+ } catch (error) {
117
+ console.error(error.message);
118
+ process.exit(1);
119
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "schema": "pluribus.claude_md_read_receipt.v1",
3
+ "session_state": "topic_switched",
4
+ "current_task": "Update upload API retry handling without regressing the v2.4.0 migration",
5
+ "reloaded_files": [
6
+ {
7
+ "path": "CLAUDE.md",
8
+ "role": "router",
9
+ "why": "Confirms the project uses topic-specific docs and points upload work to docs/upload-api.md"
10
+ },
11
+ {
12
+ "path": "docs/upload-api.md",
13
+ "role": "topic_authority",
14
+ "why": "Current source for upload retries, deprecated helpers, and safety constraints"
15
+ },
16
+ {
17
+ "path": "docs/migrations/v2.4.0.md",
18
+ "role": "migration_note",
19
+ "why": "Current migration note for uploadFile behavior and legacy helper removal"
20
+ }
21
+ ],
22
+ "active_constraints": [
23
+ "Preserve max 3 retry attempts with exponential backoff",
24
+ "Never log raw file contents or customer uploads",
25
+ "Treat v2.4.0 uploadFile migration notes as current authority",
26
+ "Do not reintroduce uploadLegacy(path); it is removed after v2.5.0"
27
+ ],
28
+ "not_loaded_files": [
29
+ {
30
+ "path": "docs/payments.md",
31
+ "why": "Previous topic only; not authority for upload API edits"
32
+ },
33
+ {
34
+ "path": "notes/old-upload-spike.md",
35
+ "why": "Historical spike; superseded by docs/upload-api.md"
36
+ }
37
+ ],
38
+ "stale_or_historical_notes": [
39
+ {
40
+ "ref": "notes/old-upload-spike.md",
41
+ "reason": "Mentions uploadLegacy(path), which is no longer current"
42
+ }
43
+ ],
44
+ "safe_to_edit": true
45
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "schema": "pluribus.claude_md_read_receipt.v1",
3
+ "session_state": "compacted",
4
+ "current_task": "Continue whatever we were doing before compaction",
5
+ "reloaded_files": [
6
+ {
7
+ "path": "CLAUDE.md",
8
+ "role": "router",
9
+ "why": "It is usually loaded at startup"
10
+ }
11
+ ],
12
+ "active_constraints": [
13
+ "Use the normal project rules"
14
+ ],
15
+ "not_loaded_files": [],
16
+ "stale_or_historical_notes": [],
17
+ "safe_to_edit": true
18
+ }
@@ -0,0 +1,22 @@
1
+ # Context sufficiency trace
2
+
3
+ Tiny fixture for the market signal that token-saving context tools need a second metric: did the agent receive the files it later needed?
4
+
5
+ The example compares a retrieval/context-bundle trace against task ground truth and reports:
6
+
7
+ - `gold_context_recall`: required files returned before the edit;
8
+ - `missed_required_file_rate`: required files not returned by the bundle;
9
+ - `late_context_rate`: required files first discovered after the edit started;
10
+ - `frontier_cut_misses`: required files that were seen as candidates but cut from the bundle.
11
+
12
+ Run it:
13
+
14
+ ```bash
15
+ node examples/context-sufficiency-trace/check-context-sufficiency.mjs \
16
+ examples/context-sufficiency-trace/ground-truth.json \
17
+ examples/context-sufficiency-trace/context-trace.json
18
+ ```
19
+
20
+ Expected result for the included fixture: fail. The bundle saved tokens, but it missed `src/auth/session.ts`, which was required for the task and only appeared after editing began.
21
+
22
+ Why this exists: score + token savings can hide a bad context bundle. A sufficiency trace turns the hidden failure into something benchmarkable before a team trusts compression.
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+
4
+ const [truthPath, tracePath] = process.argv.slice(2);
5
+ if (!truthPath || !tracePath) {
6
+ console.error('Usage: node check-context-sufficiency.mjs <ground-truth.json> <context-trace.json>');
7
+ process.exit(2);
8
+ }
9
+
10
+ const readJson = (path) => JSON.parse(fs.readFileSync(path, 'utf8'));
11
+ const truth = readJson(truthPath);
12
+ const trace = readJson(tracePath);
13
+
14
+ const required = new Set(truth.required_files || []);
15
+ const returned = new Set((trace.returned_files || []).map((file) => file.path));
16
+ const frontierCut = new Set((trace.frontier_cut || []).map((file) => file.path));
17
+ const late = new Set((trace.late_files || []).map((file) => file.path));
18
+
19
+ const requiredList = [...required];
20
+ const returnedRequired = requiredList.filter((path) => returned.has(path));
21
+ const missedRequired = requiredList.filter((path) => !returned.has(path));
22
+ const frontierCutMisses = missedRequired.filter((path) => frontierCut.has(path));
23
+ const lateMisses = missedRequired.filter((path) => late.has(path));
24
+
25
+ const ratio = (count, total) => (total === 0 ? 0 : Number((count / total).toFixed(4)));
26
+ const report = {
27
+ task_id: truth.task_id,
28
+ trace_id: trace.trace_id,
29
+ required_files: requiredList.length,
30
+ returned_files: returned.size,
31
+ gold_context_recall: ratio(returnedRequired.length, requiredList.length),
32
+ missed_required_file_rate: ratio(missedRequired.length, requiredList.length),
33
+ late_context_rate: ratio(lateMisses.length, requiredList.length),
34
+ missed_required_files: missedRequired,
35
+ frontier_cut_misses: frontierCutMisses,
36
+ verdict: missedRequired.length === 0 ? 'pass' : 'fail'
37
+ };
38
+
39
+ console.log(JSON.stringify(report, null, 2));
40
+ process.exit(report.verdict === 'pass' ? 0 : 1);
@@ -0,0 +1,28 @@
1
+ {
2
+ "trace_id": "ctxtrace_2026_06_17_demo_pass",
3
+ "query": "fix stale session redirect after token refresh",
4
+ "token_budget": 12000,
5
+ "index_revision": "sha256:demo-index-revision",
6
+ "returned_files": [
7
+ {
8
+ "path": "src/auth/session.ts",
9
+ "hash": "sha256:demo-session",
10
+ "tokens": 2200,
11
+ "reason": "session refresh state owns the redirect freshness condition"
12
+ },
13
+ {
14
+ "path": "src/routes/redirect.ts",
15
+ "hash": "sha256:demo-redirect",
16
+ "tokens": 1400,
17
+ "reason": "direct redirect logic match"
18
+ },
19
+ {
20
+ "path": "test/auth-refresh.test.ts",
21
+ "hash": "sha256:demo-test",
22
+ "tokens": 900,
23
+ "reason": "failing test references token refresh redirect"
24
+ }
25
+ ],
26
+ "frontier_cut": [],
27
+ "late_files": []
28
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "trace_id": "ctxtrace_2026_06_17_demo",
3
+ "query": "fix stale session redirect after token refresh",
4
+ "token_budget": 12000,
5
+ "index_revision": "sha256:demo-index-revision",
6
+ "returned_files": [
7
+ {
8
+ "path": "src/routes/redirect.ts",
9
+ "hash": "sha256:demo-redirect",
10
+ "tokens": 1400,
11
+ "reason": "direct redirect logic match"
12
+ },
13
+ {
14
+ "path": "test/auth-refresh.test.ts",
15
+ "hash": "sha256:demo-test",
16
+ "tokens": 900,
17
+ "reason": "failing test references token refresh redirect"
18
+ },
19
+ {
20
+ "path": "docs/auth-flow.md",
21
+ "hash": "sha256:demo-doc",
22
+ "tokens": 1300,
23
+ "reason": "architecture notes for auth flow"
24
+ }
25
+ ],
26
+ "frontier_cut": [
27
+ {
28
+ "path": "src/auth/session.ts",
29
+ "hash": "sha256:demo-session",
30
+ "tokens": 2200,
31
+ "reason": "ranked 4th; cut to preserve budget"
32
+ },
33
+ {
34
+ "path": "src/auth/cookies.ts",
35
+ "hash": "sha256:demo-cookies",
36
+ "tokens": 1800,
37
+ "reason": "ranked 5th; cut to preserve budget"
38
+ }
39
+ ],
40
+ "late_files": [
41
+ {
42
+ "path": "src/auth/session.ts",
43
+ "first_seen_after": "edit_started",
44
+ "reason": "test failure showed refresh state was stored outside redirect.ts"
45
+ }
46
+ ]
47
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "task_id": "tsbench-style-auth-redirect",
3
+ "task": "Fix the stale session redirect after token refresh.",
4
+ "required_files": [
5
+ "src/auth/session.ts",
6
+ "src/routes/redirect.ts",
7
+ "test/auth-refresh.test.ts"
8
+ ],
9
+ "edit_files": [
10
+ "src/routes/redirect.ts",
11
+ "test/auth-refresh.test.ts"
12
+ ]
13
+ }
@@ -0,0 +1,79 @@
1
+ # Provider degradation canary receipt
2
+
3
+ A tiny gate for agent runs when the model/provider may be silently degraded: slower than normal, timing out, drifting on tool calls, breaking JSON, or producing weaker code edits while the status page still looks green.
4
+
5
+ Use this before side-effecting agent actions such as patches, PRs, migrations, shell commands, deploys, or external writes. The receipt does **not** log prompts or model outputs. It records transport health, cheap capability canaries, and the decision to continue, fallback, pause writes, or stop.
6
+
7
+ ## Prompt / harness pattern
8
+
9
+ ```text
10
+ Before this agent run writes anything, record a degradation decision:
11
+ - provider/model/region and prompt template hash
12
+ - latency/error summary for the run window
13
+ - capability canaries that match this app: JSON schema, tool choice, patch format, refusal/over-refusal, citation grounding
14
+ - failed canaries and severity
15
+ - fallback chosen, if any
16
+ - write gate: continue, read_only, fallback_model, pause_writes, or stop
17
+ - confidence: provider_degraded, app_bug, network, unknown, or healthy
18
+ ```
19
+
20
+ If tool-choice or patch-format canaries fail, keep read-only analysis alive but pause writes until a fallback or human review confirms the agent can still act safely.
21
+
22
+ ## Run the sample checker
23
+
24
+ ```bash
25
+ cd examples/provider-degradation-canaries
26
+ node check-degradation-receipt.mjs --receipt healthy-decision.json
27
+ ```
28
+
29
+ The bundled healthy receipt passes because transport is stable, app-critical canaries pass, and the write gate is allowed.
30
+
31
+ A degraded write attempt should fail:
32
+
33
+ ```bash
34
+ node check-degradation-receipt.mjs --receipt unsafe-write-decision.json
35
+ ```
36
+
37
+ ## Receipt shape
38
+
39
+ ```json
40
+ {
41
+ "schema": "pluribus.provider_degradation_decision.v1",
42
+ "run_id": "agent-run-2026-06-15T20:02Z",
43
+ "provider": "anthropic",
44
+ "model": "claude-sonnet-4",
45
+ "region": "us-east-1",
46
+ "prompt_template_hash": "sha256:...",
47
+ "canary_suite_version": "coding-agent-smoke-2026-06-15",
48
+ "transport": {
49
+ "window_minutes": 10,
50
+ "ttft_p95_ms": 1400,
51
+ "total_latency_p95_ms": 9200,
52
+ "timeout_rate": 0.01,
53
+ "error_rate": 0,
54
+ "retry_count": 1,
55
+ "status_incident_url": null
56
+ },
57
+ "capability_canaries": [
58
+ { "name": "json_schema", "status": "pass", "severity": "write_blocking" },
59
+ { "name": "tool_choice", "status": "pass", "severity": "write_blocking" },
60
+ { "name": "patch_format", "status": "pass", "severity": "write_blocking" }
61
+ ],
62
+ "fallback": { "chosen": false, "reason": null },
63
+ "confidence": "healthy",
64
+ "write_gate": "continue"
65
+ }
66
+ ```
67
+
68
+ ## Why this exists
69
+
70
+ The market signal from Claude Code / API builders is practical: when an LLM silently degrades, teams lose time deciding whether provider behavior, network health, prompt changes, or their own code caused the failure.
71
+
72
+ This receipt keeps that decision falsifiable:
73
+
74
+ - latency alerts and provider status are separated from capability drift;
75
+ - canaries are app-critical, not generic benchmarks;
76
+ - side-effecting actions get stricter gates than read-only analysis;
77
+ - fallback and pause decisions are recorded as evidence, not hidden in transcripts.
78
+
79
+ Pair this with Pluribus context receipts when runtime inputs are the problem. Use this receipt when the question is whether the model/provider is currently reliable enough to let an agent keep writing.
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+
4
+ const args = process.argv.slice(2);
5
+ const receiptPath = args[args.indexOf('--receipt') + 1];
6
+ if (!receiptPath || args.indexOf('--receipt') === -1) {
7
+ console.error('Usage: node check-degradation-receipt.mjs --receipt <path>');
8
+ process.exit(2);
9
+ }
10
+
11
+ const receipt = JSON.parse(fs.readFileSync(receiptPath, 'utf8'));
12
+ const errors = [];
13
+ const gates = new Set(['continue', 'read_only', 'fallback_model', 'pause_writes', 'stop']);
14
+ const confidences = new Set(['healthy', 'provider_degraded', 'app_bug', 'network', 'unknown']);
15
+
16
+ function requireString(field) {
17
+ if (!receipt[field] || typeof receipt[field] !== 'string') errors.push(`${field} must be a non-empty string`);
18
+ }
19
+
20
+ if (receipt.schema !== 'pluribus.provider_degradation_decision.v1') {
21
+ errors.push('schema must be pluribus.provider_degradation_decision.v1');
22
+ }
23
+ for (const field of ['run_id', 'provider', 'model', 'region', 'prompt_template_hash', 'canary_suite_version']) {
24
+ requireString(field);
25
+ }
26
+ if (!String(receipt.prompt_template_hash || '').startsWith('sha256:')) {
27
+ errors.push('prompt_template_hash must be a sha256: digest');
28
+ }
29
+ if (!gates.has(receipt.write_gate)) errors.push(`write_gate must be one of ${[...gates].join(', ')}`);
30
+ if (!confidences.has(receipt.confidence)) errors.push(`confidence must be one of ${[...confidences].join(', ')}`);
31
+
32
+ const t = receipt.transport || {};
33
+ for (const [field, limit] of Object.entries({ window_minutes: 1, ttft_p95_ms: 0, total_latency_p95_ms: 0, timeout_rate: 0, error_rate: 0, retry_count: 0 })) {
34
+ if (typeof t[field] !== 'number' || t[field] < limit) errors.push(`transport.${field} must be a number >= ${limit}`);
35
+ }
36
+ if (t.timeout_rate > 1 || t.error_rate > 1) errors.push('transport timeout/error rates must be <= 1');
37
+
38
+ if (!Array.isArray(receipt.capability_canaries) || receipt.capability_canaries.length < 3) {
39
+ errors.push('capability_canaries must include at least three app-critical canaries');
40
+ }
41
+ const canaries = receipt.capability_canaries || [];
42
+ const required = ['json_schema', 'tool_choice', 'patch_format'];
43
+ for (const name of required) {
44
+ if (!canaries.some((c) => c.name === name)) errors.push(`missing required canary: ${name}`);
45
+ }
46
+ const failingWriteBlockers = canaries.filter((c) => c.status === 'fail' && c.severity === 'write_blocking');
47
+ const degradedTransport = t.timeout_rate >= 0.05 || t.error_rate >= 0.05 || t.ttft_p95_ms >= 5000 || t.total_latency_p95_ms >= 30000;
48
+ if (degradedTransport && receipt.confidence === 'healthy') {
49
+ errors.push('confidence cannot be healthy when transport degradation thresholds are exceeded');
50
+ }
51
+ if (failingWriteBlockers.length > 0 && ['continue'].includes(receipt.write_gate)) {
52
+ errors.push(`write_gate cannot be continue when write-blocking canaries fail: ${failingWriteBlockers.map((c) => c.name).join(', ')}`);
53
+ }
54
+ if (receipt.confidence === 'provider_degraded' && receipt.write_gate === 'continue' && !receipt.fallback?.chosen) {
55
+ errors.push('provider_degraded decisions must choose fallback or block writes instead of continue');
56
+ }
57
+
58
+ if (errors.length) {
59
+ console.error(`Degradation receipt failed (${receiptPath}):`);
60
+ for (const error of errors) console.error(`- ${error}`);
61
+ process.exit(1);
62
+ }
63
+
64
+ console.log(`Degradation receipt passed: ${receiptPath}`);
@@ -0,0 +1,27 @@
1
+ {
2
+ "schema": "pluribus.provider_degradation_decision.v1",
3
+ "run_id": "agent-run-2026-06-15T20:02Z",
4
+ "provider": "anthropic",
5
+ "model": "claude-sonnet-4",
6
+ "region": "us-east-1",
7
+ "prompt_template_hash": "sha256:7a6c7f8b4fb1f3a9d4d9325e5c2a9dbb6b4cbf2e77b49e1f69b1a8d93d1f5c22",
8
+ "canary_suite_version": "coding-agent-smoke-2026-06-15",
9
+ "transport": {
10
+ "window_minutes": 10,
11
+ "ttft_p95_ms": 1400,
12
+ "total_latency_p95_ms": 9200,
13
+ "timeout_rate": 0.01,
14
+ "error_rate": 0,
15
+ "retry_count": 1,
16
+ "status_incident_url": null
17
+ },
18
+ "capability_canaries": [
19
+ { "name": "json_schema", "status": "pass", "severity": "write_blocking" },
20
+ { "name": "tool_choice", "status": "pass", "severity": "write_blocking" },
21
+ { "name": "patch_format", "status": "pass", "severity": "write_blocking" },
22
+ { "name": "citation_grounding", "status": "pass", "severity": "review_blocking" }
23
+ ],
24
+ "fallback": { "chosen": false, "reason": null },
25
+ "confidence": "healthy",
26
+ "write_gate": "continue"
27
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "schema": "pluribus.provider_degradation_decision.v1",
3
+ "run_id": "agent-run-2026-06-15T20:11Z",
4
+ "provider": "anthropic",
5
+ "model": "claude-sonnet-4",
6
+ "region": "us-east-1",
7
+ "prompt_template_hash": "sha256:7a6c7f8b4fb1f3a9d4d9325e5c2a9dbb6b4cbf2e77b49e1f69b1a8d93d1f5c22",
8
+ "canary_suite_version": "coding-agent-smoke-2026-06-15",
9
+ "transport": {
10
+ "window_minutes": 10,
11
+ "ttft_p95_ms": 6200,
12
+ "total_latency_p95_ms": 41000,
13
+ "timeout_rate": 0.18,
14
+ "error_rate": 0.08,
15
+ "retry_count": 12,
16
+ "status_incident_url": null
17
+ },
18
+ "capability_canaries": [
19
+ { "name": "json_schema", "status": "pass", "severity": "write_blocking" },
20
+ { "name": "tool_choice", "status": "fail", "severity": "write_blocking", "evidence": "selected shell write tool for read-only prompt" },
21
+ { "name": "patch_format", "status": "fail", "severity": "write_blocking", "evidence": "diff missing target file header" }
22
+ ],
23
+ "fallback": { "chosen": false, "reason": null },
24
+ "confidence": "provider_degraded",
25
+ "write_gate": "continue"
26
+ }
@@ -0,0 +1,49 @@
1
+ # Semantic anchor preservation receipt
2
+
3
+ A tiny checker for Claude Code / Agent Skill workflows that claim big token savings by cleaning pasted context before it enters a session.
4
+
5
+ Token reduction is useful only if the cleaned paste keeps the anchors that make the task safe to execute: headings, code fences, API signatures, version/migration notes, and must-keep policy/security lines. This example emits a privacy-safe receipt for that claim without logging raw prompts or transcripts.
6
+
7
+ ## Run it
8
+
9
+ ```bash
10
+ cd examples/semantic-anchor-receipts
11
+ node check-semantic-anchors.mjs \
12
+ --original original-paste.md \
13
+ --cleaned cleaned-paste.md \
14
+ --out /tmp/semantic-anchor.receipt.json
15
+ ```
16
+
17
+ The bundled sample should pass and report a token reduction while preserving all detected anchors.
18
+
19
+ ## Receipt shape
20
+
21
+ ```json
22
+ {
23
+ "schema": "pluribus.semantic_anchor_preservation_receipt.v1",
24
+ "source_type": "paste-cleaning-skill-or-cli-output",
25
+ "approximate_tokens_before": 224,
26
+ "approximate_tokens_after": 110,
27
+ "approximate_reduction_percent": 50.9,
28
+ "anchors_total": 9,
29
+ "anchors_missing": 0,
30
+ "semantic_loss_check_passed": true,
31
+ "token_savings_claim_allowed": true
32
+ }
33
+ ```
34
+
35
+ The exact token counts are approximate. The important part is the gate:
36
+
37
+ - `semantic_loss_check_passed=true` means the cleaned paste preserved the detected anchors.
38
+ - `token_savings_claim_allowed=true` means the output both shrank and kept those anchors.
39
+ - If any anchor is missing, the checker exits non-zero and the receipt records the missing anchor types/text snippets.
40
+
41
+ ## Why this exists
42
+
43
+ The market signal has moved beyond MCP tool bloat. Claude Code users are also using Skills and paste-cleaning CLIs that claim 50–70% token savings. Pluribus should not be another optimizer; it should make the optimizer's claim falsifiable:
44
+
45
+ - What was removed?
46
+ - Which must-keep anchors survived?
47
+ - Did a `SKILL.md` or CLI helper reduce tokens without deleting version, API, or security context?
48
+
49
+ Use this receipt before a cleaned paste becomes session context. Pair it with tool/skill adoption receipts later if you need to prove the agent actually used a loaded Skill or MCP tool.