Repository navigation
Let tasks record task metadata through TaskContext - #29
Merged
Merged
Conversation
TaskContext gains task_metadata, a fresh dict per trial that a context-aware task writes during execution. Mic snapshots it when the task returns, raises, times out or is cancelled, and records it as the trial's task_metadata, shallow-merged under any returned TaskResult metadata. Failed and cancelled trials keep it, so evidence such as a model-call log survives the failure it explains; invalid metadata on a failed trial appends a schema error after the original one. Bumps the version to 0.4.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Executive summary
mic.TaskContextgainstask_metadata, a mutable dict that is fresh for every trial. A context-aware task writes to it while it runs. Mic records it as the trial'stask_metadata, shallow-merged under any returnedTaskResult.metadata. It is also recorded when the trial fails, times out or is cancelled. The version goes to 0.4.0.Why
In 0.3.0, a task can only emit metadata by returning a
TaskResult, and writes toctx.metadataare thrown away. Per-trial setup and teardown, like resetting a failure counter and attaching a model-call log, then needs a callback-taking runner wrapped around mic: a second framework. A failed trial also records no task metadata at all, yet that is the trial whose call log explains what went wrong. The consumer is the intent2auth microeval harness (Tenetgraph/intent2auth#910, TEN-1196). The design was approved in the handoff doc.Design and implementation
src/mic/models.py: addstask_metadata: JsonObject = field(default_factory=dict)to the frozenTaskContext. Reassigning it raisesFrozenInstanceError; mutating it works. Because the field has a default,TaskContext(case_id, trial, metadata)still constructs.src/mic/_runtime/case.py,run_case:{**ctx.task_metadata, **TaskResult.metadata}goes through the existingjson_object(..., "$.task_metadata"). That call is both the snapshot and the validation, and it feeds the existing merge with dataset metadata.TaskResultkeys win.TaskResult, the field stays absent, so existing artifacts are unchanged.exceptblock calls a nestedsalvage_task_metadata()after the existingrecord_error. It records the snapshot without changing the status orerrors[0]. If the snapshot does not serialize, it appends oneschema-phase error instead.record_errortakes an optional explicit phase for that.returnedflag: set when the task returns. From then on the success path owns the metadata. Without the flag, invalid metadata on the success path would be salvaged a second time and log a duplicate error.docs/api.md: the contract, snapshot timing, failure semantics, and the three-level merge order (dataset, thenctx.task_metadata, thenTaskResult).docs/artifacts.md:task_metadatanow also appears on failed, timed-out and cancelled trials.task-contextsnippet now writesctx.task_metadata.version = "0.4.0"anduv lock.The handoff doc said the schema error on a failed trial would name
$.task_metadata. Mic's error records deliberately hold only phase, type and a generic message, so the path is not persisted. The tests check phase and type instead.Verification and confidence
Main risks: data loss or masking on failure paths, cross-trial leakage, duplicate errors, and changes to artifacts that don't use the feature.
tests/runtime/test_task_context_metadata.pyhas 18 cases and runs real evaluations throughmic.run/mic.arun. It covers each behaviour row from the design:TaskResultprecedence, plus an emptyTaskResultstill recording{};gatherchildren writing the same dict;TrialFinishedand JSONL artifacts agreeing and validating against the v4 schemas;With the runtime change stashed, 17 of the 18 fail. The one that still passes is the "absent" case, which is meant to hold either way.
README acceptance test: now asserts that the
task-contextsnippet records{"model": "jev-latest"}on all six trials. That includes the run where every trial fails.Typing fixtures:
positive.pywrites and.updates the dict;negative.pyrejects reassignment.verify_typing.pypasses, rejecting all 23 deliberate mistakes.scripts/verify.py: tests, coverage gates, strict pyright, authoring typing, lint and format all pass.uv buildandscripts/verify_packaging.pypass.Compatibility and risks
task_metadataalready exists in common-v4 as an optional field on any trial. Runs that don't use the feature produce the same artifacts as before.task_failed. This is the existing rule for invalidTaskResultmetadata, applied to the new field.