plumb-line-provenance 0.2.0 → 0.3.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/audit.mjs CHANGED
@@ -20,9 +20,14 @@ export function auditMeta(meta) {
20
20
  );
21
21
  }
22
22
 
23
+ // An unknown confidence on a step is laundering, not "no signal": treat it as
24
+ // the `none` floor (mirroring weakestConfidence), so audit is never laxer than
25
+ // the combination law. A step that records *no* confidence is still skipped —
26
+ // absence is genuinely unrankable and must not manufacture a false over-claim.
23
27
  const lineageConfidences = lineage
24
28
  .map((s) => s?.confidence)
25
- .filter((c) => CONFIDENCE.includes(c));
29
+ .filter((c) => c != null)
30
+ .map((c) => (CONFIDENCE.includes(c) ? c : "none"));
26
31
  if (lineageConfidences.length > 0) {
27
32
  const weakest = weakestConfidence(...lineageConfidences);
28
33
  if (CONFIDENCE.indexOf(meta.confidence) > CONFIDENCE.indexOf(weakest)) {
package/marked.mjs CHANGED
@@ -18,7 +18,7 @@ const META_KEYS = [
18
18
  const OVERRIDE_KEYS = ["source", "confidence", "confidenceScore", "basis", "adapter"];
19
19
 
20
20
  export function mark(value, metaInput = {}) {
21
- return { value, ...makeMeta(metaInput) };
21
+ return Object.freeze({ value, ...makeMeta(metaInput) });
22
22
  }
23
23
 
24
24
  export function unwrap(marked) {
@@ -39,11 +39,15 @@ export function derive(inputs, fn, metaOverride = {}) {
39
39
  for (const key of OVERRIDE_KEYS) {
40
40
  if (key in metaOverride) safeOverride[key] = metaOverride[key];
41
41
  }
42
- const merged = {
42
+ // Route the override through makeMeta so derive is never weaker than the
43
+ // constructor: an out-of-range confidenceScore (or unrankable weakestSource)
44
+ // is dropped by the same validation, not stored raw. derivedFromMock is
45
+ // force-OR'd *before* the call, so taint still cannot be cleared (the one law).
46
+ const merged = makeMeta({
43
47
  ...combined,
44
48
  ...safeOverride,
45
49
  derivedFromMock:
46
50
  combined.derivedFromMock || Boolean(metaOverride.derivedFromMock),
47
- };
48
- return { value, ...merged };
51
+ });
52
+ return Object.freeze({ value, ...merged });
49
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plumb-line-provenance",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Conservative provenance/confidence/lineage envelope with a taint-propagation combination law. Mock or low-confidence data cannot launder itself clean.",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
package/provenance.mjs CHANGED
@@ -36,7 +36,15 @@ export function makeMeta({
36
36
  derivedFromMock === undefined
37
37
  ? source === "mock"
38
38
  : Boolean(derivedFromMock),
39
- lineage: Array.isArray(lineage) ? [...lineage] : [],
39
+ // Each meta owns a *frozen copy* of its lineage. Steps are cloned then
40
+ // frozen so (a) an envelope's recorded history can't be rewritten in place,
41
+ // and (b) a step shared across parent/child metas can't leak a mutation from
42
+ // one into the other — the audit trail an auditMeta() trusts stays intact.
43
+ lineage: Object.freeze(
44
+ (Array.isArray(lineage) ? lineage : []).map((s) =>
45
+ s && typeof s === "object" ? Object.freeze({ ...s }) : s,
46
+ ),
47
+ ),
40
48
  };
41
49
  // Optional numeric confidence — a finer-grained companion to the ordinal
42
50
  // `confidence`, never a replacement. Stored only when it is a valid score.
@@ -46,7 +54,7 @@ export function makeMeta({
46
54
  if (STATUS.includes(weakestSource)) meta.weakestSource = weakestSource;
47
55
  if (basis !== undefined) meta.basis = basis;
48
56
  if (adapter !== undefined) meta.adapter = adapter;
49
- return meta;
57
+ return Object.freeze(meta);
50
58
  }
51
59
 
52
60
  export function weakestConfidence(...levels) {
@@ -83,6 +91,8 @@ export function combineConfidenceScore(scores) {
83
91
  }
84
92
 
85
93
  let __stepCounter = 0;
94
+ // Test-only: exposed so test suites can isolate step counter state between runs.
95
+ // Not intended for production use; call sites should use combineProvenance/derive.
86
96
  export function __resetStepCounter() {
87
97
  __stepCounter = 0;
88
98
  }