Skip to content

question: no authoring surface for experiment-core specs (run/study/apparatus) — archival-only today #675

Closed

Description

@Brad-Edwards

Observation

SDL scenarios are authored as files (examples/scenarios/*.sdl.yaml), validated against a published schema, and — via agents + the MCP — are a first-class authoring surface.

The experiment-core contracts (ExperimentRunModel, ExperimentStudyModel, ExperimentApparatusContextModel, ExperimentRunAllocationPlanModel, capture spec, …) are archival / provenance OUTPUT objects emitted by a run (ExperimentRunModel docstring: "Archival provenance record for one execution"). The only in-repo instances are conformance fixtures; there is no authoring path — file or MCP tool — to specify an experiment (run count, seeds, red-variant selection, turn order, step count, termination, condition assignments) as an input artifact before execution.

Why it matters

A full CAGE-2 spec is scenario + experiment. The experiment half has no authoring home today, so "fully specify the CAGE-2 experiment" is not a supported workflow.

Question to examine

Should experiment specs get an authoring surface (agent/MCP first, optional authored file + published schema, discovery/validation test) analogous to SDL scenarios, so an experiment can be authored and validated pre-run rather than only captured post-run? (Agents + MCP are the intended authoring surface; the human CLI/GUI surfaces #85/#263 are support.)

Refs: #637 (REP-003), #85, #263.

Activity

  1. added
    in-progressAn agent is actively working this issue via /implement
    on Jul 8, 2026
  2. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    🛠️ Picked up by /implement — driver Claude Code, branch 675-experiment-authoring, 2026-07-08T00:37:48Z.

  3. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_codex_review — cycle 1 of 1 (pre-push) on issue #675 (branch 675-experiment-authoring)

    Core review

    Verdict: ship-with-fixes

    This is shaped correctly at the contract boundary: it introduces a separate pre-run authoring contract instead of weakening the archival run/study/apparatus-context records, reuses the existing ContractModel/schema bundle/manifest/fixture/test/MCP vocabulary, and keeps runtime execution out of scope. The design seam is the ExperimentSpecModel/ExperimentRunPlanModel layer, with model validators carrying the cross-field invariants JSON Schema cannot express; that fits the ADR direction and does not foreclose the obvious next variation where orchestration consumes the spec and emits archival records.

    Blocking findings (1):

    1. [one-off] Blocking factors can bypass declared-factor validation — implementations/python/packages/aces_contracts/contracts.py:5592
      The top-level invariant says every allocation blocking factor must resolve to a declared experiment-spec factor, but the validator only runs when self.factors is truthy. A spec with run_plan.allocation.blocking_factors: ['site'] and no factors map will pass Pydantic validation even though the formal spec and x-aces-invariant require rejection. Remove the and self.factors guard and compare against set(self.factors) unconditionally whenever an allocation exists; add an invalid fixture for the empty/missing factors case.

    Security review

    Verdict: ship

    This change is shaped as a contract and authoring-tool addition: it introduces a pre-run experiment-spec surface beside the existing archival experiment-core outputs, wires it into schema publication, examples, MCP discovery, and conformance tests, and keeps execution/orchestration out of scope. The main security-relevant seam is the MCP authoring boundary, where untrusted YAML enters validation and where example retrieval could have become file access; the diff uses safe YAML loading, a size cap on MCP input, and an allowlisted example map rather than user-controlled paths. I do not see a concrete exploitable weakening of an existing security control.

    No blocking findings.

  4. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_codex_review pre-push cycle 1 of 1 complete for issue #675 on branch '675-experiment-authoring'. Posted by the MCP server to enforce the pre-push hard-cap-1 contract (issues #796, #804, #906). Do not edit or delete — used by the next gc_codex_review (uncommitted) invocation to count cycles.

  5. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Review decision record — codex cycle 1 (issue #675)

    Reviewer: codex
    Cycle: 1

    Architectural read:

    Core reviewer: This is shaped correctly at the contract boundary: it introduces a separate pre-run authoring contract instead of weakening the archival run/study/apparatus-context records, reuses the existing ContractModel/schema bundle/manifest/fixture/test/MCP vocabulary, and keeps runtime execution out of scope. The design seam is the ExperimentSpecModel/ExperimentRunPlanModel layer, with model validators carrying the cross-field invariants JSON Schema cannot express; that fits the ADR direction and does not foreclose the obvious next variation where orchestration consumes the spec and emits archival records.

    Security reviewer: This change is shaped as a contract and authoring-tool addition: it introduces a pre-run experiment-spec surface beside the existing archival experiment-core outputs, wires it into schema publication, examples, MCP discovery, and conformance tests, and keeps execution/orchestration out of scope. The main security-relevant seam is the MCP authoring boundary, where untrusted YAML enters validation and where example retrieval could have become file access; the diff uses safe YAML loading, a size cap on MCP input, and an allowlisted example map rather than user-controlled paths. I do not see a concrete exploitable weakening of an existing security control.

    Blocking findings: 1

    Finding 1 — one-off

    • ID: F1
    • Title: [core] Blocking factors can bypass declared-factor validation
    • Location: implementations/python/packages/aces_contracts/contracts.py:5592
    • Decision: fix
    • Rationale: The top-level invariant says every allocation blocking factor must resolve to a declared experiment-spec factor, but the validator only runs when self.factors is truthy. A spec with run_plan.allocation.blocking_factors: ['site'] and no…
  6. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_test_quality_review cycle 1 of 1 — issue #675

    Reviewer: test-quality (claude-sonnet-5 via gc_test_quality_review)
    Branch: 675-experiment-authoring
    Cycle: 1 / 1
    Findings: 0 (clean run)

  7. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_test_quality_review cycle 1 of 1 complete for issue #675 on branch '675-experiment-authoring'. Posted by the MCP server to enforce the gc_test_quality_review hard-cap-1 contract (issue #884 follow-up, default lowered in #906). Do not edit or delete — used by the next gc_test_quality_review invocation to count cycles.

  8. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Review decision record — test-quality cycle 1 (issue #675)

    Reviewer: test-quality
    Cycle: 1

    Architectural read:

    This diff extends an already-well-factored, data-driven contract-test harness rather than hand-rolling new test logic: the new experiment-authoring-input-v1 contract slots into existing generic loops (EXPERIMENT_CORE_FIXTURE_MODELS, the schema/model fixture-rejection loop, the closed-world-contract loop, schema_bundle() vs published-JSON diff) and into the CorpusEntry-based published-schema conformance harness in test_example_schema_conformance.py. The actual new, bespoke test code is small: one dedicated unit test (test_experiment_authoring_input_rejects_undeclared_blocking_factor) that correctly demonstrates the schema-valid/model-invalid split for an x-aces-invariant, plus two new invalid fixtures (run-plan-both-allocation-and-count.json, run-plan-neither-allocation-nor-count.json) that are cleanly isolated — each violates exactly the oneOf(allocation, target_run_count) invariant and nothing else — and get exercised automatically by the pre-existing generic fixture-rejection loop (asserts both a JSON-Schema error and a ValidationError, so either the oneOf schema clause or the _validate_run_plan model validator being weakened would be caught). The two new .exp.yaml examples exercise both branches of that oneOf (allocation-based and target_run_count-based) through the real publication-serialization path, which is genuine regression coverage, not a rubber stamp. paths.py's one-line EXPERIMENTS_DIR addition is inert plumbing. This is shaped correctly — extend-by-data rather than extend-by-new-test-function is the right seam here, and I would ship it.

    Blocking findings: 0 (clean run)

  9. added a commit that references this issue on Jul 8, 2026
    3026c56
  10. Brad-Edwards commented on Jul 8, 2026

    @Brad-Edwards
    CollaboratorAuthor

    ✅ Ready for review — Phase D complete (PR #711)

    All automated gates are green; the only remaining step is your review + merge of PR #711.

    What shipped: experiment-authoring-input-v1 (ExperimentSpecModel) — a pre-run experiment specification (task binding + run plan: seeds, episode controls, red-variant selection, condition allocation) that answers this issue's gap. It is a separate input contract that references the archival experiment-core outputs rather than weakening them, mirroring sdl-authoring-input-v1 ↔ instantiated-scenario-v1. Includes a loader, MCP authoring tools (experiment_scaffold/experiment_validate/experiment_get_example), worked examples/experiments/*.exp.yaml, fixtures, and a discovery test.

    Decision record: ADR-074 (accepted) decides the surface; ADR-055 and ADR-069 amended (cross-reference rows; pins unchanged). ADR-055 anticipated exactly this ("explicit draft/authoring surface … rather than weakening these archival contracts"), and it gives ADR-069's REP-003 a pre-run home for CAGE-2 execution-control facts.

    Gates:

    • CI: green (full nox verify, including wheel/corpus packaging).
    • SonarCloud quality gate: OK — new coverage 96.8%, new violations 0, all ratings A.
    • Pre-push reviews: codex (1 finding — blocking-factor validator guard — fixed + verified) and test-quality (clean). Decision records posted above.

    Run type: requirement-free (this is a question issue with no requirements in scope). No requirement transition or issue→requirement link applies; the change governs a new experiment-core contract, recorded in ADR-074 and the experiment-core formal spec.

    Merge PR #711 when ready; I'll run Phase E (final report + issue close) after the merge.

  11. added a commit that references this issue on Jul 9, 2026
    ac5f697
  12. Brad-Edwards commented on Jul 9, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Governance update: created EXP-736 — Experiment Authoring Input Specification (ACTIVE) to govern the new contract, with full IMPLEMENTS/TESTS traceability (contract/loader/MCP source + published schema + test modules + ADR-074 + formal spec); check_requirement_governance.py passes. Also filed #712 to add a detection for any published contract not tied to a requirement.

  13. Brad-Edwards commented on Jul 10, 2026

    @Brad-Edwards
    CollaboratorAuthor

    ✅ Phase E complete — merged & reconciled

    PR #711 merged into dev (merge commit ac5f697).

    Outcome (plain English): ACES now has a pre-run authoring surface for experiments. Previously the experiment-core contracts were archival outputs only — you could record what a run produced, but not specify an experiment (seeds, turn order/step count/termination, red-variant selection, condition allocation) before running it. experiment-authoring-input-v1 closes that gap with an agent/MCP-first authoring surface (scaffold → validate → get-example), a published schema, worked examples, and a discovery test — the experiment analogue of SDL scenario authoring.

    Requirement: EXP-736 — Experiment Authoring Input Specification (ACTIVE, wave 2).

    Traceability reconciled: EXP-736 carries IMPLEMENTS links to the changed contract/loader/MCP source + the published schema, TESTS links to the four changed test modules, and DOCUMENTS links to ADR-074 and the experiment-core formal spec. Verified locally via check_requirement_governance.py (exit 0). (Note: gc_assert_traceability_reconciled / gc_post_final_report could not post their markers on this multi-project backend — gc_assert_traceability_reconciled returns "Multiple projects exist. Specify a 'project' parameter" and exposes no project param — so this is the durable reconciliation record in lieu of the tool-posted marker.)

    Gates at merge: CI green (full nox verify); SonarCloud quality gate OK (new coverage 96.8%, new violations 0, ratings A); pre-push reviews codex (1 finding fixed) + test-quality (clean).

    Decision record: ADR-074 (accepted); ADR-055 and ADR-069 amended.

    Follow-up: #712 — add a detection that every published contract traces to a governing requirement.

  14. removed
    in-progressAn agent is actively working this issue via /implement
    on Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions