simplicio-loop 3.22.6__tar.gz → 3.23.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simplicio_loop-3.22.6/simplicio_loop.egg-info → simplicio_loop-3.23.0}/PKG-INFO +2 -2
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/pyproject.toml +2 -2
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/SKILL.md +27 -4
- {simplicio_loop-3.22.6/simplicio_loop/_bundle/skills/simplicio-tasks → simplicio_loop-3.23.0/simplicio_loop/_bundle/skills/simplicio-loop}/references/extension-points.md +5 -4
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/orchestration.md +5 -1
- {simplicio_loop-3.22.6/simplicio_loop/_bundle/skills/simplicio-loop → simplicio_loop-3.23.0/simplicio_loop/_bundle/skills/simplicio-tasks}/references/extension-points.md +5 -4
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/orchestration.md +5 -1
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0/simplicio_loop.egg-info}/PKG-INFO +2 -2
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop.egg-info/SOURCES.txt +1 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop.egg-info/requires.txt +1 -1
- simplicio_loop-3.23.0/tests/test_task_backlog.py +225 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_worker_cli_contract.py +1 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_worker_selftests.py +7 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/LICENSE +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/MANIFEST.in +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/PYPI.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/README.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/setup.cfg +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/__init__.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/README.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/action_gate.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/hooks.claude.json +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/hooks.json +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/loop_capture.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/loop_stop.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/orient_clamp.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/orient_rewrite.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/pre-commit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/simplicio_dashboard.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/simplicio_watch.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/scripts/cross_agent_wiki.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/scripts/hierarchical_planner.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-autoresearch/SKILL.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-compress/SKILL.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-learn/SKILL.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/agentsview-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/azure-devops-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/bound-operators.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/claims-gate.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/cross-agent-wiki.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/cross-repo-integration.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/hierarchical-planner.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/lmcache-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/quality-safety-delivery.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/run-journal-stall-detector.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/spindle-handoff.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/standing-loop-247.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/token-capture.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/token-economy.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/triage-verify-detail.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/understand-anything-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/video-evidence.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-loop/references/web-evidence.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-orient/SKILL.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-review/SKILL.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/SKILL.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/agentsview-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/azure-devops-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/lmcache-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/quality-safety-delivery.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/standing-loop-247.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/token-capture.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/token-economy.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/understand-anything-adapter.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/video-evidence.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/skills/simplicio-tasks/references/web-evidence.md +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/tests/_selfrun.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/tests/test_cross_agent_wiki.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/tests/test_loop_e2e.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/cli.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop.egg-info/dependency_links.txt +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop.egg-info/entry_points.txt +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop.egg-info/top_level.txt +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_action_gate.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_agentsview_adapter.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_autoresearch.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_az_boards_adapter.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_claims_audit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_claims_manifest_unit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_cross_agent_wiki.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_dashboard_hook.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_doctor_smoke.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_evidence_chain.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_fan_out_flow.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_fan_out_unit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_flow_audit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_hierarchical_planner.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_hooks_coverage.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_impact_audit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_install_lib.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_learn_pipeline_removed.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_loop_e2e.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_precommit_bundle_sync.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_repo_conventions_architecture.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_schema_verify_integration.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_schema_verify_unit.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_system_check.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_token_budget.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_toon_codec.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_verify_adapters_integration.py +0 -0
- {simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/tests/test_worker_smoke.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simplicio-loop
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.23.0
|
|
4
4
|
Summary: The Universal Looping AI Orchestrator — a runtime-agnostic super-plugin (7 skills) that drains any queue of work end-to-end on any LLM/runtime.
|
|
5
5
|
Author-email: Wesley Simplicio <wesleybob4@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -20,7 +20,7 @@ Requires-Python: >=3.8
|
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: simplicio-mapper>=0.17.0
|
|
23
|
-
Requires-Dist: simplicio-cli>=0.9.
|
|
23
|
+
Requires-Dist: simplicio-cli>=0.9.6
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
26
26
|
Provides-Extra: ml
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simplicio-loop"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.23.0"
|
|
8
8
|
description = "The Universal Looping AI Orchestrator — a runtime-agnostic super-plugin (7 skills) that drains any queue of work end-to-end on any LLM/runtime."
|
|
9
9
|
readme = "PYPI.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -26,7 +26,7 @@ classifiers = [
|
|
|
26
26
|
# simplicio-cli -> the operator that applies+verifies changes (binds `execute`/`deterministic_edit`)
|
|
27
27
|
dependencies = [
|
|
28
28
|
"simplicio-mapper>=0.17.0",
|
|
29
|
-
"simplicio-cli>=0.9.
|
|
29
|
+
"simplicio-cli>=0.9.6",
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
# Optional: the real embedding backend for `simplicio-cli semantic --ml` / `simplicio-cli rag --ml`.
|
|
@@ -158,9 +158,11 @@ detector below. It is the difference between a loop that converges and one that
|
|
|
158
158
|
Before deciding the change, refresh the impact map (`python3 scripts/impact_audit.py audit <root>
|
|
159
159
|
--file <seed> --cover <known-file> --json`, `--fail-on medium` for shared/public contracts) and,
|
|
160
160
|
for cross-surface flows, the flow map (`python3 scripts/flow_audit.py audit <root> --fail-on
|
|
161
|
-
high --json`).
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
high --json`). When a Phase 0 decomposition exists, also re-read the backlog (`python3
|
|
162
|
+
scripts/task_backlog.py status`). Journal = memory for ATTEMPTS; anchor = SCOPE; backlog =
|
|
163
|
+
THE DECOMPOSITION; impact audit = BLAST RADIUS; flow audit = INTEGRATION. Act only on what's
|
|
164
|
+
still genuinely open (idempotency). Full rationale + extra flags:
|
|
165
|
+
**`references/triage-verify-detail.md`**.
|
|
164
166
|
3. **Work the goal** each turn against that triaged state. The model DECIDES the AC-scoped change;
|
|
165
167
|
the **`simplicio-dev-cli` operator APPLIES and verifies it** — never hand-edit inside the loop.
|
|
166
168
|
End EVERY iteration with a concrete verification. **After the operator passes, run the watcher
|
|
@@ -193,7 +195,7 @@ for a single goal, `drain` for a work-queue.
|
|
|
193
195
|
| | `converge` (single hard task) | `drain` (a queue of items) |
|
|
194
196
|
|---|---|---|
|
|
195
197
|
| Wants | depth — keep changing strategy until ONE thing passes | breadth — clear many independent items, idempotently |
|
|
196
|
-
| Each turn | triage `since` last turn (incremental) → one AC-scoped change → verify → watcher-gate → journal | claim next open item → implement → deliver → re-query source |
|
|
198
|
+
| Each turn | triage `since` last turn (incremental) → one AC-scoped change → verify → watcher-gate → journal | claim next open item → implement → deliver → re-query source (the local Phase 0 backlog is a first-class source: re-query = `task_backlog.py next`; an `empty` print counts as a dry round, `dry≥2` unchanged) |
|
|
197
199
|
| **Termination** | the evidence-gated `<promise>` fires, OR the **stall detector** says STALLED and escalates (below) | the source re-query returns empty for **K consecutive rounds** (`dry≥2`) AND the working set is idle |
|
|
198
200
|
| Anti-pattern it avoids | oscillation (retrying the same dead-end) | missing late-arriving work (stops too early) |
|
|
199
201
|
|
|
@@ -204,6 +206,27 @@ genuinely stuck; `drain` is done when the queue stays empty across rounds. Don't
|
|
|
204
206
|
and don't apply `converge`'s stall-escalation to a queue (a stuck item should be quarantined, not
|
|
205
207
|
halt the whole drain). `simplicio-tasks` Step 3 routes fast-path/heavy-path on top of this.
|
|
206
208
|
|
|
209
|
+
## Phase 0 — intake & decomposition (no source / vague goal / genesis)
|
|
210
|
+
|
|
211
|
+
When the goal is vague and no external source (board/issues) supplies items, the LLM brainstorms
|
|
212
|
+
the decomposition — subtasks with ≥1 acceptance criterion each, `depends_on`, risks — and MUST
|
|
213
|
+
freeze it BEFORE any edit: `python3 scripts/task_backlog.py init --goal "<goal verbatim>"
|
|
214
|
+
--items-file plan.json` (the worker refuses an empty plan, a zero-AC item, or an unknown/cyclic
|
|
215
|
+
dependency — the AI decides, the worker freezes, orders and gates). State:
|
|
216
|
+
`.orchestrator/backlog/backlog.jsonl`.
|
|
217
|
+
|
|
218
|
+
**Genesis.** First run `python3 scripts/task_backlog.py genesis --exit-code` — exit 10 means a
|
|
219
|
+
repo with NO code yet. There `init` demands `--genesis` plus exactly one item tagged `scaffold`
|
|
220
|
+
(structure + toolchain + one minimal green test as its ACs); the worker reorders it to T1 and
|
|
221
|
+
makes every other item depend on it. After the scaffold item's gate passes, re-run
|
|
222
|
+
`simplicio-mapper scan . --json` before claiming the next item — the survey only feeds the goal
|
|
223
|
+
once there is something to map.
|
|
224
|
+
|
|
225
|
+
**Per-item cycle**: `python3 scripts/task_backlog.py next` claims one item (re-prints the one in
|
|
226
|
+
flight) and prints the ready `task_anchor.py set` arming command → work it under the normal
|
|
227
|
+
converge contract → `python3 scripts/task_backlog.py done --id T1` (exit 12 unless the ARMED
|
|
228
|
+
anchor is this item with every AC verified) → `next` again; exactly `empty` = drained.
|
|
229
|
+
|
|
207
230
|
## HRM-style hierarchical planner (two-level reasoning loop)
|
|
208
231
|
|
|
209
232
|
Inspired by the **Hierarchical Reasoning Model** (arXiv:2506.21734, JesseBrown1980/HRM), the loop
|
|
@@ -12,7 +12,7 @@ fallback with standard tools. The skill depends on the ABSTRACTION, never on a s
|
|
|
12
12
|
| `normalize` | Work-item → canonical schema | LLM maps fields by hand |
|
|
13
13
|
| `deterministic_edit` | Mechanical file writer (zero-token apply of a decided change) | LLM applies edit with file tool |
|
|
14
14
|
| `autoscale` | Safe fleet size from machine profile | formula in orchestration.md |
|
|
15
|
-
| `plan` / `decide` | Plan / decision support | LLM reasons it out |
|
|
15
|
+
| `plan` / `decide` | Plan / decision support. Runnable freeze: a vague goal's LLM decomposition (subtasks, per-item ACs, `depends_on`) is frozen, ordered and gated by `scripts/task_backlog.py init` — genesis-aware (an empty repo demands `--genesis` and a leading `scaffold` item) | LLM reasons it out |
|
|
16
16
|
| `execute` | Local agent fan-out for mass/mechanical work | LLM does it or spawns host sub-agents |
|
|
17
17
|
| `issue_factory` | Full orchestrator loop: discover→claim→implement→PR | manual pipeline (Steps 2–6) |
|
|
18
18
|
| `claim` | Atomic claim on a work-item (cross-session safe) | `gh label "in-progress"` + lockfile |
|
|
@@ -31,10 +31,10 @@ fallback with standard tools. The skill depends on the ABSTRACTION, never on a s
|
|
|
31
31
|
| `retry` | Classified retry+backoff by failure class | manual retry loop |
|
|
32
32
|
| `status` | Live observability dashboard | `gh` queries |
|
|
33
33
|
| `security` | Supply-chain / secret scan | `rg` for secrets |
|
|
34
|
-
| `intake` | Ingest work from sprint/board link | `gh issue list` |
|
|
35
|
-
| `dependency_graph` | Inter-item ordering as a resumable DAG (B after A; independents fan out); re-run skips done nodes. At code level, it also means "what else breaks if I touch this?" — runnable form: `scripts/impact_audit.py audit <root> --file <seed> --cover <planned-file> --json > .orchestrator/impact-audit.json` maps local dependencies, reverse dependents, and related tests for the planned task surface. `high` gaps block missing callers/dependents; `--fail-on medium` blocks uncovered local deps/tests for shared contracts. | LLM topo-sorts by depends-on/blocked-by, runs ready first, journals done node-ids to resume; for code impact, it uses `rg`/imports/git grep to enumerate local dependencies, reverse callers, and related tests, then widens the plan before editing |
|
|
34
|
+
| `intake` | Ingest work from sprint/board link — or, with no board, the local backlog (`task_backlog.py next`) | `gh issue list` |
|
|
35
|
+
| `dependency_graph` | Inter-item ordering as a resumable DAG (B after A; independents fan out); re-run skips done nodes (at item level, the frozen backlog's `depends_on` — `scripts/task_backlog.py` — IS this DAG for Phase 0 decompositions). At code level, it also means "what else breaks if I touch this?" — runnable form: `scripts/impact_audit.py audit <root> --file <seed> --cover <planned-file> --json > .orchestrator/impact-audit.json` maps local dependencies, reverse dependents, and related tests for the planned task surface. `high` gaps block missing callers/dependents; `--fail-on medium` blocks uncovered local deps/tests for shared contracts. | LLM topo-sorts by depends-on/blocked-by, runs ready first, journals done node-ids to resume; for code impact, it uses `rg`/imports/git grep to enumerate local dependencies, reverse callers, and related tests, then widens the plan before editing |
|
|
36
36
|
| `durable_workflow` | Per-item pipeline (intake→plan→edit→validate→deliver) as a resumable phase state-machine; retry skips done phases | LLM drives phases, journals which phase each item reached, resumes from last completed |
|
|
37
|
-
| `work_queue` | Durable priority queue that runs+auto-retries+requeues-stuck, with a write-serialization lock for shared checkouts | LLM keeps queue in JSONL/SQLite, pops by priority, re-enqueues on fail, lockfile+TTL guards shared-tree writes |
|
|
37
|
+
| `work_queue` | Durable priority queue that runs+auto-retries+requeues-stuck, with a write-serialization lock for shared checkouts. Local binding: `scripts/task_backlog.py` — `next` honors `depends_on` and re-prints the one claimed item; `done` is exit-12-gated on the verified task anchor; `skip` quarantines with a reason; an exact `empty` print is the drain dry signal | LLM keeps queue in JSONL/SQLite, pops by priority, re-enqueues on fail, lockfile+TTL guards shared-tree writes |
|
|
38
38
|
| `resource_governor` | Dynamic mid-loop throttle: decide when to back off + machine-tier ceilings before scaling a wave | LLM re-probes CPU/RAM/load each tick, reduces fleet / sleeps longer under load, degrades tiers |
|
|
39
39
|
| `delivery_gate` | One DoD gate: AC check + run-verification + regression guard + diff self-review + delivery certificate. Runnable form: the **task anchor** (`scripts/task_anchor.py`) freezes the ACs at intake, `check` flags goal-drift each turn (anti-deviation), `mark` records a per-AC receipt, and `gate` (exit 12) BLOCKS "done"/PR-open while any AC is unverified. | LLM walks the AC checklist, runs affected tests, reviews own diff, writes a certificate into the receipt |
|
|
40
40
|
| `action_gate` | Risk-classify every mutation (safe/auto/ask) vs allow/deny + hardline blocklist before it runs | LLM pattern-matches action vs irreversible-op list, secret-scans, proceeds/auto-runs/escalates to `human_gate` |
|
|
@@ -92,6 +92,7 @@ state file" bug class (the 685600b spindle/latch mismatch; the HANDOFF.md three-
|
|
|
92
92
|
| `anchor.json` | `scripts/task_anchor.py set`/`mark` (agent-invoked, once per item + per AC) | `hooks/loop_stop.py` (`anchor_pending()`, drift/AC gate), `scripts/watcher_verify.py` (independent recompute) | Frozen at intake; re-`set` with an unchanged goal preserves progress, a changed goal requires `--force`. |
|
|
93
93
|
| `journal.jsonl` | `scripts/loop_journal.py record` (agent-invoked); `hooks/loop_stop.py` (`auto_record_journal`, a minimal fallback record only when the agent didn't record one this turn) | `scripts/hierarchical_planner.py` (phase timing/stall), `hooks/loop_stop.py` (journal tail in `write_handoff`) | Append-only. The fallback record uses `gate: blocked` (never `fail`) so it can never itself trigger stall detection — it is a presence signal, not attempt memory. |
|
|
94
94
|
| `phase.json` | `scripts/hierarchical_planner.py plan` | `hooks/loop_stop.py` (re-feed header hint) | Re-planned every `DEFAULT_PLAN_INTERVAL` iterations or on stall. |
|
|
95
|
+
| `backlog.jsonl` (`.orchestrator/backlog/`) | `scripts/task_backlog.py` (`init` freezes; `next`/`done`/`skip` transition item states — agent-invoked) | the Phase 0 per-item cycle (SKILL.md § Phase 0), drain-mode dry detection (an exact `empty` from `next`) | Frozen at Phase 0 intake; re-`init` with the same master goal preserves per-item progress, a changed goal requires `--force`; `done` only closes an item whose armed anchor gate passed. |
|
|
95
96
|
|
|
96
97
|
If a machine has no `.claude/skills/simplicio-loop/SKILL.md` (a bare `simplicio-tasks` loop with
|
|
97
98
|
no `simplicio-loop` companion), none of the watcher/anchor/journal producers are expected to run —
|
|
@@ -11,6 +11,7 @@ and authed, then use it. Never claim a source works without a live connector.
|
|
|
11
11
|
| Trello / Azure DevOps | host connector, else the `az boards` adapter (`scripts/az_boards_adapter.py`, see `azure-devops-adapter.md`) |
|
|
12
12
|
| agentsview sessions | `scripts/agentsview_adapter.py` (see `agentsview-adapter.md`) | session observability, recovery of stalled sessions |
|
|
13
13
|
| local files / CI queue | filesystem / CI API |
|
|
14
|
+
| vague goal / no reachable board | the LOCAL BACKLOG — `scripts/task_backlog.py` (the frozen LLM decomposition, `.orchestrator/backlog/`; SKILL.md § Phase 0) |
|
|
14
15
|
|
|
15
16
|
If the target source has no reachable adapter, STOP and report it as a blocker (do not silently
|
|
16
17
|
fall back to GitHub). Each adapter exposes: list_ready (metadata-only), get_details, claim,
|
|
@@ -30,7 +31,10 @@ Triage is metadata-only; implementation is NOT. An agent that skips this produce
|
|
|
30
31
|
assignees, milestone, acceptance_criteria, comments, linked_prs, linked_items.
|
|
31
32
|
- Extract explicit **acceptance criteria** (numbered, checklists, "done when…"). If none stated,
|
|
32
33
|
derive + record them. An item that obviously should have ACs but has none is a BLOCKER — ask
|
|
33
|
-
ONE line, don't guess.
|
|
34
|
+
ONE line, don't guess. With a VAGUE goal and no source at all, decompose first (brainstorm the
|
|
35
|
+
subtasks + per-item ACs + `depends_on`) and freeze the plan with `python3
|
|
36
|
+
scripts/task_backlog.py init --goal "<goal>" --items-file plan.json` (SKILL.md § Phase 0); a
|
|
37
|
+
GENESIS repo (`task_backlog.py genesis --exit-code` exits 10) leads with the `scaffold` item.
|
|
34
38
|
- Extract design decisions/constraints/rejections from comments ("don't use X", "must integrate
|
|
35
39
|
with Y", reviewer requests) — these override naive title reading.
|
|
36
40
|
- Note linked items/PRs and check status — a blocked dependency is flagged, not ignored.
|
|
@@ -12,7 +12,7 @@ fallback with standard tools. The skill depends on the ABSTRACTION, never on a s
|
|
|
12
12
|
| `normalize` | Work-item → canonical schema | LLM maps fields by hand |
|
|
13
13
|
| `deterministic_edit` | Mechanical file writer (zero-token apply of a decided change) | LLM applies edit with file tool |
|
|
14
14
|
| `autoscale` | Safe fleet size from machine profile | formula in orchestration.md |
|
|
15
|
-
| `plan` / `decide` | Plan / decision support | LLM reasons it out |
|
|
15
|
+
| `plan` / `decide` | Plan / decision support. Runnable freeze: a vague goal's LLM decomposition (subtasks, per-item ACs, `depends_on`) is frozen, ordered and gated by `scripts/task_backlog.py init` — genesis-aware (an empty repo demands `--genesis` and a leading `scaffold` item) | LLM reasons it out |
|
|
16
16
|
| `execute` | Local agent fan-out for mass/mechanical work | LLM does it or spawns host sub-agents |
|
|
17
17
|
| `issue_factory` | Full orchestrator loop: discover→claim→implement→PR | manual pipeline (Steps 2–6) |
|
|
18
18
|
| `claim` | Atomic claim on a work-item (cross-session safe) | `gh label "in-progress"` + lockfile |
|
|
@@ -31,10 +31,10 @@ fallback with standard tools. The skill depends on the ABSTRACTION, never on a s
|
|
|
31
31
|
| `retry` | Classified retry+backoff by failure class | manual retry loop |
|
|
32
32
|
| `status` | Live observability dashboard | `gh` queries |
|
|
33
33
|
| `security` | Supply-chain / secret scan | `rg` for secrets |
|
|
34
|
-
| `intake` | Ingest work from sprint/board link | `gh issue list` |
|
|
35
|
-
| `dependency_graph` | Inter-item ordering as a resumable DAG (B after A; independents fan out); re-run skips done nodes. At code level, it also means "what else breaks if I touch this?" — runnable form: `scripts/impact_audit.py audit <root> --file <seed> --cover <planned-file> --json > .orchestrator/impact-audit.json` maps local dependencies, reverse dependents, and related tests for the planned task surface. `high` gaps block missing callers/dependents; `--fail-on medium` blocks uncovered local deps/tests for shared contracts. | LLM topo-sorts by depends-on/blocked-by, runs ready first, journals done node-ids to resume; for code impact, it uses `rg`/imports/git grep to enumerate local dependencies, reverse callers, and related tests, then widens the plan before editing |
|
|
34
|
+
| `intake` | Ingest work from sprint/board link — or, with no board, the local backlog (`task_backlog.py next`) | `gh issue list` |
|
|
35
|
+
| `dependency_graph` | Inter-item ordering as a resumable DAG (B after A; independents fan out); re-run skips done nodes (at item level, the frozen backlog's `depends_on` — `scripts/task_backlog.py` — IS this DAG for Phase 0 decompositions). At code level, it also means "what else breaks if I touch this?" — runnable form: `scripts/impact_audit.py audit <root> --file <seed> --cover <planned-file> --json > .orchestrator/impact-audit.json` maps local dependencies, reverse dependents, and related tests for the planned task surface. `high` gaps block missing callers/dependents; `--fail-on medium` blocks uncovered local deps/tests for shared contracts. | LLM topo-sorts by depends-on/blocked-by, runs ready first, journals done node-ids to resume; for code impact, it uses `rg`/imports/git grep to enumerate local dependencies, reverse callers, and related tests, then widens the plan before editing |
|
|
36
36
|
| `durable_workflow` | Per-item pipeline (intake→plan→edit→validate→deliver) as a resumable phase state-machine; retry skips done phases | LLM drives phases, journals which phase each item reached, resumes from last completed |
|
|
37
|
-
| `work_queue` | Durable priority queue that runs+auto-retries+requeues-stuck, with a write-serialization lock for shared checkouts | LLM keeps queue in JSONL/SQLite, pops by priority, re-enqueues on fail, lockfile+TTL guards shared-tree writes |
|
|
37
|
+
| `work_queue` | Durable priority queue that runs+auto-retries+requeues-stuck, with a write-serialization lock for shared checkouts. Local binding: `scripts/task_backlog.py` — `next` honors `depends_on` and re-prints the one claimed item; `done` is exit-12-gated on the verified task anchor; `skip` quarantines with a reason; an exact `empty` print is the drain dry signal | LLM keeps queue in JSONL/SQLite, pops by priority, re-enqueues on fail, lockfile+TTL guards shared-tree writes |
|
|
38
38
|
| `resource_governor` | Dynamic mid-loop throttle: decide when to back off + machine-tier ceilings before scaling a wave | LLM re-probes CPU/RAM/load each tick, reduces fleet / sleeps longer under load, degrades tiers |
|
|
39
39
|
| `delivery_gate` | One DoD gate: AC check + run-verification + regression guard + diff self-review + delivery certificate. Runnable form: the **task anchor** (`scripts/task_anchor.py`) freezes the ACs at intake, `check` flags goal-drift each turn (anti-deviation), `mark` records a per-AC receipt, and `gate` (exit 12) BLOCKS "done"/PR-open while any AC is unverified. | LLM walks the AC checklist, runs affected tests, reviews own diff, writes a certificate into the receipt |
|
|
40
40
|
| `action_gate` | Risk-classify every mutation (safe/auto/ask) vs allow/deny + hardline blocklist before it runs | LLM pattern-matches action vs irreversible-op list, secret-scans, proceeds/auto-runs/escalates to `human_gate` |
|
|
@@ -92,6 +92,7 @@ state file" bug class (the 685600b spindle/latch mismatch; the HANDOFF.md three-
|
|
|
92
92
|
| `anchor.json` | `scripts/task_anchor.py set`/`mark` (agent-invoked, once per item + per AC) | `hooks/loop_stop.py` (`anchor_pending()`, drift/AC gate), `scripts/watcher_verify.py` (independent recompute) | Frozen at intake; re-`set` with an unchanged goal preserves progress, a changed goal requires `--force`. |
|
|
93
93
|
| `journal.jsonl` | `scripts/loop_journal.py record` (agent-invoked); `hooks/loop_stop.py` (`auto_record_journal`, a minimal fallback record only when the agent didn't record one this turn) | `scripts/hierarchical_planner.py` (phase timing/stall), `hooks/loop_stop.py` (journal tail in `write_handoff`) | Append-only. The fallback record uses `gate: blocked` (never `fail`) so it can never itself trigger stall detection — it is a presence signal, not attempt memory. |
|
|
94
94
|
| `phase.json` | `scripts/hierarchical_planner.py plan` | `hooks/loop_stop.py` (re-feed header hint) | Re-planned every `DEFAULT_PLAN_INTERVAL` iterations or on stall. |
|
|
95
|
+
| `backlog.jsonl` (`.orchestrator/backlog/`) | `scripts/task_backlog.py` (`init` freezes; `next`/`done`/`skip` transition item states — agent-invoked) | the Phase 0 per-item cycle (SKILL.md § Phase 0), drain-mode dry detection (an exact `empty` from `next`) | Frozen at Phase 0 intake; re-`init` with the same master goal preserves per-item progress, a changed goal requires `--force`; `done` only closes an item whose armed anchor gate passed. |
|
|
95
96
|
|
|
96
97
|
If a machine has no `.claude/skills/simplicio-loop/SKILL.md` (a bare `simplicio-tasks` loop with
|
|
97
98
|
no `simplicio-loop` companion), none of the watcher/anchor/journal producers are expected to run —
|
|
@@ -11,6 +11,7 @@ and authed, then use it. Never claim a source works without a live connector.
|
|
|
11
11
|
| Trello / Azure DevOps | host connector, else the `az boards` adapter (`scripts/az_boards_adapter.py`, see `azure-devops-adapter.md`) |
|
|
12
12
|
| agentsview sessions | `scripts/agentsview_adapter.py` (see `agentsview-adapter.md`) | session observability, recovery of stalled sessions |
|
|
13
13
|
| local files / CI queue | filesystem / CI API |
|
|
14
|
+
| vague goal / no reachable board | the LOCAL BACKLOG — `scripts/task_backlog.py` (the frozen LLM decomposition, `.orchestrator/backlog/`; SKILL.md § Phase 0) |
|
|
14
15
|
|
|
15
16
|
If the target source has no reachable adapter, STOP and report it as a blocker (do not silently
|
|
16
17
|
fall back to GitHub). Each adapter exposes: list_ready (metadata-only), get_details, claim,
|
|
@@ -30,7 +31,10 @@ Triage is metadata-only; implementation is NOT. An agent that skips this produce
|
|
|
30
31
|
assignees, milestone, acceptance_criteria, comments, linked_prs, linked_items.
|
|
31
32
|
- Extract explicit **acceptance criteria** (numbered, checklists, "done when…"). If none stated,
|
|
32
33
|
derive + record them. An item that obviously should have ACs but has none is a BLOCKER — ask
|
|
33
|
-
ONE line, don't guess.
|
|
34
|
+
ONE line, don't guess. With a VAGUE goal and no source at all, decompose first (brainstorm the
|
|
35
|
+
subtasks + per-item ACs + `depends_on`) and freeze the plan with `python3
|
|
36
|
+
scripts/task_backlog.py init --goal "<goal>" --items-file plan.json` (SKILL.md § Phase 0); a
|
|
37
|
+
GENESIS repo (`task_backlog.py genesis --exit-code` exits 10) leads with the `scaffold` item.
|
|
34
38
|
- Extract design decisions/constraints/rejections from comments ("don't use X", "must integrate
|
|
35
39
|
with Y", reviewer requests) — these override naive title reading.
|
|
36
40
|
- Note linked items/PRs and check status — a blocked dependency is flagged, not ignored.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simplicio-loop
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.23.0
|
|
4
4
|
Summary: The Universal Looping AI Orchestrator — a runtime-agnostic super-plugin (7 skills) that drains any queue of work end-to-end on any LLM/runtime.
|
|
5
5
|
Author-email: Wesley Simplicio <wesleybob4@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -20,7 +20,7 @@ Requires-Python: >=3.8
|
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: simplicio-mapper>=0.17.0
|
|
23
|
-
Requires-Dist: simplicio-cli>=0.9.
|
|
23
|
+
Requires-Dist: simplicio-cli>=0.9.6
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
26
26
|
Provides-Extra: ml
|
|
@@ -90,6 +90,7 @@ tests/test_repo_conventions_architecture.py
|
|
|
90
90
|
tests/test_schema_verify_integration.py
|
|
91
91
|
tests/test_schema_verify_unit.py
|
|
92
92
|
tests/test_system_check.py
|
|
93
|
+
tests/test_task_backlog.py
|
|
93
94
|
tests/test_token_budget.py
|
|
94
95
|
tests/test_toon_codec.py
|
|
95
96
|
tests/test_verify_adapters_integration.py
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""End-to-end tests for `scripts/task_backlog.py` — the frozen multi-item decomposition ABOVE the
|
|
2
|
+
per-item task anchor (Phase 0):
|
|
3
|
+
|
|
4
|
+
* `init` is fail-closed: no items / zero-AC item refused; a GENESIS (no-code) repo refuses a
|
|
5
|
+
plan without `--genesis`, and with it forces the scaffold item to lead.
|
|
6
|
+
* `genesis --exit-code` is the deterministic greenfield detector (exit 10).
|
|
7
|
+
* `next` honors `depends_on`, re-prints the claimed item (one in flight), and prints exactly
|
|
8
|
+
`empty` when everything drained (the drain-mode dry signal).
|
|
9
|
+
* `done` is GATED on the real anchor: it refuses (exit 12) with no anchor, with another item's
|
|
10
|
+
anchor, or with pending ACs — and passes only after a real `task_anchor.py set` + `mark`.
|
|
11
|
+
|
|
12
|
+
Every test isolates state via SIMPLICIO_BACKLOG_FILE / SIMPLICIO_ANCHOR_FILE into a tmp dir and
|
|
13
|
+
pins the genesis detector with --root.
|
|
14
|
+
"""
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _env(tmp_path):
|
|
24
|
+
return dict(os.environ,
|
|
25
|
+
SIMPLICIO_BACKLOG_FILE=str(tmp_path / "backlog.jsonl"),
|
|
26
|
+
SIMPLICIO_ANCHOR_FILE=str(tmp_path / "anchor.json"))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _run(script, args, env):
|
|
30
|
+
return subprocess.run([sys.executable, os.path.join(REPO, "scripts", script)] + args,
|
|
31
|
+
capture_output=True, text=True, cwd=REPO, env=env)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _backlog(args, env):
|
|
35
|
+
return _run("task_backlog.py", args, env)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _anchor(args, env):
|
|
39
|
+
return _run("task_anchor.py", args, env)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _plan(tmp_path, items, name="plan.json"):
|
|
43
|
+
p = tmp_path / name
|
|
44
|
+
p.write_text(json.dumps(items), encoding="utf-8")
|
|
45
|
+
return str(p)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _code_root(tmp_path):
|
|
49
|
+
"""A --root that is NOT genesis (has one code file)."""
|
|
50
|
+
root = tmp_path / "coderoot"
|
|
51
|
+
root.mkdir(exist_ok=True)
|
|
52
|
+
(root / "app.py").write_text("print('x')\n", encoding="utf-8")
|
|
53
|
+
return str(root)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _drive_anchor_done(goal, acs, env):
|
|
57
|
+
"""Arm the real anchor for one item and verify every AC — the flow `next` prescribes."""
|
|
58
|
+
s = _anchor(["set", "--goal", goal, "--force"] + sum([["--ac", a] for a in acs], []), env)
|
|
59
|
+
assert s.returncode == 0, s.stdout + s.stderr
|
|
60
|
+
for i in range(len(acs)):
|
|
61
|
+
m = _anchor(["mark", "--id", "AC%d" % (i + 1), "--status", "done",
|
|
62
|
+
"--evidence", "receipt-%d" % (i + 1)], env)
|
|
63
|
+
assert m.returncode == 0, m.stdout + m.stderr
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_init_refuses_zero_ac_and_empty(tmp_path):
|
|
67
|
+
env = _env(tmp_path)
|
|
68
|
+
root = _code_root(tmp_path)
|
|
69
|
+
r = _backlog(["init", "--goal", "g", "--root", root,
|
|
70
|
+
"--items-file", _plan(tmp_path, [])], env)
|
|
71
|
+
assert r.returncode == 2, "empty plan must refuse (2), got %d:\n%s" % (r.returncode, r.stdout)
|
|
72
|
+
r = _backlog(["init", "--goal", "g", "--root", root,
|
|
73
|
+
"--items-file", _plan(tmp_path, [{"goal": "x", "acs": []}])], env)
|
|
74
|
+
assert r.returncode == 2, "zero-AC item must refuse (2), got %d:\n%s" % (r.returncode, r.stdout)
|
|
75
|
+
assert "acceptance criteria" in r.stdout, r.stdout
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_genesis_enforcement_and_scaffold_reorder(tmp_path):
|
|
79
|
+
env = _env(tmp_path)
|
|
80
|
+
empty = tmp_path / "empty"
|
|
81
|
+
empty.mkdir()
|
|
82
|
+
plan = [{"goal": "add the endpoint", "acs": ["endpoint responds"]},
|
|
83
|
+
{"goal": "bootstrap the project", "acs": ["structure exists", "one test green"],
|
|
84
|
+
"tags": ["scaffold"]},
|
|
85
|
+
{"goal": "add the docs page", "acs": ["page renders"]}]
|
|
86
|
+
# a genesis repo without --genesis is BLOCKED (12)
|
|
87
|
+
r = _backlog(["init", "--goal", "greenfield app", "--root", str(empty),
|
|
88
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
89
|
+
assert r.returncode == 12, "expected BLOCKED 12, got %d:\n%s" % (r.returncode, r.stdout)
|
|
90
|
+
assert "genesis" in r.stdout.lower(), r.stdout
|
|
91
|
+
# --genesis without a scaffold-tagged item refuses (2)
|
|
92
|
+
r = _backlog(["init", "--goal", "greenfield app", "--genesis", "--root", str(empty),
|
|
93
|
+
"--items-file", _plan(tmp_path, [{"goal": "x", "acs": ["a"]}])], env)
|
|
94
|
+
assert r.returncode == 2, r.stdout
|
|
95
|
+
assert "scaffold" in r.stdout, r.stdout
|
|
96
|
+
# --genesis with the scaffold given NOT first: freezes AND auto-orders it to T1
|
|
97
|
+
r = _backlog(["init", "--goal", "greenfield app", "--genesis", "--root", str(empty),
|
|
98
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
99
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
100
|
+
n = _backlog(["next", "--json"], env)
|
|
101
|
+
assert n.returncode == 0, n.stdout + n.stderr
|
|
102
|
+
got = json.loads(n.stdout)
|
|
103
|
+
assert got["id"] == "T1" and got["goal"] == "bootstrap the project", n.stdout
|
|
104
|
+
assert "task_anchor.py set" in got["arm"], n.stdout
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_genesis_exit_code(tmp_path):
|
|
108
|
+
env = _env(tmp_path)
|
|
109
|
+
empty = tmp_path / "empty"
|
|
110
|
+
empty.mkdir()
|
|
111
|
+
r = _backlog(["genesis", "--root", str(empty), "--exit-code"], env)
|
|
112
|
+
assert r.returncode == 10, "expected genesis exit 10, got %d:\n%s" % (r.returncode, r.stdout)
|
|
113
|
+
assert "genesis" in r.stdout, r.stdout
|
|
114
|
+
(empty / "main.py").write_text("pass\n", encoding="utf-8")
|
|
115
|
+
r = _backlog(["genesis", "--root", str(empty), "--exit-code"], env)
|
|
116
|
+
assert r.returncode == 0, "one .py must clear genesis, got %d:\n%s" % (r.returncode, r.stdout)
|
|
117
|
+
assert "code" in r.stdout, r.stdout
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_next_honors_depends_on_and_reprints_claimed(tmp_path):
|
|
121
|
+
env = _env(tmp_path)
|
|
122
|
+
plan = [{"id": "T1", "goal": "first thing", "acs": ["a1"]},
|
|
123
|
+
{"id": "T2", "goal": "second thing", "acs": ["a2"], "depends_on": ["T1"]}]
|
|
124
|
+
r = _backlog(["init", "--goal", "two steps", "--root", _code_root(tmp_path),
|
|
125
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
126
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
127
|
+
first = json.loads(_backlog(["next", "--json"], env).stdout)
|
|
128
|
+
assert first["id"] == "T1", first
|
|
129
|
+
again = json.loads(_backlog(["next", "--json"], env).stdout)
|
|
130
|
+
assert again["id"] == "T1" and again["verdict"] == "claimed", again # one in flight
|
|
131
|
+
_drive_anchor_done("first thing", ["a1"], env)
|
|
132
|
+
d = _backlog(["done", "--id", "T1"], env)
|
|
133
|
+
assert d.returncode == 0, d.stdout + d.stderr
|
|
134
|
+
nxt = json.loads(_backlog(["next", "--json"], env).stdout)
|
|
135
|
+
assert nxt["id"] == "T2", "depends_on not honored:\n%s" % nxt
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_done_is_gated_on_the_real_anchor(tmp_path):
|
|
139
|
+
env = _env(tmp_path)
|
|
140
|
+
plan = [{"goal": "item one", "acs": ["ac one", "ac two"]},
|
|
141
|
+
{"goal": "item two", "acs": ["other ac"]}]
|
|
142
|
+
r = _backlog(["init", "--goal", "gated", "--root", _code_root(tmp_path),
|
|
143
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
144
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
145
|
+
# no anchor armed at all -> BLOCKED 12
|
|
146
|
+
d = _backlog(["done", "--id", "T1"], env)
|
|
147
|
+
assert d.returncode == 12, "no-anchor done must block (12), got %d:\n%s" % (d.returncode, d.stdout)
|
|
148
|
+
assert "blocked" in d.stdout.lower(), d.stdout
|
|
149
|
+
# anchor armed for ANOTHER item's goal -> BLOCKED 12 (wrong fingerprint)
|
|
150
|
+
_drive_anchor_done("item two", ["other ac"], env)
|
|
151
|
+
d = _backlog(["done", "--id", "T1"], env)
|
|
152
|
+
assert d.returncode == 12, "wrong-fp done must block (12), got %d:\n%s" % (d.returncode, d.stdout)
|
|
153
|
+
# anchor armed for THIS item but ACs still pending -> BLOCKED 12
|
|
154
|
+
s = _anchor(["set", "--goal", "item one", "--force",
|
|
155
|
+
"--ac", "ac one", "--ac", "ac two"], env)
|
|
156
|
+
assert s.returncode == 0, s.stdout + s.stderr
|
|
157
|
+
d = _backlog(["done", "--id", "T1"], env)
|
|
158
|
+
assert d.returncode == 12, "pending-AC done must block (12), got %d:\n%s" % (d.returncode, d.stdout)
|
|
159
|
+
# every AC verified on the real anchor -> done, evidence copied
|
|
160
|
+
_drive_anchor_done("item one", ["ac one", "ac two"], env)
|
|
161
|
+
d = _backlog(["done", "--id", "T1"], env)
|
|
162
|
+
assert d.returncode == 0, d.stdout + d.stderr
|
|
163
|
+
st = _backlog(["status"], env)
|
|
164
|
+
assert "[done ] T1" in st.stdout, st.stdout
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_drain_dry_prints_exactly_empty(tmp_path):
|
|
168
|
+
env = _env(tmp_path)
|
|
169
|
+
plan = [{"goal": "only item", "acs": ["one ac"]},
|
|
170
|
+
{"goal": "doomed item", "acs": ["never"]}]
|
|
171
|
+
r = _backlog(["init", "--goal", "drain me", "--root", _code_root(tmp_path),
|
|
172
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
173
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
174
|
+
_backlog(["next"], env)
|
|
175
|
+
_drive_anchor_done("only item", ["one ac"], env)
|
|
176
|
+
assert _backlog(["done", "--id", "T1"], env).returncode == 0
|
|
177
|
+
sk = _backlog(["skip", "--id", "T2"], env)
|
|
178
|
+
assert sk.returncode == 2, "skip without --reason must refuse (2):\n%s" % sk.stdout
|
|
179
|
+
assert _backlog(["skip", "--id", "T2", "--reason", "out of scope"], env).returncode == 0
|
|
180
|
+
n = _backlog(["next"], env)
|
|
181
|
+
assert n.returncode == 0, n.stdout + n.stderr
|
|
182
|
+
assert n.stdout.strip() == "empty", "dry signal must be exactly 'empty':\n%r" % n.stdout
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_check_drift_and_idempotent_reinit(tmp_path):
|
|
186
|
+
env = _env(tmp_path)
|
|
187
|
+
plan = [{"goal": "stable item", "acs": ["an ac"]}]
|
|
188
|
+
r = _backlog(["init", "--goal", "the frozen goal", "--root", _code_root(tmp_path),
|
|
189
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
190
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
191
|
+
d = _backlog(["check", "--goal", "a totally different goal", "--exit-code"], env)
|
|
192
|
+
assert d.returncode == 11, "expected DRIFT 11, got %d:\n%s" % (d.returncode, d.stdout)
|
|
193
|
+
assert "DRIFT" in d.stdout, d.stdout
|
|
194
|
+
ok = _backlog(["check", "--goal", "the frozen goal", "--exit-code"], env)
|
|
195
|
+
assert ok.returncode == 0, ok.stdout
|
|
196
|
+
assert "BACKLOG_OK" in ok.stdout, ok.stdout
|
|
197
|
+
# progress, then re-init the SAME goal: idempotent, done state preserved
|
|
198
|
+
_backlog(["next"], env)
|
|
199
|
+
_drive_anchor_done("stable item", ["an ac"], env)
|
|
200
|
+
assert _backlog(["done", "--id", "T1"], env).returncode == 0
|
|
201
|
+
r = _backlog(["init", "--goal", "the frozen goal", "--root", _code_root(tmp_path),
|
|
202
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
203
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
204
|
+
st = _backlog(["status"], env)
|
|
205
|
+
assert "[done ] T1" in st.stdout, "re-init lost progress:\n%s" % st.stdout
|
|
206
|
+
# a CHANGED goal without --force is BLOCKED 12
|
|
207
|
+
r = _backlog(["init", "--goal", "a swapped goal", "--root", _code_root(tmp_path),
|
|
208
|
+
"--items-file", _plan(tmp_path, plan)], env)
|
|
209
|
+
assert r.returncode == 12, "goal swap without --force must block (12):\n%s" % r.stdout
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def test_selftest_and_unknown_verb(tmp_path):
|
|
213
|
+
env = _env(tmp_path)
|
|
214
|
+
r = _backlog(["selftest"], env)
|
|
215
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
216
|
+
assert "PASS" in r.stdout, r.stdout
|
|
217
|
+
r = _backlog(["definitely-not-a-real-verb-xyz"], env)
|
|
218
|
+
assert r.returncode == 2, r.stdout
|
|
219
|
+
assert "Traceback" not in r.stderr, "unknown verb crashed:\n%s" % r.stderr
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
if __name__ == "__main__":
|
|
223
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
224
|
+
from _selfrun import run_module
|
|
225
|
+
run_module(globals(), "test_task_backlog")
|
|
@@ -16,6 +16,7 @@ SELFTESTS = [
|
|
|
16
16
|
("scripts/billing_aggregator.py", "selftest"),
|
|
17
17
|
("scripts/savings_harness.py", "selftest"),
|
|
18
18
|
("scripts/task_anchor.py", "selftest"),
|
|
19
|
+
("scripts/task_backlog.py", "selftest"),
|
|
19
20
|
("scripts/pr_evidence.py", "selftest"),
|
|
20
21
|
("scripts/flow_audit.py", "selftest"),
|
|
21
22
|
("scripts/impact_audit.py", "selftest"),
|
|
@@ -54,6 +55,12 @@ def test_task_anchor_selftest():
|
|
|
54
55
|
assert "PASS" in r.stdout, r.stdout
|
|
55
56
|
|
|
56
57
|
|
|
58
|
+
def test_task_backlog_selftest():
|
|
59
|
+
r = _run("scripts/task_backlog.py", "selftest")
|
|
60
|
+
assert r.returncode == 0, "task_backlog selftest failed:\n%s%s" % (r.stdout, r.stderr)
|
|
61
|
+
assert "PASS" in r.stdout, r.stdout
|
|
62
|
+
|
|
63
|
+
|
|
57
64
|
def test_pr_evidence_selftest():
|
|
58
65
|
r = _run("scripts/pr_evidence.py", "selftest")
|
|
59
66
|
assert r.returncode == 0, "pr_evidence selftest failed:\n%s%s" % (r.stdout, r.stderr)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/hooks.claude.json
RENAMED
|
File without changes
|
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/loop_capture.py
RENAMED
|
File without changes
|
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/orient_clamp.py
RENAMED
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/orient_rewrite.py
RENAMED
|
File without changes
|
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/simplicio_dashboard.py
RENAMED
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/hooks/simplicio_watch.py
RENAMED
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/scripts/cross_agent_wiki.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop/_bundle/tests/test_loop_e2e.py
RENAMED
|
File without changes
|
|
File without changes
|
{simplicio_loop-3.22.6 → simplicio_loop-3.23.0}/simplicio_loop.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|