diff --git a/plugins/repo-dreamer/skills/repository-skill-forge/SKILL.md b/plugins/repo-dreamer/skills/repository-skill-forge/SKILL.md index 8ee5233..c0da515 100644 --- a/plugins/repo-dreamer/skills/repository-skill-forge/SKILL.md +++ b/plugins/repo-dreamer/skills/repository-skill-forge/SKILL.md @@ -155,6 +155,10 @@ With `--fail-on-omission`, any irreducible discovery failure blocks. Every query success or failure must be recorded through `extraction-controller.py`. Never retry a query manually, alter controller SQL ad hoc, or continue after the controller returns a blocked state. +Pass each action's `description` unchanged to `session_store_sql`; it equals the +stable `actionId`. Never replace it with ordinal labels such as "first batch" +or "second batch". Associate the returned rows or error with that same action +object, and verify the action ID before recording the outcome. When `session_store_sql` returns query rows to the agent instead of accepting the controller's `outputPath`, use the packaged materializer. It matches the exact controller SQL in the current automation session's local `events.jsonl`, @@ -219,10 +223,12 @@ Discovery manifests contain exactly one action because pages and timeout partitions are cursor-dependent. Post-discovery manifests contain up to `maxConcurrentBatches` actions from different session batches. Execute those queries concurrently, but record each success or failure sequentially through -the controller using its action ID. Issued actions remain persisted until their -individual result is recorded, so recording one action cannot invalidate its -siblings. Record completed successes before failures, and terminal failures -last, so a blocked action cannot prevent sibling results from being persisted. +the controller using the action ID carried by that exact tool call. Do not map +parallel outcomes by completion order. Issued actions remain persisted until +their individual result is recorded, so recording one action cannot invalidate +its siblings. Record completed successes before failures, and terminal +failures last, so a blocked action cannot prevent sibling results from being +persisted. Never execute two actions for the same batch concurrently. The controller is the only writer of extraction state. diff --git a/plugins/repo-dreamer/skills/repository-skill-forge/scripts/extraction-controller.py b/plugins/repo-dreamer/skills/repository-skill-forge/scripts/extraction-controller.py index 654cbd2..00fbdad 100644 --- a/plugins/repo-dreamer/skills/repository-skill-forge/scripts/extraction-controller.py +++ b/plugins/repo-dreamer/skills/repository-skill-forge/scripts/extraction-controller.py @@ -258,6 +258,7 @@ def next_actions( ) actions = [{ "actionId": action_id, + "description": action_id, "kind": "discovery", "partitionId": partition["partitionId"], "limit": limits["discoveryPageSize"], @@ -291,6 +292,7 @@ def next_batch_action( action_id = f"metadata-{batch['batchId']}" return { "actionId": action_id, + "description": action_id, "kind": "metadata", "partitionId": partition["partitionId"], "batchId": batch["batchId"], @@ -306,6 +308,7 @@ def next_batch_action( action_id = paged_action_id("refs", batch, page) return { "actionId": action_id, + "description": action_id, "kind": "refs", "partitionId": partition["partitionId"], "batchId": batch["batchId"], @@ -324,6 +327,7 @@ def next_batch_action( action_id = paged_action_id("files", batch, page) return { "actionId": action_id, + "description": action_id, "kind": "files", "partitionId": partition["partitionId"], "batchId": batch["batchId"], @@ -343,6 +347,7 @@ def next_batch_action( action_id = paged_action_id("tools", batch, page) return { "actionId": action_id, + "description": action_id, "kind": "tool-calls", "partitionId": partition["partitionId"], "batchId": batch["batchId"], diff --git a/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_extraction_controller.py b/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_extraction_controller.py index a4e1965..198f484 100644 --- a/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_extraction_controller.py +++ b/plugins/repo-dreamer/skills/repository-skill-forge/tests/test_extraction_controller.py @@ -153,6 +153,7 @@ def test_artifact_failure_blocks_without_splitting_or_query_failure(self) -> Non state = controller.initialize(arguments(run_dir)) discovery = controller.next_action(state) assert discovery is not None + self.assertEqual(discovery["actionId"], discovery["description"]) write_rows( discovery["outputPath"], [ @@ -401,6 +402,12 @@ def test_tool_timeout_splits_only_tools_and_reuses_artifacts(self) -> None: for action in controller.next_actions(state, 3) ) ) + self.assertTrue( + all( + action["description"] == action["actionId"] + for action in controller.next_actions(state, 3) + ) + ) self.assertFalse( any( action["kind"] == "metadata"