pluribus-context 0.3.15 → 0.3.16
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 +7 -0
- package/bin/pluribus.js +3 -1
- package/docs/portability-fidelity-report.md +4 -4
- package/package.json +1 -1
- package/schemas/audit-result.schema.json +78 -0
- package/src/commands/audit.js +114 -2
- package/src/utils/version.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
All notable changes to Pluribus are documented here.
|
|
6
6
|
|
|
7
|
+
## 0.3.16 — audit fidelity evidence
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add `pluribus audit --fidelity-report` so maintainers can emit target-by-target portability evidence in JSON or human output: represented sections, unsupported sections, activation shape, warnings, and the next step before claiming a rule/skill bundle is universal.
|
|
12
|
+
- Update the portability fidelity report guide to use `audit --json --fidelity-report` as the reproducible evidence artifact for directory reviewers and rule/skill bundle maintainers.
|
|
13
|
+
|
|
7
14
|
## 0.3.15 — portability fidelity report demo
|
|
8
15
|
|
|
9
16
|
### Added
|
package/bin/pluribus.js
CHANGED
|
@@ -55,6 +55,7 @@ OPTIONS (audit)
|
|
|
55
55
|
--json Print machine-readable audit results
|
|
56
56
|
--output Write --json results to a file instead of stdout
|
|
57
57
|
--github-annotations Print GitHub Actions annotations for drift/missing outputs
|
|
58
|
+
--fidelity-report Include portability/fidelity evidence for selected targets
|
|
58
59
|
|
|
59
60
|
OPTIONS (watch)
|
|
60
61
|
--source Path to pluribus.md (default: ./pluribus.md)
|
|
@@ -78,6 +79,7 @@ EXAMPLES
|
|
|
78
79
|
pluribus audit --json
|
|
79
80
|
pluribus audit --strict --json --output pluribus-audit.json
|
|
80
81
|
pluribus audit --strict --github-annotations
|
|
82
|
+
pluribus audit --json --fidelity-report
|
|
81
83
|
pluribus watch --tools claude,cursor
|
|
82
84
|
|
|
83
85
|
DOCS
|
|
@@ -88,7 +90,7 @@ const COMMAND_FLAGS = {
|
|
|
88
90
|
init: new Set(['name', 'description', 'tools', 'dry-run']),
|
|
89
91
|
sync: new Set(['dry-run', 'tools', 'source', 'update-imports']),
|
|
90
92
|
validate: new Set(['source', 'update-imports']),
|
|
91
|
-
audit: new Set(['source', 'tools', 'update-imports', 'strict', 'ci', 'json', 'output', 'github-annotations']),
|
|
93
|
+
audit: new Set(['source', 'tools', 'update-imports', 'strict', 'ci', 'json', 'output', 'github-annotations', 'fidelity-report']),
|
|
92
94
|
watch: new Set(['source', 'tools', 'update-imports', 'dry-run', 'once', 'debounce']),
|
|
93
95
|
}
|
|
94
96
|
|
|
@@ -15,7 +15,7 @@ git clone https://github.com/caioribeiroclw-pixel/pluribus.git
|
|
|
15
15
|
cd pluribus/examples/portability-fidelity
|
|
16
16
|
node ../../bin/pluribus.js validate
|
|
17
17
|
node ../../bin/pluribus.js sync --dry-run
|
|
18
|
-
node ../../bin/pluribus.js audit --json
|
|
18
|
+
node ../../bin/pluribus.js audit --json --fidelity-report
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
For the npm release path, copy `examples/portability-fidelity/pluribus.md` into a temporary directory as `pluribus.md`, then run:
|
|
@@ -23,7 +23,7 @@ For the npm release path, copy `examples/portability-fidelity/pluribus.md` into
|
|
|
23
23
|
```bash
|
|
24
24
|
npx --yes pluribus-context@latest validate
|
|
25
25
|
npx --yes pluribus-context@latest sync --dry-run
|
|
26
|
-
npx --yes pluribus-context@latest audit --json
|
|
26
|
+
npx --yes pluribus-context@latest audit --json --fidelity-report
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## What a claim should say
|
|
@@ -75,7 +75,7 @@ Pluribus is intentionally narrower than a skill registry or memory layer:
|
|
|
75
75
|
- `pluribus.md` keeps the claim in one reviewed source of truth.
|
|
76
76
|
- `sync --dry-run` previews target-specific outputs before writing files.
|
|
77
77
|
- generated files carry a warning header so manual edits are visible.
|
|
78
|
-
- `audit --json` gives CI/reviewers a machine-readable check for missing
|
|
78
|
+
- `audit --json --fidelity-report` gives CI/reviewers a machine-readable check for missing/drifted outputs plus target-by-target section loss, activation shape, and portability warnings.
|
|
79
79
|
- remote imports are opt-in, locked, cached, and digest-checked before becoming shared context.
|
|
80
80
|
|
|
81
81
|
That does **not** prove runtime behavior. You still need tool-specific smoke tests for load order, path/glob activation, available tools, MCP servers, and permission semantics.
|
|
@@ -85,7 +85,7 @@ That does **not** prove runtime behavior. You still need tool-specific smoke tes
|
|
|
85
85
|
1. Put the portability claim in the canonical source.
|
|
86
86
|
2. Generate target outputs with `sync --dry-run` and inspect semantic loss.
|
|
87
87
|
3. Keep target-native instructions when a semantic cannot be represented everywhere.
|
|
88
|
-
4. Commit a small audit artifact (`pluribus audit --json --output reports/pluribus-audit.json`) when you want CI/review evidence.
|
|
88
|
+
4. Commit a small audit artifact (`pluribus audit --json --fidelity-report --output reports/pluribus-audit.json`) when you want CI/review evidence.
|
|
89
89
|
5. Update the claim whenever a new target is added, a tool changes capability names, or a permission/security default changes.
|
|
90
90
|
|
|
91
91
|
## Feedback wanted
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pluribus-context",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"description": "AI context/rules sync for CLAUDE.md, Claude Code, Cursor rules, Copilot instructions, OpenClaw, Windsurf, Continue, and Zed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/caioribeiroclw-pixel/pluribus#readme",
|
|
@@ -68,6 +68,10 @@
|
|
|
68
68
|
"type": "string",
|
|
69
69
|
"format": "uri",
|
|
70
70
|
"description": "Issue template URL for reporting audit false positives, noisy output, or confusing next steps."
|
|
71
|
+
},
|
|
72
|
+
"fidelityReport": {
|
|
73
|
+
"$ref": "#/$defs/fidelityReport",
|
|
74
|
+
"description": "Optional portability/fidelity evidence emitted by `pluribus audit --fidelity-report`."
|
|
71
75
|
}
|
|
72
76
|
},
|
|
73
77
|
"allOf": [
|
|
@@ -92,6 +96,80 @@
|
|
|
92
96
|
],
|
|
93
97
|
"additionalProperties": false,
|
|
94
98
|
"$defs": {
|
|
99
|
+
"fidelityReport": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"required": ["claim", "sourceSections", "targets", "summary", "warnings", "nextStep"],
|
|
102
|
+
"properties": {
|
|
103
|
+
"claim": { "type": "string" },
|
|
104
|
+
"sourceSections": {
|
|
105
|
+
"type": "array",
|
|
106
|
+
"items": { "type": "string" }
|
|
107
|
+
},
|
|
108
|
+
"targets": {
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": { "$ref": "#/$defs/fidelityTarget" }
|
|
111
|
+
},
|
|
112
|
+
"summary": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"required": ["targetCount", "targetsWithUnsupportedSections", "warningCount"],
|
|
115
|
+
"properties": {
|
|
116
|
+
"targetCount": { "type": "integer", "minimum": 0 },
|
|
117
|
+
"targetsWithUnsupportedSections": { "type": "integer", "minimum": 0 },
|
|
118
|
+
"warningCount": { "type": "integer", "minimum": 0 }
|
|
119
|
+
},
|
|
120
|
+
"additionalProperties": false
|
|
121
|
+
},
|
|
122
|
+
"warnings": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"items": { "$ref": "#/$defs/fidelityWarning" }
|
|
125
|
+
},
|
|
126
|
+
"nextStep": { "type": "string" }
|
|
127
|
+
},
|
|
128
|
+
"additionalProperties": false
|
|
129
|
+
},
|
|
130
|
+
"fidelityTarget": {
|
|
131
|
+
"type": "object",
|
|
132
|
+
"required": ["toolId", "files", "activation", "representedSections", "unsupportedSections"],
|
|
133
|
+
"properties": {
|
|
134
|
+
"toolId": { "type": "string" },
|
|
135
|
+
"files": {
|
|
136
|
+
"type": "array",
|
|
137
|
+
"items": { "type": "string" }
|
|
138
|
+
},
|
|
139
|
+
"activation": { "$ref": "#/$defs/fidelityActivation" },
|
|
140
|
+
"representedSections": {
|
|
141
|
+
"type": "array",
|
|
142
|
+
"items": { "type": "string" }
|
|
143
|
+
},
|
|
144
|
+
"unsupportedSections": {
|
|
145
|
+
"type": "array",
|
|
146
|
+
"items": { "type": "string" }
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"additionalProperties": false
|
|
150
|
+
},
|
|
151
|
+
"fidelityActivation": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"required": ["kind", "evidence"],
|
|
154
|
+
"properties": {
|
|
155
|
+
"kind": { "type": "string" },
|
|
156
|
+
"evidence": {
|
|
157
|
+
"type": "array",
|
|
158
|
+
"items": { "type": "string" }
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"additionalProperties": false
|
|
162
|
+
},
|
|
163
|
+
"fidelityWarning": {
|
|
164
|
+
"type": "object",
|
|
165
|
+
"required": ["code", "target", "message"],
|
|
166
|
+
"properties": {
|
|
167
|
+
"code": { "type": "string" },
|
|
168
|
+
"target": { "type": "string" },
|
|
169
|
+
"message": { "type": "string" }
|
|
170
|
+
},
|
|
171
|
+
"additionalProperties": false
|
|
172
|
+
},
|
|
95
173
|
"result": {
|
|
96
174
|
"type": "object",
|
|
97
175
|
"required": ["toolId", "status", "file"],
|
package/src/commands/audit.js
CHANGED
|
@@ -38,6 +38,7 @@ export async function runAudit(args) {
|
|
|
38
38
|
const strict = Boolean(args.strict || ci)
|
|
39
39
|
const json = Boolean(args.json)
|
|
40
40
|
const githubAnnotations = Boolean(args['github-annotations'] || ci)
|
|
41
|
+
const fidelityReportEnabled = Boolean(args['fidelity-report'])
|
|
41
42
|
const hasJsonOutput = Object.prototype.hasOwnProperty.call(args, 'output')
|
|
42
43
|
const jsonOutput = typeof args.output === 'string' && args.output.trim() ? args.output : null
|
|
43
44
|
const cwd = process.cwd()
|
|
@@ -225,12 +226,18 @@ export async function runAudit(args) {
|
|
|
225
226
|
}, {})
|
|
226
227
|
|
|
227
228
|
const hasProblem = (summary.drift || 0) + (summary.missing || 0) + (summary.error || 0) > 0
|
|
229
|
+
const fidelityReport = fidelityReportEnabled ? buildFidelityReport({ cwd, sections, tools, loadSkill }) : null
|
|
230
|
+
|
|
231
|
+
if (!json && fidelityReport) {
|
|
232
|
+
printFidelityReport(fidelityReport)
|
|
233
|
+
}
|
|
234
|
+
|
|
228
235
|
if (githubAnnotations) {
|
|
229
236
|
writeGitHubAnnotations(results, { strict })
|
|
230
237
|
}
|
|
231
238
|
|
|
232
239
|
if (json) {
|
|
233
|
-
|
|
240
|
+
const payload = {
|
|
234
241
|
ok: !hasProblem,
|
|
235
242
|
source: displaySource,
|
|
236
243
|
sourceFound: true,
|
|
@@ -246,7 +253,13 @@ export async function runAudit(args) {
|
|
|
246
253
|
? 'Run pluribus sync --dry-run to preview fixes, then pluribus sync to update generated files.'
|
|
247
254
|
: 'Generated context files are in sync.',
|
|
248
255
|
feedback: AUDIT_FEEDBACK_URL,
|
|
249
|
-
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (fidelityReport) {
|
|
259
|
+
payload.fidelityReport = fidelityReport
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
writeJson(payload, jsonOutput)
|
|
250
263
|
} else {
|
|
251
264
|
console.log('')
|
|
252
265
|
console.log(`Summary: ${summary.current || 0} current, ${summary.drift || 0} drifted, ${summary.missing || 0} missing, ${summary.error || 0} error(s).`)
|
|
@@ -264,6 +277,105 @@ export async function runAudit(args) {
|
|
|
264
277
|
}
|
|
265
278
|
}
|
|
266
279
|
|
|
280
|
+
function buildFidelityReport({ cwd, sections, tools, loadSkill }) {
|
|
281
|
+
const presentSections = Object.entries(sections)
|
|
282
|
+
.filter(([, value]) => String(value || '').trim())
|
|
283
|
+
.map(([name]) => name)
|
|
284
|
+
.sort((a, b) => a.localeCompare(b))
|
|
285
|
+
|
|
286
|
+
const lowerPresentSections = new Set(presentSections.map((name) => name.toLowerCase()))
|
|
287
|
+
const targets = tools.map((toolId) => {
|
|
288
|
+
const skill = loadSkill(cwd, toolId)
|
|
289
|
+
const representedSections = new Set([...(skill?.required || []), ...(skill?.optional || [])].map((name) => name.toLowerCase()))
|
|
290
|
+
const unsupportedSections = presentSections.filter((name) => !representedSections.has(name.toLowerCase()))
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
toolId,
|
|
294
|
+
files: skill?.outputFiles || [],
|
|
295
|
+
activation: inferActivation(toolId, skill?.outputFiles || []),
|
|
296
|
+
representedSections: presentSections.filter((name) => representedSections.has(name.toLowerCase())),
|
|
297
|
+
unsupportedSections,
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
const warnings = []
|
|
302
|
+
for (const target of targets) {
|
|
303
|
+
if (target.unsupportedSections.length > 0) {
|
|
304
|
+
warnings.push({
|
|
305
|
+
code: 'section-not-rendered-by-target',
|
|
306
|
+
target: target.toolId,
|
|
307
|
+
message: `${target.toolId} template does not render section(s): ${target.unsupportedSections.join(', ')}`,
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (targets.some((target) => target.activation.kind === 'flat-project-wide')) {
|
|
313
|
+
warnings.push({
|
|
314
|
+
code: 'project-wide-activation-only',
|
|
315
|
+
target: '*',
|
|
316
|
+
message: 'Generated outputs are project-wide/always-on; Pluribus does not currently model path-scoped activation, manual attach, or progressive disclosure semantics.',
|
|
317
|
+
})
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const advancedSections = ['workflow', 'context', 'examples', 'anti-patterns'].filter((name) => lowerPresentSections.has(name))
|
|
321
|
+
if (advancedSections.length > 0 && warnings.some((warning) => warning.code === 'section-not-rendered-by-target')) {
|
|
322
|
+
warnings.push({
|
|
323
|
+
code: 'portability-claim-needs-evidence',
|
|
324
|
+
target: '*',
|
|
325
|
+
message: `Do not claim universal portability without evidence: advanced section(s) ${advancedSections.join(', ')} are not represented equally by every selected target.`,
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
claim: 'project-wide instruction portability evidence for selected targets',
|
|
331
|
+
sourceSections: presentSections,
|
|
332
|
+
targets,
|
|
333
|
+
summary: {
|
|
334
|
+
targetCount: targets.length,
|
|
335
|
+
targetsWithUnsupportedSections: targets.filter((target) => target.unsupportedSections.length > 0).length,
|
|
336
|
+
warningCount: warnings.length,
|
|
337
|
+
},
|
|
338
|
+
warnings,
|
|
339
|
+
nextStep: warnings.length > 0
|
|
340
|
+
? 'Review unsupportedSections/warnings before calling this context universal; narrow the tools list, change the source, or document known lossy targets.'
|
|
341
|
+
: 'Selected targets render the current non-empty source sections with no known Pluribus template loss; still smoke-test behavior in each agent.',
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function inferActivation(toolId, outputFiles) {
|
|
346
|
+
if (toolId === 'windsurf' || toolId === 'continue') {
|
|
347
|
+
return {
|
|
348
|
+
kind: 'project-wide-rule',
|
|
349
|
+
evidence: outputFiles,
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return {
|
|
354
|
+
kind: 'flat-project-wide',
|
|
355
|
+
evidence: outputFiles,
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function printFidelityReport(report) {
|
|
360
|
+
console.log('')
|
|
361
|
+
console.log('Fidelity report:')
|
|
362
|
+
console.log(` Claim: ${report.claim}`)
|
|
363
|
+
console.log(` Targets: ${report.targets.map((target) => target.toolId).join(', ')}`)
|
|
364
|
+
|
|
365
|
+
for (const target of report.targets) {
|
|
366
|
+
const unsupported = target.unsupportedSections.length > 0
|
|
367
|
+
? `; unsupported sections: ${target.unsupportedSections.join(', ')}`
|
|
368
|
+
: '; no known section loss'
|
|
369
|
+
console.log(` • ${target.toolId}: ${target.activation.kind}${unsupported}`)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
for (const warning of report.warnings) {
|
|
373
|
+
console.log(` ⚠️ ${warning.code}: ${warning.message}`)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
console.log(` Next: ${report.nextStep}`)
|
|
377
|
+
}
|
|
378
|
+
|
|
267
379
|
function getTools(rawContent, toolsArg) {
|
|
268
380
|
if (toolsArg) {
|
|
269
381
|
return splitTools(toolsArg)
|
package/src/utils/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.3.
|
|
1
|
+
export const VERSION = '0.3.16'
|