Skip to content

feat: end-to-end task→workflow→outer-loop creation pipeline (#1478) - #1481

Draft
colehurwitz wants to merge 8 commits into
factory/run-3110c50afrom
factory/run-71a91bd3
Draft

feat: end-to-end task→workflow→outer-loop creation pipeline (#1478)#1481
colehurwitz wants to merge 8 commits into
factory/run-3110c50afrom
factory/run-71a91bd3

Conversation

@colehurwitz

@colehurwitz colehurwitz commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Closes #1478

Changes

Phase 1: Shared resolve_task() + --task CLI flag

  • Added resolve_task() 3-step resolver in factory/task.py: TOML file → Python file → module:Class import string
  • Added _load_task_from_python_file() helper using importlib introspection
  • Added --task flag to factory outer-loop calibrate and factory outer-loop evaluate commands
  • Wired task resolution through SwarmConfig.set_task() for outer-loop integration
  • Updated docs/outer-loop.md with Task Discovery documentation
  • 12 tests covering all resolution paths, error cases, and equivalence

Phase 2: task-setup workflow mode (W₁₄)

  • Added task_setup_workflow() graph definition: fork(researcher_domain, researcher_verification) → join → CEO gate → strategist → user gate → builder → FnNode(validate_task) → archivist (10 nodes, 12 edges)
  • Registered in _get_builtin_registry() and WORKFLOW_META
  • Added "task-setup" to CEO_MODES in _helpers.py
  • Added mode detection line in ceo.md prompt
  • SKILL.md auto-generated (gitignored, regenerated by skill_cache)

Phase 3: --task flag for create mode + OptKnob auto-generation

  • Added _build_task_aware_directive() in _task_builder.py using same directive-injection pattern as Plugin Package and Update Existing Mode
  • Added --task argument to CEO parser in _parser_groups.py
  • Threaded task_ref through ceo.py_ceo_helpers.py_task_builder.py
  • Auto-generates OptKnob mechanical derivation table: AgentNode.role→model, timeout→threshold, prompt_template→prompt
  • Added "task-setup" mode suffix handling
  • 18 tests covering directive injection, OptKnob tables, resolution failures, and integration

Phase 4: ScoringContract.threshold + domain-level OptKnobs

  • Added threshold: float | None = None field to ScoringContract
  • Updated TaskDefinition.from_toml() to parse threshold from TOML scoring section
  • Extended _build_task_aware_directive() to emit domain-level OptKnob instructions based on threshold presence
  • Tests for threshold parsing, default values, and domain knob generation

Phase 5: DataNode OptKnob integration (rebased onto PR #1483)

  • Rebased onto PR feat: DataNode graph primitive — first-class data loading in workflows #1483's branch (factory/run-3110c50a) — inherits DataNode, main, and review fixes
  • Added ### DataNode OptKnob Auto-Generation section to _build_task_aware_directive()
  • DataNode mechanical derivation rules (threshold knobs only):
    • parallelism → threshold knob, bounds [1, current, current*2, 8], expandable=False
    • limit (when set) → threshold knob, bounds [limit//2, limit, limit*2], expandable=True
    • max_items → threshold knob, bounds [100, 250, 500, 1000], expandable=True
  • Explicit prohibition of topology knobs for DataNode.split/shuffle
  • Each knob uses OptKnob.description field (from PR workflow: make Workflow.to_dict() deterministic; add OptKnob.description #1487)
  • 8 new tests for DataNode OptKnob derivation rules

Base branch: factory/run-3110c50a (PR #1483). When PR #1483 merges to main, this PR automatically retargets to main.

Test results

  • 1206+ passed (pre-existing k8s/container test failures excluded — no oc/kubectl in CI environment)

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Sentrux Quality Report

Absolute

Scanning ....
[scan] git ls-files: 653 total, 639 kept, 14 dropped (ext:14, meta:0, big:0)
[build_project_map] 639 files, 108 unique dirs, 100 cache misses, 4.9ms
[resolve] 1305 resolved, 1684 unresolved (of 2989 total specs)
[resolve_imports] project_map 5.1ms, suffix_idx 1.1ms, suffix_resolve 15.3ms, total 21.4ms
[build_graphs] 639 files | maps 2.5ms, imports 21.6ms, calls+inherit 5.6ms, total 29.8ms | 1304 import, 10576 call, 4 inherit edges
sentrux check — 3 rules checked

Quality: 4414

✗ [Error] max_cc: 9 function(s) exceed max cyclomatic complexity of 30
    factory/workflow/executor.py:_execute_data (cc=53)
    factory/outer_loop/reflector.py:_extract_eval_patterns (cc=46)
    factory/cli/_ceo_helpers.py:_validate_ceo_flags (cc=43)
    factory/cli/_ceo_helpers.py:_execute_ceo (cc=43)
    factory/outer_loop/mutations.py:_try_mutation (cc=40)
    factory/cli/_task_builder.py:_build_ceo_task (cc=34)
    examples/chess_evolve.py:main (cc=33)
    factory/outer_loop/reflector.py:_llm_reflect (cc=32)
    factory/outer_loop/mutations.py:validate_and_repair (cc=31)

✗ 1 violation(s) found

Diff (vs base branch)

Scanning ....
[scan] git ls-files: 653 total, 639 kept, 14 dropped (ext:14, meta:0, big:0)
[build_project_map] 639 files, 108 unique dirs, 100 cache misses, 4.9ms
[resolve] 1305 resolved, 1684 unresolved (of 2989 total specs)
[resolve_imports] project_map 5.1ms, suffix_idx 1.2ms, suffix_resolve 15.2ms, total 21.5ms
[build_graphs] 639 files | maps 2.7ms, imports 21.7ms, calls+inherit 7.9ms, total 32.4ms | 1304 import, 10576 call, 4 inherit edges
sentrux gate — structural regression check

Quality:      4415 -> 4414
Coupling:     0.81 → 0.81
Cycles:       3 → 3
God files:    3 → 3

Distance from Main Sequence: 0.35

✓ No degradation detected

colehurwitz and others added 7 commits September 11, 2026 16:12
…r loop (#1478)

Phase 1 of the task→workflow→outer-loop creation pipeline.

- Add resolve_task() to factory/task.py: 3-step resolution (TOML file →
  Python file → module:Class string) with project-relative path support
- Add --task flag to both calibrate and evaluate subcommands in
  factory/cli/outer_loop.py, using the shared resolver (one helper, not
  two — lesson from #1449)
- Keep --task-module as a functional escape hatch
- Resolved tasks attach via set_task() for highest precedence in
  SwarmConfig.get_task()
- 12 new tests covering all resolution paths and equivalence
- Updated docs/outer-loop.md with --task documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 2 of the task→workflow→outer-loop creation pipeline.

- Add task_setup_workflow() to factory/workflow/definitions.py:
  fork(researcher_domain, researcher_verification) → join → CEO gate →
  strategist → user gate → builder → FnNode(validate) → archivist
- Register in _get_builtin_registry() for automatic discovery
- Add WORKFLOW_META entry in skill_export.py for SKILL.md generation
- Add 'task-setup' to CEO_MODES in _helpers.py
- Add mode suffix in _task_builder.py for CEO task string
- Add mode detection line in ceo.md prompt
- SKILL.md auto-generates via skill_cache (139 lines)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
)

Phase 3 of the task→workflow→outer-loop creation pipeline.

- Add --task CLI flag to factory ceo parser for task-aware create mode
- Add _build_task_aware_directive() in _task_builder.py: resolves the
  task, extracts scoring contract/constraints, injects directive section
  with OptKnob mechanical derivation table (same directive-injection
  pattern as Plugin Package and Update Existing Mode extensions)
- Wire --task through cmd_ceo → _execute_ceo → _build_ceo_task
- Update create_workflow() strategist prompt to handle Task-Aware
  directive and include OptKnob generation instructions
- Update create_workflow() builder prompt with knob_values/knob_bounds
  and compose.py validate_composition() post-build gate
- 12 new tests for directive injection and task-setup workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…on (#1478)

Phase 4 of the task→workflow→outer-loop creation pipeline.

- Add optional threshold: float | None = None field to ScoringContract
- Parse threshold from TOML [scoring] section via from_toml()
- Add domain-level OptKnob suggestion instructions to the task-aware
  create mode directive: CEO-gated, Strategist-proposed, restricted to
  prompt/model/threshold kinds (never topology), expandable=False by
  default
- Use ScoringContract.threshold for threshold-kind domain knobs when
  scoring.method is json with a numeric metric_path
- 6 new tests for threshold field and domain-level knob directives

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Relative path 'benchmarks/configs/chess-evolve.toml' breaks when the
working directory changes due to test ordering/isolation. Resolve the
path relative to the repo root via Path(__file__).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…1478)

Add a '### DataNode OptKnob Auto-Generation' section to
_build_task_aware_directive() with mechanical derivation rules for
DataNode fields:
- parallelism → threshold knob, bounds [1, current, current*2, 8]
- limit (when set) → threshold knob, bounds [limit//2, limit, limit*2]
- max_items → threshold knob, bounds [100, 250, 500, 1000]

Explicitly prohibits topology knobs for split/shuffle fields.
Includes OptKnob.description for each knob (uses PR #1487's field).

8 new tests covering DataNode section presence, individual field
derivation rules, kind validation, expandable flags, and topology
exclusion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@colehurwitz
colehurwitz changed the base branch from main to factory/run-3110c50a September 11, 2026 16:20
…count

- Add _deep_qa_subgraph() to task_setup_workflow(): fork_qa →
  [health_checker, code_reviewer, adversarial_tester] → join_qa →
  gate_qa between builder and validate_task
- Update registry count assertion from 16 to 17 in test_spec_generate.py
- Regenerate workflow-task-setup/SKILL.md and SKILL.annotations.yaml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: end-to-end task→workflow→outer-loop creation pipeline

2 participants