Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions plugins/repo-dreamer/skills/repository-skill-forge/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,13 @@ Cluster eligible candidates by repository subject. Assign a stable
Assign deterministic non-negative `rank` values.

Validate and independently review every proposal. Compare it with repository
skills and the complete Forge PR catalog. Every promoted proposal body must
contain the exact marker produced by:
skills and the complete Forge PR catalog. Store each promoted proposal's marker
with that proposal rather than in a shared run-level file:

```bash
python3 "$SKILL_DIR/scripts/proposal-ledger.py" marker \
--proposal "$PROPOSAL_JSON" \
--out "$RUN_DIR/proposal-marker.md"
--out "$RUN_DIR/proposals/$PROPOSAL_KEY/proposal-marker.md"
```

The marker is persistent PR metadata. Do not edit or remove it when updating a
Expand All @@ -317,6 +317,10 @@ python3 "$SKILL_DIR/scripts/proposal-ledger.py" select \
--out "$RUN_DIR/proposal-selection.json"
```

The selected entry contains `selection.marker`, generated directly from the
selected proposal. Pass that exact value unchanged in the PR body; never use a
shared marker file or a marker belonging to another proposal.

Reconciliation rules:

- same `proposalKey` and `proposalVersion` in any open, closed, or merged PR:
Expand Down Expand Up @@ -346,6 +350,11 @@ TARGET_SHA="$(

If no proposal is selected, missing target identity must not block the run.
If selected and target identity cannot be resolved, block before publication.
For a create action, stage only the selected proposal. Before copying, reject
symlinks in its source tree, every existing destination path component, and
every existing destination entry mapped from a selected source entry. Compare
the pending checkout paths with the exact selected source-file manifest and
block on any additional path.
After publication, apply `skills-forge` when the label exists and the available
GitHub tools support it. Label lookup, creation, or application failure is
non-blocking because the persistent marker is the authoritative Forge identity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ proposal manifest's `candidateIds` array.
Set `proposalVersion` from the complete proposal, including the sorted candidate
IDs and versions plus the generated skill content, so materially changed
evidence or instructions produce a new version.
The pull request body must contain the exact machine-readable marker generated
by `proposal-ledger.py marker`. Keep that marker unchanged for the lifetime of
the PR; it is the stateless workflow's cross-run identity and rejection memory.
Store the machine-readable marker generated by `proposal-ledger.py marker`
inside this proposal's run-local directory, never in a shared marker file.
Publication must use the exact `selection.marker` generated from the selected
proposal and keep it unchanged for the lifetime of the PR; it is the stateless
workflow's cross-run identity and rejection memory.

Copy the extraction coverage into the proposal manifest. Use
`extraction.status: complete` for complete runs. For partial runs include
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1013,11 +1013,15 @@ def record_failure(
recovered = split_partition(state, partition, reason)
else:
batch = find_batch(partition, action["batchId"])
recovered = (
split_tool_batch(state, partition, batch, reason)
if batch["status"] == "tools"
else split_batch(state, partition, batch, reason)
)
if batch["status"] == "tools":
recovered = split_tool_batch(
state,
partition,
batch,
reason,
) or split_batch(state, partition, batch, reason)
else:
recovered = split_batch(state, partition, batch, reason)
if recovered:
state["handledActionIds"].append(action["actionId"])
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ def select(
),
None,
)
if selected is not None:
selected = {
**selected,
"marker": render_marker(selected["proposal"]),
}
return {
"selection": selected,
"mutationCount": 1 if selected else 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,35 @@ def test_handoff_failure_splits_without_artifact_blocker(self) -> None:
self.assertIn(action["actionId"], state["handledActionIds"])
self.assertEqual(1, state["workCounters"]["failedQueries"])

def test_single_session_tool_overflow_reduces_page_size(self) -> None:
with tempfile.TemporaryDirectory() as run_dir:
state = controller.initialize(arguments(run_dir, tool_page_size=8))
partition = state["partitions"][0]
batch = controller.make_batches(["session-1"], 1, 8)[0]
batch["status"] = "tools"
partition["batches"] = [batch]
action = {
"actionId": "tools-batch-1",
"kind": "tool-calls",
"partitionId": partition["partitionId"],
"batchId": batch["batchId"],
}
state["issuedActions"] = [action]

controller.record_failure(
state,
action,
"row_limit_exceeded",
count_attempt=False,
allow_retry=False,
)

self.assertEqual("running", state["status"])
self.assertEqual(4, batch["pageSize"])
self.assertEqual([], state["blockers"])
self.assertEqual([], state["omittedUnits"])
self.assertEqual("reduce_evidence_page", state["retryHistory"][-1]["kind"])

def test_cli_uses_fast_safe_defaults(self) -> None:
with tempfile.TemporaryDirectory() as run_dir:
state_path = Path(run_dir) / "state.json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ def test_selection_allows_at_most_one_mutation(self) -> None:

self.assertEqual(1, result["mutationCount"])
self.assertEqual("first", result["selection"]["proposal"]["proposalKey"])
self.assertEqual(
ledger.render_marker(proposal(key="first", rank=1)),
result["selection"]["marker"],
)

def test_selection_rejects_invalid_rank(self) -> None:
invalid = proposal()
Expand Down