feat: add SCI report output method - #1361
Open
davidberenstein1957 wants to merge 1 commit into
Open
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1361 +/- ##
==========================================
+ Coverage 91.43% 91.59% +0.15%
==========================================
Files 49 50 +1
Lines 5057 5151 +94
==========================================
+ Hits 4624 4718 +94
Misses 433 433 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
davidberenstein1957
marked this pull request as ready for review
August 12, 2026 19:14
davidberenstein1957
force-pushed
the
feat/sci-report-output
branch
from
August 19, 2026 09:08
3fd5690 to
43edc9f
Compare
davidberenstein1957
force-pushed
the
feat/sci-report-output
branch
from
August 19, 2026 14:30
080791e to
a21d8e3
Compare
Emit an ISO/IEC 21031 Software Carbon Intensity report alongside the existing output methods. E and I come from the measured run; R and M are user declarations and are reported as undeclared rather than guessed, so a report never invents numbers the run cannot support. Embodied carbon (M) is apportioned across tasks by each task's share of the run duration. Handing every task the same declared M made a 5-task run report the device's full embodied carbon 5 times. The split is exhaustive: per-task figures sum back to the run-level report, and `M_source` records the share applied. Per-task SCI is reported as `sciShare`, not as a per-unit rate. Failure handling is narrow rather than broad: an unreadable `sci_context_file` degrades instead of failing the run, while unrelated exceptions while writing a report are no longer swallowed. Context dataclasses are built straight from the JSON keys, with the documented camelCase `gCO2e` key normalised so existing context files keep working. Docs cover the formula, the term declarations, the config keys and a sample report, and note that `output_methods = csv,sci` alone can never produce a non-null sci unless the context file hardcodes `functionalUnit.count`. The constructor, `from_file` and context-file walkthrough live in `examples/sci_output.py`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
davidberenstein1957
force-pushed
the
feat/sci-report-output
branch
from
August 20, 2026 06:14
a21d8e3 to
9474fda
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an SCI (Software Carbon Intensity, ISO/IEC 21031:2024) output method, following the same pattern as the existing BoAmps exporter.
What it adds
codecarbon/output_methods/sci.py, a single module holding the two declaration dataclasses, the pure mapping function, and the handler:FunctionalUnit/EmbodiedDeclaration— theRandMterms, which only the user can supply.map_emissions_to_sci(data, ...)— pure, no I/O.Iis derived asemissions * 1000 / energy_consumedrather than recomputed, so the report agrees with the CSV by construction and inherits the cloud-region, PUE and country/region handling already applied upstream.SCIOutput(BaseOutput)—out()writessci_report_<run_id>.json,task_out()writessci_report_tasks_<run_id>.jsonwith one entry per task,live_out()is a documented no-op because the report is final rather than incremental.OutputMethod.SCIregistered in_init_output_methods, reading an optionalsci_context_filefrom the usual config hierarchy.Two honesty rules, both tested:
Rdeclared → the report is still written, withsci: nulland astatusfield explaining why, instead of dividing by zero or assumingR = 1.Mdeclared →M_gCO2e: 0withM_source: "not declared", so a reader can see the report covers only the operational half.User-facing surface
sci.set_functional_unit_count(n)for the common case where the count is only known at the end;SCIOutput.from_file("sci_context.json")for the declarative path;output_methods = csv,sciplussci_context_filein.codecarbon.config.Docs: a new SCI section in
docs/reference/output.md(including a sample report), a row indocs/how-to/examples.md, and a runnableexamples/sci_output.py. No new dependencies.Verification
uv run pytest tests/test_sci_output.py -q— 14 tests covering the formula, provenance assembly, the undeclared-Rand undeclared-Mbranches, zero-energy, the handler and its task path, and context-file loading (valid, missing, malformed).black --checkandruff checkwere run scoped to the touched files; the remaining ruff hits are the sameOptional/List/dict()style the surrounding modules already use, so the new code matches its neighbours.Deliberately left out
EmbodiedProfiletracker parameter, no bundled hardware table, no cloud per-instance figures. CodeCarbon has no defensible manufacturing data, and an uncitedMin a compliance report is worse than a blank one.Mis user-declared or explicitly undeclared.emissionsmeans. Existing consumers are untouched.Closes #1353
🤖 Generated with Claude Code
Review follow-up: embodied carbon in task reports
task_out()passed the same declaredMto every task, so a run with 5 tasks reported the device's full embodied carbon 5 times, and each per-tasksciincluded 100% of it — a wrong number in a document framed as ISO/IEC 21031 output.Mis now apportioned by each task's share of the run duration. Chosen over omittingMfrom task reports because the split is exhaustive:Ris already the run-level count, so with an apportionedMthe per-task figures sum back to the run-level report instead of quietly dropping half the accounting.M_sourcerecords the share applied, e.g."vendor LCA; apportioned by duration (25.0% of the run)".Tested by
test_task_out_apportions_embodied_by_duration(unequal durations: asserts the 10/30 split of a declared 40 gCO2e and that the shares sum back to 40), plus the undeclared-Mand zero-duration branches.Also documented in
docs/reference/output.mdthat the configuration-only path (output_methods = csv,sci) can never produce a non-nullsciunlessfunctionalUnit.countis hardcoded in the context file, sinceset_functional_unit_count()needs a reference to a handler the tracker owns.