Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/profiler-compare.js
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@
engine: 'js',
dataset_hash_a: hashA.digest,
dataset_hash_b: hashB.digest,
params: Object.assign({}, currentOpts),
params: E.publicParams(currentOpts),
overrides: Object.assign({}, currentOverrides)
};
if (hashA.note !== null) provenance.dataset_hash_a_note = hashA.note;
Expand Down
22 changes: 22 additions & 0 deletions assets/profiler-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@
validateOpts(o);
return o;
}

// Parsed data structures that carry their own provenance field elsewhere -
// echoing them into params would be noise. Mirrors
// faircode.provenance._OPAQUE_PARAMS.
var OPAQUE_PARAMS = { reference: 1 };

// The resolved knobs as actually applied (defaults included), minus the
// opaque parsed structures, key-sorted. Mirrors
// faircode.provenance.public_params(faircode.profiler._resolve_opts(opts)),
// so a web-profiler export's provenance.params matches the CLI/MCP path
// even when the user never touched a threshold input (#490).
function publicParams(opts) {
var resolved = resolveOpts(opts);
var out = {};
Object.keys(resolved).sort().forEach(function (k) {
if (!OPAQUE_PARAMS[k]) out[k] = resolved[k];
});
return out;
}
// Comparison / drift (SPEC section 8)
var PSI_EPSILON = 0.0001;
var MISSING_DRIFT_FLAG = 0.05;
Expand Down Expand Up @@ -1088,6 +1107,9 @@
sniffDelimiter: sniffDelimiter,
profile: profile, compare: compare,
parseReference: parseReference,
// publicParams: resolved knobs for an export's
// provenance.params, matching the Python path (#490).
publicParams: publicParams,
// Exposed so the Profile/Compare threshold-input
// placeholders (issue #377) can be sourced from
// this single source of truth instead of a
Expand Down
2 changes: 1 addition & 1 deletion assets/profiler-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@
faircode_version: FAIRCODE_VERSION,
engine: 'js',
dataset_hash: hash.digest,
params: Object.assign({}, currentOpts),
params: E.publicParams(currentOpts),
overrides: Object.assign({}, currentOverrides)
};

Expand Down
25 changes: 25 additions & 0 deletions tests/test_js_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,31 @@ def test_python_js_na_token_parity_on_literal_na_and_none(tmp_path):
assert status["missing_pct"] == 0.2


def test_python_js_public_params_parity_for_a_defaulted_run():
"""A web-profiler export with no threshold ever touched must still record
the 7 resolved defaults in provenance.params, matching the CLI/MCP path -
E.publicParams({}) mirrors provenance.public_params(_resolve_opts(None)) (#490)."""
from faircode.profiler import _resolve_opts
from faircode.provenance import public_params

expected = public_params(_resolve_opts(None))

script = (
"require(process.argv[1]);"
"process.stdout.write(JSON.stringify(globalThis.FairCodeProfiler.publicParams({})));"
)
completed = subprocess.run(
["node", "-e", script, str(REPO_ROOT / "assets" / "profiler-engine.js")],
capture_output=True, text=True, encoding="utf-8", check=True,
)
assert json.loads(completed.stdout) == expected
assert set(expected) == {
"cross", "imbalance_flag", "intersection_floor", "min_group_size",
"min_share", "missing_flag", "reference_flag",
}
assert "reference" not in expected


def test_python_js_profiler_parity_with_overrides_cross_and_thresholds(tmp_path):
"""Non-default options - --map/--cross/--reference/thresholds - only ever
had cross-engine parity coverage for their default-off path (issue #376).
Expand Down