"""The knowledge-cycle bundle (goal 24 task 6): ONE end-to-end pass through the understanding and discoveries cycles, cross-cutting the surfaces the per-repo bundles could only check in isolation. Understanding: press Refresh on a project → the created task's OWN assignment payload (what the daemon actually receives) carries the brief's embedded old hash / old document / project notes AND the `understanding` member with the current revision → the saddle POSTs /api/saddle/understanding → the project page shows the new current document and a history row → a second POST makes the page show the newer one. Discoveries: POST via the API → the /discoveries page lists it and the dashboard shows it → update-by-id refines it → a fresh assignment payload carries it. """ from harness import * # noqa: F401,F403 — the shared wire helpers def run(ctx): auth, fake, fake_id, fake_token = ctx.auth, ctx.fake, ctx.fake_id, ctx.fake_token def db_rows(sql, params=()): conn = db() try: return conn.execute(sql, params).fetchall() finally: conn.close() def payload_for(task_id): for payload in reversed(fake.start_payloads): if int((payload.get("task") or {}).get("id") or 0) == int(task_id): return payload return None # A dedicated project so the cycle owns every row it asserts on. state = slot_public(auth, "/projects", "projects") act(auth, state["create"], {"name": "cycle", "git_url": "https://example.com/cycle.git"}) cycle_id = int([p["id"] for p in slot_public(auth, "/projects", "projects")["projects"] if p["name"] == "cycle"][0]) print("== cycle: the project page ships the section and Refresh ==") cycle_state = slot_public(auth, "/projects/%d" % cycle_id, "project") check(cycle_state.get("refresh_understanding") is not None, "the cycle project's slot authors the Refresh action") page_html = http_get_page(auth, "/projects/%d" % cycle_id) check("Understanding" in page_html and "Refresh" in page_html, "the project page renders the Understanding section with its button") print("== cycle: seed a current document + notes, press Refresh ==") status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "cycle", "body": "# Cycle v1\n\nThe old map.", "commit_hash": "aaa1111", "task_id": 0}) check(status == 200 and body.get("ok") is True, "seeding the first understanding via the API works") conn = db() conn.execute("insert into project_notes (project_id, source_task_id, body," " created_at) values (?, 0, ?, strftime('%s','now'))", (cycle_id, "Cycle note: the fixtures live in test/bundles/.")) conn.commit() conn.close() cycle_state = slot_public(auth, "/projects/%d" % cycle_id, "project") result = act(auth, cycle_state["refresh_understanding"], {}) check(any(d.get("type") == "notify" and d.get("kind") == "success" for d in result), "pressing Refresh queues the explorer task") rows = db_rows("select id, title, status from tasks" " where title like 'Understanding refresh: cycle'") check(len(rows) == 1, "Refresh created exactly one task") refresh_id = rows[0][0] check(rows[0][1].startswith("Understanding refresh:"), "the refresh task's title carries the goal-24 prefix") check(rows[0][2] in ("queued", "assigned", "working"), "the refresh task is live (%s)" % rows[0][2]) print("== cycle: the refresh task's OWN assignment payload ==") # The fake saddle asks when idle, so the dispatcher hands it the # refresh task: the payload the daemon builds from the brief AND # the understanding member must both be there. check(wait_for(lambda: payload_for(refresh_id) is not None or False, timeout=30, what="refresh assignment push") is not None, "the dispatcher assigns the refresh task to the saddle") payload = payload_for(refresh_id) brief = (payload.get("task") or {}).get("description") or "" check("Previous commit hash: aaa1111" in brief, "the assigned brief embeds the OLD commit hash") check("```markdown" in brief and "The old map." in brief, "the assigned brief embeds the OLD document") check("Cycle note: the fixtures live in test/bundles/." in brief, "the assigned brief embeds the project notes from other agents") check(payload.get("understanding") == "# Cycle v1\n\nThe old map.", "the assignment payload's understanding member is the current doc") check("discoveries" in payload and isinstance(payload.get("discoveries"), list), "the assignment payload carries the discoveries array alongside") print("== cycle: the explorer saves; the page flips ==") fake.push_results("done", summary="walked the history and updated the doc") check(wait_task_done(auth, refresh_id, timeout=30) is not None, "the refresh task completes") status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "cycle", "body": "# Cycle v2\n\nThe updated map.", "commit_hash": "bbb2222", "task_id": refresh_id}) check(status == 200 and int(body.get("understanding_id", 0)) > 0, "the explorer's save_understanding POST lands") cycle_state = slot_public(auth, "/projects/%d" % cycle_id, "project") current = cycle_state.get("understanding_current") or {} check(current.get("body") == "# Cycle v2\n\nThe updated map." and current.get("commit_hash") == "bbb2222", "the page shows the NEW current document after the save") history = cycle_state.get("understanding_history") or [] check([h.get("commit_hash") for h in history] == ["aaa1111"] and (history[0].get("body") or "").endswith("The old map."), "the page keeps the previous revision as a history row") page_html = http_get_page(auth, "/projects/%d" % cycle_id) check("stm-markdown=\"project.understanding_current.body\"" in page_html, "the rendered page binds the current document as markdown") print("== cycle: a second save makes the page show the newer ==") status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "cycle", "body": "# Cycle v3\n\nThe newest map.", "commit_hash": "ccc3333"}) check(status == 200, "the second explorer POST lands") cycle_state = slot_public(auth, "/projects/%d" % cycle_id, "project") current = cycle_state.get("understanding_current") or {} check(current.get("body") == "# Cycle v3\n\nThe newest map.", "the page's current flips to the newest revision") check([h.get("commit_hash") for h in cycle_state.get("understanding_history") or []] == ["bbb2222", "aaa1111"], "the history grows newest-first with both older revisions") print("== cycle: the discoveries leg ==") status, body = saddle_api("POST", "/api/saddle/discovery", fake_token, {"body": "cycle fact: meson test -C builddir runs the suite", "task_id": refresh_id}) check(status == 200 and int(body.get("discovery_id", 0)) > 0, "POST /api/saddle/discovery inserts and echoes the id") discovery_id = int(body["discovery_id"]) discoveries_state = slot_public(auth, "/discoveries", "discoveries") listed = [r for r in discoveries_state.get("discoveries") or [] if r.get("body") == "cycle fact: meson test -C builddir runs the suite"] check(len(listed) == 1, "the /discoveries page lists the new row") home_state = slot_public(auth, "/", "dashboard") dashboard = [r for r in home_state.get("discoveries") or [] if r.get("body") == "cycle fact: meson test -C builddir runs the suite"] check(len(dashboard) == 1, "the dashboard shows the discovery") status, body = saddle_api("POST", "/api/saddle/discovery/update", fake_token, {"id": discovery_id, "body": "cycle fact: meson test -C builddir runs the suite (also task-log-js)"}) check(status == 200 and body.get("ok") is True, "update-by-id answers ok") discoveries_state = slot_public(auth, "/discoveries", "discoveries") rows_now = [r for r in discoveries_state.get("discoveries") or [] if r.get("id") == str(discovery_id)] check(len(rows_now) == 1 and "(also task-log-js)" in rows_now[0].get("body", ""), "the page shows the refined body in place (no duplicate row)") # A fresh assignment carries the refined discovery. payload_count = len(fake.start_payloads) create_queued(auth, {"project_id": str(cycle_id), "title": "Cycle dispatch", "priority": "2"}) check(wait_for(lambda: len(fake.start_payloads) > payload_count or False, timeout=30, what="cycle /start push") is not None, "the dispatcher pushes the cycle task") shipped = [r.get("body", "") for r in fake.start_payloads[-1].get("discoveries") or []] check(any("(also task-log-js)" in b for b in shipped), "a fresh assignment payload carries the refined discovery") check(fake.start_payloads[-1].get("understanding") == "# Cycle v3\n\nThe newest map.", "the fresh assignment also carries the newest understanding")